diff --git a/.github/policies/resourceManagement.yml b/.github/policies/resourceManagement.yml index 379cea47b9f11..b87713780d643 100644 --- a/.github/policies/resourceManagement.yml +++ b/.github/policies/resourceManagement.yml @@ -27,23 +27,6 @@ configuration: eventResponderTasks: - - description: Auto-approve auto-merge PRs - triggerOnOwnActions: false - if: - - payloadType: Pull_Request - - isPullRequest - - labelAdded: - label: auto-merge - - or: - - activitySenderHasPermission: - permission: Admin - - isActivitySender: - user: dotnet-bot - issueAuthor: False - then: - - approvePullRequest: - comment: Auto-approval - - description: Auto-approve maestro PRs triggerOnOwnActions: false if: @@ -80,7 +63,7 @@ configuration: - addMilestone: milestone: Next - - description: Auto-approve OneLoc PRs + - description: Auto-approve/merge OneLoc PRs triggerOnOwnActions: false if: - payloadType: Pull_Request @@ -94,8 +77,29 @@ configuration: - isAction: action: Opened then: - - addLabel: - label: auto-merge + - approvePullRequest: + comment: Auto-approve + - enableAutoMerge: + mergeMethod: merge + + - description: Auto-approve/merge automated merge PRs + triggerOnOwnActions: false + if: + - payloadType: Pull_Request + - isPullRequest + - isActivitySender: + user: github-actions[bot] + issueAuthor: False + - titleContains: + pattern: "[automated] Merge branch" + isRegex: False + - isAction: + action: Opened + then: + - approvePullRequest: + comment: Auto-approve + - enableAutoMerge: + mergeMethod: merge - description: Remove "Need More Info" on comment triggerOnOwnActions: false @@ -147,7 +151,7 @@ configuration: issueAuthor: False - not: isActivitySender: - user: github-actions + user: github-actions[bot] issueAuthor: False then: - addLabel: @@ -168,7 +172,7 @@ configuration: issueAuthor: False - not: isActivitySender: - user: github-actions + user: github-actions[bot] issueAuthor: False - or: - isAction: diff --git a/.github/workflows/main-merge.yml b/.github/workflows/main-merge.yml new file mode 100644 index 0000000000000..8f90cffb5883b --- /dev/null +++ b/.github/workflows/main-merge.yml @@ -0,0 +1,25 @@ +# See https://github.com/dotnet/arcade/blob/e52018a/Documentation/Maestro/New-Inter-Branch-Merge-Approach.md + +name: Inter-branch merge +on: + schedule: + # Create a merge every 3 hours (works only for merges from `main`, others would need a `push` trigger). + - cron: '0 */3 * * *' + workflow_dispatch: + inputs: + configuration_file_branch: + description: 'Branch to use for configuration file' + required: true + default: 'main' + +permissions: + contents: write + pull-requests: write + +jobs: + merge: + if: github.repository == 'dotnet/roslyn' + uses: dotnet/arcade/.github/workflows/inter-branch-merge-base.yml@main + with: + configuration_file_path: 'eng/config/branch-merge.jsonc' + configuration_file_branch: ${{ inputs.configuration_file_branch || 'main' }} diff --git a/Roslyn.sln b/Roslyn.sln index c49637445381e..e93789c055083 100644 --- a/Roslyn.sln +++ b/Roslyn.sln @@ -352,8 +352,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ExternalAccess", "ExternalA EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.FSharp", "src\VisualStudio\ExternalAccess\FSharp\Microsoft.CodeAnalysis.ExternalAccess.FSharp.csproj", "{BD8CE303-5F04-45EC-8DCF-73C9164CD614}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.Razor", "src\Tools\ExternalAccess\Razor\Microsoft.CodeAnalysis.ExternalAccess.Razor.csproj", "{2FB6C157-DF91-4B1C-9827-A4D1C08C73EC}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.LanguageServices.CodeLens", "src\VisualStudio\CodeLens\Microsoft.VisualStudio.LanguageServices.CodeLens.csproj", "{5E6E9184-DEC5-4EC5-B0A4-77CFDC8CDEBE}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.LanguageServer.Protocol", "src\LanguageServer\Protocol\Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj", "{686BF57E-A6FF-467B-AAB3-44DE916A9772}" @@ -535,7 +533,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Exte EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost", "src\Workspaces\MSBuild\BuildHost\Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.csproj", "{B1481D94-682E-46EC-ADBE-A16EB46FEEE9}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.Copilot", "src\EditorFeatures\ExternalAccess\Copilot\Microsoft.CodeAnalysis.ExternalAccess.Copilot.csproj", "{5E8FB6D6-6C5C-42E6-9220-1EAA7ED9BCAD}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.Copilot", "src\Features\ExternalAccess\Copilot\Microsoft.CodeAnalysis.ExternalAccess.Copilot.csproj", "{5D60CF30-28A9-9F0F-7610-D90E4A69AE73}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.EditorConfigGenerator", "src\VisualStudio\ExternalAccess\EditorConfigGenerator\Microsoft.CodeAnalysis.ExternalAccess.EditorConfigGenerator.csproj", "{09AEDEE4-6358-47C9-8022-3BD37A518070}" EndProject @@ -569,6 +567,24 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ExternalAccess", "ExternalA EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.LanguageServer.Protocol.Test.Utilities", "src\LanguageServer\Protocol.TestUtilities\Microsoft.CodeAnalysis.LanguageServer.Protocol.Test.Utilities.csproj", "{7465CE63-A7B7-475F-8C57-48D2F8BC665A}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot", "src\LanguageServer\ExternalAccess\Copilot\Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot.csproj", "{900168D7-D982-86CE-5097-C5F173BA4D8B}" +EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Microsoft.CodeAnalysis.Threading", "src\Dependencies\Threading\Microsoft.CodeAnalysis.Threading.shproj", "{967723E8-4FDD-447B-99F6-4F8C47CB5433}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Threading.Package", "src\Dependencies\Threading\Microsoft.CodeAnalysis.Threading.Package.csproj", "{2559DAF9-784E-4C29-E0E1-70204B1FD56E}" +EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Microsoft.CodeAnalysis.Contracts", "src\Dependencies\Contracts\Microsoft.CodeAnalysis.Contracts.shproj", "{BD974609-C68B-4BE6-9682-EB132462B50D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Contracts.Package", "src\Dependencies\Contracts\Microsoft.CodeAnalysis.Contracts.Package.csproj", "{A8D5CFFA-7F9E-C35B-4F19-D63F6EC1D5CA}" +EndProject +Project("{9a19103f-16f7-4668-be54-9a1e7a4f7556}") = "Microsoft.CodeAnalysis.ExternalAccess.Razor", "src\Tools\ExternalAccess\Razor\EditorFeatures\Microsoft.CodeAnalysis.ExternalAccess.Razor.csproj", "{068CD9AA-CEC3-CA68-1BAB-2B1B9FD711D3}" +EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Microsoft.CodeAnalysis.ExternalAccess.Razor.Shared", "src\Tools\ExternalAccess\Razor\Shared\Microsoft.CodeAnalysis.ExternalAccess.Razor.Shared.shproj", "{4853A78A-4EC4-4D86-9F02-D0DDEAE85520}" +EndProject +Project("{9a19103f-16f7-4668-be54-9a1e7a4f7556}") = "Microsoft.CodeAnalysis.ExternalAccess.Razor.Features", "src\Tools\ExternalAccess\Razor\Features\Microsoft.CodeAnalysis.ExternalAccess.Razor.Features.csproj", "{D5A8E20C-E8D2-4A57-906A-263994D8731D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.LanguageServices.ExternalAccess.Copilot", "src\VisualStudio\ExternalAccess\Copilot\Microsoft.VisualStudio.LanguageServices.ExternalAccess.Copilot.csproj", "{9EB058F3-10C9-8F3F-AD9E-72CB362A0928}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1099,10 +1115,6 @@ Global {BD8CE303-5F04-45EC-8DCF-73C9164CD614}.Debug|Any CPU.Build.0 = Debug|Any CPU {BD8CE303-5F04-45EC-8DCF-73C9164CD614}.Release|Any CPU.ActiveCfg = Release|Any CPU {BD8CE303-5F04-45EC-8DCF-73C9164CD614}.Release|Any CPU.Build.0 = Release|Any CPU - {2FB6C157-DF91-4B1C-9827-A4D1C08C73EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2FB6C157-DF91-4B1C-9827-A4D1C08C73EC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2FB6C157-DF91-4B1C-9827-A4D1C08C73EC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2FB6C157-DF91-4B1C-9827-A4D1C08C73EC}.Release|Any CPU.Build.0 = Release|Any CPU {5E6E9184-DEC5-4EC5-B0A4-77CFDC8CDEBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5E6E9184-DEC5-4EC5-B0A4-77CFDC8CDEBE}.Debug|Any CPU.Build.0 = Debug|Any CPU {5E6E9184-DEC5-4EC5-B0A4-77CFDC8CDEBE}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -1355,10 +1367,10 @@ Global {B1481D94-682E-46EC-ADBE-A16EB46FEEE9}.Debug|Any CPU.Build.0 = Debug|Any CPU {B1481D94-682E-46EC-ADBE-A16EB46FEEE9}.Release|Any CPU.ActiveCfg = Release|Any CPU {B1481D94-682E-46EC-ADBE-A16EB46FEEE9}.Release|Any CPU.Build.0 = Release|Any CPU - {5E8FB6D6-6C5C-42E6-9220-1EAA7ED9BCAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5E8FB6D6-6C5C-42E6-9220-1EAA7ED9BCAD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5E8FB6D6-6C5C-42E6-9220-1EAA7ED9BCAD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5E8FB6D6-6C5C-42E6-9220-1EAA7ED9BCAD}.Release|Any CPU.Build.0 = Release|Any CPU + {5D60CF30-28A9-9F0F-7610-D90E4A69AE73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5D60CF30-28A9-9F0F-7610-D90E4A69AE73}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5D60CF30-28A9-9F0F-7610-D90E4A69AE73}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5D60CF30-28A9-9F0F-7610-D90E4A69AE73}.Release|Any CPU.Build.0 = Release|Any CPU {09AEDEE4-6358-47C9-8022-3BD37A518070}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {09AEDEE4-6358-47C9-8022-3BD37A518070}.Debug|Any CPU.Build.0 = Debug|Any CPU {09AEDEE4-6358-47C9-8022-3BD37A518070}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -1399,6 +1411,30 @@ Global {7465CE63-A7B7-475F-8C57-48D2F8BC665A}.Debug|Any CPU.Build.0 = Debug|Any CPU {7465CE63-A7B7-475F-8C57-48D2F8BC665A}.Release|Any CPU.ActiveCfg = Release|Any CPU {7465CE63-A7B7-475F-8C57-48D2F8BC665A}.Release|Any CPU.Build.0 = Release|Any CPU + {900168D7-D982-86CE-5097-C5F173BA4D8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {900168D7-D982-86CE-5097-C5F173BA4D8B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {900168D7-D982-86CE-5097-C5F173BA4D8B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {900168D7-D982-86CE-5097-C5F173BA4D8B}.Release|Any CPU.Build.0 = Release|Any CPU + {2559DAF9-784E-4C29-E0E1-70204B1FD56E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2559DAF9-784E-4C29-E0E1-70204B1FD56E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2559DAF9-784E-4C29-E0E1-70204B1FD56E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2559DAF9-784E-4C29-E0E1-70204B1FD56E}.Release|Any CPU.Build.0 = Release|Any CPU + {A8D5CFFA-7F9E-C35B-4F19-D63F6EC1D5CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A8D5CFFA-7F9E-C35B-4F19-D63F6EC1D5CA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A8D5CFFA-7F9E-C35B-4F19-D63F6EC1D5CA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A8D5CFFA-7F9E-C35B-4F19-D63F6EC1D5CA}.Release|Any CPU.Build.0 = Release|Any CPU + {9EB058F3-10C9-8F3F-AD9E-72CB362A0928}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9EB058F3-10C9-8F3F-AD9E-72CB362A0928}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9EB058F3-10C9-8F3F-AD9E-72CB362A0928}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9EB058F3-10C9-8F3F-AD9E-72CB362A0928}.Release|Any CPU.Build.0 = Release|Any CPU + {068CD9AA-CEC3-CA68-1BAB-2B1B9FD711D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {068CD9AA-CEC3-CA68-1BAB-2B1B9FD711D3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {068CD9AA-CEC3-CA68-1BAB-2B1B9FD711D3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {068CD9AA-CEC3-CA68-1BAB-2B1B9FD711D3}.Release|Any CPU.Build.0 = Release|Any CPU + {D5A8E20C-E8D2-4A57-906A-263994D8731D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D5A8E20C-E8D2-4A57-906A-263994D8731D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D5A8E20C-E8D2-4A57-906A-263994D8731D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D5A8E20C-E8D2-4A57-906A-263994D8731D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1558,7 +1594,6 @@ Global {6362616E-6A47-48F0-9EE0-27800B306ACB} = {AFA5F921-0650-45E8-B293-51A0BB89DEA0} {8977A560-45C2-4EC2-A849-97335B382C74} = {FD0FAF5F-1DED-485C-99FA-84B97F3A8EEC} {BD8CE303-5F04-45EC-8DCF-73C9164CD614} = {5880FECB-91F1-4AB8-8726-75EAFA8A918E} - {2FB6C157-DF91-4B1C-9827-A4D1C08C73EC} = {8977A560-45C2-4EC2-A849-97335B382C74} {5E6E9184-DEC5-4EC5-B0A4-77CFDC8CDEBE} = {8DBA5174-B0AA-4561-82B1-A46607697753} {686BF57E-A6FF-467B-AAB3-44DE916A9772} = {D449D505-CC6A-4E0B-AF1B-976E2D0AE67A} {1DDE89EE-5819-441F-A060-2FF4A986F372} = {D449D505-CC6A-4E0B-AF1B-976E2D0AE67A} @@ -1644,7 +1679,7 @@ Global {A833B11C-5072-4A1F-A32B-2700433B0D3D} = {806F0C6F-3640-4C92-8D55-6767B1535467} {8988270E-393A-4B92-AC1A-534F903CFD34} = {8977A560-45C2-4EC2-A849-97335B382C74} {B1481D94-682E-46EC-ADBE-A16EB46FEEE9} = {55A62CFA-1155-46F1-ADF3-BEEE51B58AB5} - {5E8FB6D6-6C5C-42E6-9220-1EAA7ED9BCAD} = {1AE9182D-B03E-4B00-B32E-37AE01715F57} + {5D60CF30-28A9-9F0F-7610-D90E4A69AE73} = {58A2876A-618D-4AE6-A136-E44B42BBDE11} {09AEDEE4-6358-47C9-8022-3BD37A518070} = {5880FECB-91F1-4AB8-8726-75EAFA8A918E} {5BABC440-4F1B-46E8-9068-DD7F02ED25D3} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6} {5762E483-75CE-4328-A410-511F30737712} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6} @@ -1661,6 +1696,15 @@ Global {1AE9182D-B03E-4B00-B32E-37AE01715F57} = {EE97CB90-33BB-4F3A-9B3D-69375DEC6AC6} {806F0C6F-3640-4C92-8D55-6767B1535467} = {D449D505-CC6A-4E0B-AF1B-976E2D0AE67A} {7465CE63-A7B7-475F-8C57-48D2F8BC665A} = {D449D505-CC6A-4E0B-AF1B-976E2D0AE67A} + {900168D7-D982-86CE-5097-C5F173BA4D8B} = {806F0C6F-3640-4C92-8D55-6767B1535467} + {967723E8-4FDD-447B-99F6-4F8C47CB5433} = {C2D1346B-9665-4150-B644-075CF1636BAA} + {2559DAF9-784E-4C29-E0E1-70204B1FD56E} = {C2D1346B-9665-4150-B644-075CF1636BAA} + {BD974609-C68B-4BE6-9682-EB132462B50D} = {C2D1346B-9665-4150-B644-075CF1636BAA} + {A8D5CFFA-7F9E-C35B-4F19-D63F6EC1D5CA} = {C2D1346B-9665-4150-B644-075CF1636BAA} + {9EB058F3-10C9-8F3F-AD9E-72CB362A0928} = {5880FECB-91F1-4AB8-8726-75EAFA8A918E} + {068CD9AA-CEC3-CA68-1BAB-2B1B9FD711D3} = {8977A560-45C2-4EC2-A849-97335B382C74} + {4853A78A-4EC4-4D86-9F02-D0DDEAE85520} = {8977A560-45C2-4EC2-A849-97335B382C74} + {D5A8E20C-E8D2-4A57-906A-263994D8731D} = {8977A560-45C2-4EC2-A849-97335B382C74} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {604E6B91-7BC0-4126-AE07-D4D2FEFC3D29} @@ -1669,26 +1713,37 @@ Global src\Analyzers\VisualBasic\CodeFixes\VisualBasicCodeFixes.projitems*{0141285d-8f6c-42c7-baf3-3c0ccd61c716}*SharedItemsImports = 5 src\Workspaces\SharedUtilitiesAndExtensions\Workspace\VisualBasic\VisualBasicWorkspaceExtensions.projitems*{0141285d-8f6c-42c7-baf3-3c0ccd61c716}*SharedItemsImports = 5 src\Compilers\CSharp\csc\CscCommandLine.projitems*{0161e25c-918a-4dc8-9648-30fdcc8e31e9}*SharedItemsImports = 5 + src\Tools\ExternalAccess\Razor\Shared\Microsoft.CodeAnalysis.ExternalAccess.Razor.Shared.projitems*{068cd9aa-cec3-ca68-1bab-2b1b9fd711d3}*SharedItemsImports = 5 + src\Dependencies\Contracts\Microsoft.CodeAnalysis.Contracts.projitems*{0c2e1633-1462-4712-88f4-a0c945bad3a8}*SharedItemsImports = 5 src\Analyzers\Core\CodeFixes\CodeFixes.projitems*{1b6c4a1a-413b-41fb-9f85-5c09118e541b}*SharedItemsImports = 13 src\Compilers\Core\AnalyzerDriver\AnalyzerDriver.projitems*{1ee8cad3-55f9-4d91-96b2-084641da9a6c}*SharedItemsImports = 5 src\Dependencies\CodeAnalysis.Debugging\Microsoft.CodeAnalysis.Debugging.projitems*{1ee8cad3-55f9-4d91-96b2-084641da9a6c}*SharedItemsImports = 5 src\Dependencies\Collections\Microsoft.CodeAnalysis.Collections.projitems*{1ee8cad3-55f9-4d91-96b2-084641da9a6c}*SharedItemsImports = 5 + src\Dependencies\Contracts\Microsoft.CodeAnalysis.Contracts.projitems*{1ee8cad3-55f9-4d91-96b2-084641da9a6c}*SharedItemsImports = 5 src\Dependencies\PooledObjects\Microsoft.CodeAnalysis.PooledObjects.projitems*{1ee8cad3-55f9-4d91-96b2-084641da9a6c}*SharedItemsImports = 5 src\Workspaces\SharedUtilitiesAndExtensions\Compiler\CSharp\CSharpCompilerExtensions.projitems*{21b239d0-d144-430f-a394-c066d58ee267}*SharedItemsImports = 5 src\Workspaces\SharedUtilitiesAndExtensions\Workspace\CSharp\CSharpWorkspaceExtensions.projitems*{21b239d0-d144-430f-a394-c066d58ee267}*SharedItemsImports = 5 src\Compilers\VisualBasic\BasicAnalyzerDriver\BasicAnalyzerDriver.projitems*{2523d0e6-df32-4a3e-8ae0-a19bffae2ef6}*SharedItemsImports = 5 src\Analyzers\VisualBasic\Analyzers\VisualBasicAnalyzers.projitems*{2531a8c4-97dd-47bc-a79c-b7846051e137}*SharedItemsImports = 5 src\Workspaces\SharedUtilitiesAndExtensions\Compiler\VisualBasic\VisualBasicCompilerExtensions.projitems*{2531a8c4-97dd-47bc-a79c-b7846051e137}*SharedItemsImports = 5 + src\Dependencies\Collections\Microsoft.CodeAnalysis.Collections.projitems*{2559daf9-784e-4c29-e0e1-70204b1fd56e}*SharedItemsImports = 5 + src\Dependencies\Contracts\Microsoft.CodeAnalysis.Contracts.projitems*{2559daf9-784e-4c29-e0e1-70204b1fd56e}*SharedItemsImports = 5 + src\Dependencies\PooledObjects\Microsoft.CodeAnalysis.PooledObjects.projitems*{2559daf9-784e-4c29-e0e1-70204b1fd56e}*SharedItemsImports = 5 src\Analyzers\Core\Analyzers\Analyzers.projitems*{275812ee-dedb-4232-9439-91c9757d2ae4}*SharedItemsImports = 5 src\Dependencies\Collections\Microsoft.CodeAnalysis.Collections.projitems*{275812ee-dedb-4232-9439-91c9757d2ae4}*SharedItemsImports = 5 + src\Dependencies\Contracts\Microsoft.CodeAnalysis.Contracts.projitems*{275812ee-dedb-4232-9439-91c9757d2ae4}*SharedItemsImports = 5 src\Dependencies\PooledObjects\Microsoft.CodeAnalysis.PooledObjects.projitems*{275812ee-dedb-4232-9439-91c9757d2ae4}*SharedItemsImports = 5 + src\Dependencies\Threading\Microsoft.CodeAnalysis.Threading.projitems*{275812ee-dedb-4232-9439-91c9757d2ae4}*SharedItemsImports = 5 src\Workspaces\SharedUtilitiesAndExtensions\Compiler\Core\CompilerExtensions.projitems*{275812ee-dedb-4232-9439-91c9757d2ae4}*SharedItemsImports = 5 + src\Dependencies\Contracts\Microsoft.CodeAnalysis.Contracts.projitems*{2801f82b-78ce-4bae-b06f-537574751e2e}*SharedItemsImports = 5 src\ExpressionEvaluator\VisualBasic\Source\ResultProvider\BasicResultProvider.projitems*{3140fe61-0856-4367-9aa3-8081b9a80e35}*SharedItemsImports = 13 src\ExpressionEvaluator\CSharp\Source\ResultProvider\CSharpResultProvider.projitems*{3140fe61-0856-4367-9aa3-8081b9a80e36}*SharedItemsImports = 13 src\Analyzers\CSharp\Analyzers\CSharpAnalyzers.projitems*{3973b09a-4fbf-44a5-8359-3d22ceb71f71}*SharedItemsImports = 5 src\Analyzers\CSharp\CodeFixes\CSharpCodeFixes.projitems*{3973b09a-4fbf-44a5-8359-3d22ceb71f71}*SharedItemsImports = 5 src\Compilers\CSharp\CSharpAnalyzerDriver\CSharpAnalyzerDriver.projitems*{3973b09a-4fbf-44a5-8359-3d22ceb71f71}*SharedItemsImports = 5 + src\Dependencies\Contracts\Microsoft.CodeAnalysis.Contracts.projitems*{41ed1bfa-fdad-4fe4-8118-db23fb49b0b0}*SharedItemsImports = 5 src\Workspaces\SharedUtilitiesAndExtensions\Workspace\CSharp\CSharpWorkspaceExtensions.projitems*{438db8af-f3f0-4ed9-80b5-13fddd5b8787}*SharedItemsImports = 13 + src\Tools\ExternalAccess\Razor\Shared\Microsoft.CodeAnalysis.ExternalAccess.Razor.Shared.projitems*{4853a78a-4ec4-4d86-9f02-d0ddeae85520}*SharedItemsImports = 13 src\Compilers\CSharp\csc\CscCommandLine.projitems*{4b45ca0c-03a0-400f-b454-3d4bcb16af38}*SharedItemsImports = 5 src\Analyzers\CSharp\Tests\CSharpAnalyzers.UnitTests.projitems*{5018d049-5870-465a-889b-c742ce1e31cb}*SharedItemsImports = 5 src\Compilers\CSharp\CSharpAnalyzerDriver\CSharpAnalyzerDriver.projitems*{54e08bf5-f819-404f-a18d-0ab9ea81ea04}*SharedItemsImports = 13 @@ -1696,7 +1751,9 @@ Global src\Workspaces\SharedUtilitiesAndExtensions\Workspace\VisualBasic\VisualBasicWorkspaceExtensions.projitems*{57ca988d-f010-4bf2-9a2e-07d6dcd2ff2c}*SharedItemsImports = 5 src\Analyzers\CSharp\Tests\CSharpAnalyzers.UnitTests.projitems*{58969243-7f59-4236-93d0-c93b81f569b3}*SharedItemsImports = 13 src\Dependencies\Collections\Microsoft.CodeAnalysis.Collections.projitems*{5f8d2414-064a-4b3a-9b42-8e2a04246be5}*SharedItemsImports = 5 + src\Dependencies\Contracts\Microsoft.CodeAnalysis.Contracts.projitems*{5f8d2414-064a-4b3a-9b42-8e2a04246be5}*SharedItemsImports = 5 src\Dependencies\PooledObjects\Microsoft.CodeAnalysis.PooledObjects.projitems*{5f8d2414-064a-4b3a-9b42-8e2a04246be5}*SharedItemsImports = 5 + src\Dependencies\Threading\Microsoft.CodeAnalysis.Threading.projitems*{5f8d2414-064a-4b3a-9b42-8e2a04246be5}*SharedItemsImports = 5 src\Workspaces\SharedUtilitiesAndExtensions\Compiler\Core\CompilerExtensions.projitems*{5f8d2414-064a-4b3a-9b42-8e2a04246be5}*SharedItemsImports = 5 src\Workspaces\SharedUtilitiesAndExtensions\Workspace\Core\WorkspaceExtensions.projitems*{5f8d2414-064a-4b3a-9b42-8e2a04246be5}*SharedItemsImports = 5 src\Analyzers\Core\CodeFixes\CodeFixes.projitems*{5ff1e493-69cc-4d0b-83f2-039f469a04e1}*SharedItemsImports = 5 @@ -1705,12 +1762,18 @@ Global src\LanguageServer\Microsoft.CommonLanguageServerProtocol.Framework\Microsoft.CommonLanguageServerProtocol.Framework.Shared.projitems*{64eaded3-4b5d-4431-bbe5-a4aba1c38c00}*SharedItemsImports = 13 src\LanguageServer\Microsoft.CommonLanguageServerProtocol.Framework\Microsoft.CommonLanguageServerProtocol.Framework.Shared.projitems*{686bf57e-a6ff-467b-aab3-44de916a9772}*SharedItemsImports = 5 src\Workspaces\SharedUtilitiesAndExtensions\Compiler\CSharp\CSharpCompilerExtensions.projitems*{699fea05-aea7-403d-827e-53cf4e826955}*SharedItemsImports = 13 + src\Dependencies\Contracts\Microsoft.CodeAnalysis.Contracts.projitems*{6fc8e6f5-659c-424d-aeb5-331b95883e29}*SharedItemsImports = 5 src\ExpressionEvaluator\VisualBasic\Source\ResultProvider\BasicResultProvider.projitems*{76242a2d-2600-49dd-8c15-fea07ecb1843}*SharedItemsImports = 5 src\Analyzers\Core\Analyzers\Analyzers.projitems*{76e96966-4780-4040-8197-bde2879516f4}*SharedItemsImports = 13 + src\Dependencies\Contracts\Microsoft.CodeAnalysis.Contracts.projitems*{7ad4fe65-9a30-41a6-8004-aa8f89bcb7f3}*SharedItemsImports = 5 src\Analyzers\VisualBasic\Tests\VisualBasicAnalyzers.UnitTests.projitems*{7b7f4153-ae93-4908-b8f0-430871589f83}*SharedItemsImports = 13 src\Compilers\VisualBasic\vbc\VbcCommandLine.projitems*{810b02ad-2ea5-4422-88ac-b71b8ab0df0b}*SharedItemsImports = 13 + src\Dependencies\Collections\Microsoft.CodeAnalysis.Collections.projitems*{8e2a252e-a140-45a6-a81a-2652996ea589}*SharedItemsImports = 5 + src\Dependencies\Contracts\Microsoft.CodeAnalysis.Contracts.projitems*{8e2a252e-a140-45a6-a81a-2652996ea589}*SharedItemsImports = 5 + src\Dependencies\Threading\Microsoft.CodeAnalysis.Threading.projitems*{8e2a252e-a140-45a6-a81a-2652996ea589}*SharedItemsImports = 5 src\Analyzers\VisualBasic\Analyzers\VisualBasicAnalyzers.projitems*{94faf461-2e74-4dbb-9813-6b2cde6f1880}*SharedItemsImports = 13 src\Compilers\Server\VBCSCompiler\VBCSCompilerCommandLine.projitems*{9508f118-f62e-4c16-a6f4-7c3b56e166ad}*SharedItemsImports = 5 + src\Dependencies\Threading\Microsoft.CodeAnalysis.Threading.projitems*{967723e8-4fdd-447b-99f6-4f8c47cb5433}*SharedItemsImports = 13 src\Compilers\VisualBasic\vbc\VbcCommandLine.projitems*{975cd834-45f4-4ea0-a395-cb60dbd0e214}*SharedItemsImports = 5 src\Workspaces\SharedUtilitiesAndExtensions\Workspace\Core\WorkspaceExtensions.projitems*{99f594b1-3916-471d-a761-a6731fc50e9a}*SharedItemsImports = 13 src\Analyzers\VisualBasic\CodeFixes\VisualBasicCodeFixes.projitems*{9f9ccc78-7487-4127-9d46-db23e501f001}*SharedItemsImports = 13 @@ -1721,21 +1784,27 @@ Global src\Compilers\VisualBasic\BasicAnalyzerDriver\BasicAnalyzerDriver.projitems*{a1bcd0ce-6c2f-4f8c-9a48-d9d93928e26d}*SharedItemsImports = 5 src\Analyzers\CSharp\Analyzers\CSharpAnalyzers.projitems*{aa87bfed-089a-4096-b8d5-690bdc7d5b24}*SharedItemsImports = 5 src\Workspaces\SharedUtilitiesAndExtensions\Compiler\CSharp\CSharpCompilerExtensions.projitems*{aa87bfed-089a-4096-b8d5-690bdc7d5b24}*SharedItemsImports = 5 + src\Dependencies\Contracts\Microsoft.CodeAnalysis.Contracts.projitems*{abdbac1e-350e-4dc3-bb45-3504404545ee}*SharedItemsImports = 5 src\ExpressionEvaluator\Core\Source\ResultProvider\ResultProvider.projitems*{abdbac1e-350e-4dc3-bb45-3504404545ee}*SharedItemsImports = 5 src\ExpressionEvaluator\VisualBasic\Source\ResultProvider\BasicResultProvider.projitems*{ace53515-482c-4c6a-e2d2-4242a687dfee}*SharedItemsImports = 5 src\Compilers\CSharp\csc\CscCommandLine.projitems*{b021ccbc-b2af-4560-af28-ed055f0ed696}*SharedItemsImports = 13 src\Dependencies\Collections\Microsoft.CodeAnalysis.Collections.projitems*{b1481d94-682e-46ec-adbe-a16eb46feee9}*SharedItemsImports = 5 + src\Dependencies\Contracts\Microsoft.CodeAnalysis.Contracts.projitems*{b1481d94-682e-46ec-adbe-a16eb46feee9}*SharedItemsImports = 5 src\Dependencies\PooledObjects\Microsoft.CodeAnalysis.PooledObjects.projitems*{b1481d94-682e-46ec-adbe-a16eb46feee9}*SharedItemsImports = 5 src\Compilers\CSharp\CSharpAnalyzerDriver\CSharpAnalyzerDriver.projitems*{b501a547-c911-4a05-ac6e-274a50dff30e}*SharedItemsImports = 5 src\ExpressionEvaluator\Core\Source\ResultProvider\ResultProvider.projitems*{bb3ca047-5d00-48d4-b7d3-233c1265c065}*SharedItemsImports = 13 + src\Dependencies\Contracts\Microsoft.CodeAnalysis.Contracts.projitems*{bd9539eb-aa5e-4e67-ac7f-97d7cbc4d0c9}*SharedItemsImports = 5 + src\Dependencies\Contracts\Microsoft.CodeAnalysis.Contracts.projitems*{bd974609-c68b-4be6-9682-eb132462b50d}*SharedItemsImports = 13 src\ExpressionEvaluator\CSharp\Source\ResultProvider\CSharpResultProvider.projitems*{bf9dac1e-3a5e-4dc3-bb44-9a64e0d4e9d4}*SharedItemsImports = 5 src\Dependencies\PooledObjects\Microsoft.CodeAnalysis.PooledObjects.projitems*{c1930979-c824-496b-a630-70f5369a636f}*SharedItemsImports = 13 src\Workspaces\SharedUtilitiesAndExtensions\Compiler\VisualBasic\VisualBasicCompilerExtensions.projitems*{cec0dce7-8d52-45c3-9295-fc7b16bd2451}*SharedItemsImports = 13 src\Compilers\Core\AnalyzerDriver\AnalyzerDriver.projitems*{d0bc9be7-24f6-40ca-8dc6-fcb93bd44b34}*SharedItemsImports = 13 - src\LanguageServer\Microsoft.CommonLanguageServerProtocol.Framework.Shared\Microsoft.CommonLanguageServerProtocol.Framework.Shared.projitems*{d2589bce-4f2e-4113-b7e7-37392c0c5492}*SharedItemsImports = 5 + src\Dependencies\Contracts\Microsoft.CodeAnalysis.Contracts.projitems*{d2589bce-4f2e-4113-b7e7-37392c0c5492}*SharedItemsImports = 5 + src\Tools\ExternalAccess\Razor\Shared\Microsoft.CodeAnalysis.ExternalAccess.Razor.Shared.projitems*{d5a8e20c-e8d2-4a57-906a-263994d8731d}*SharedItemsImports = 5 src\Dependencies\CodeAnalysis.Debugging\Microsoft.CodeAnalysis.Debugging.projitems*{d73adf7d-2c1c-42ae-b2ab-edc9497e4b71}*SharedItemsImports = 13 src\Compilers\Server\VBCSCompiler\VBCSCompilerCommandLine.projitems*{d8ef0777-9d65-4849-a7d6-ac81e58e2317}*SharedItemsImports = 13 src\Analyzers\CSharp\CodeFixes\CSharpCodeFixes.projitems*{da973826-c985-4128-9948-0b445e638bdb}*SharedItemsImports = 13 + src\Dependencies\Contracts\Microsoft.CodeAnalysis.Contracts.projitems*{db96c25f-39a9-4a6a-92bc-d1e42717308f}*SharedItemsImports = 5 src\Compilers\Server\VBCSCompiler\VBCSCompilerCommandLine.projitems*{dc8c78cc-b6fe-47bf-93b1-b65a1c67c08d}*SharedItemsImports = 5 src\Analyzers\VisualBasic\Tests\VisualBasicAnalyzers.UnitTests.projitems*{e512c6c1-f085-4ad7-b0d9-e8f1a0a2a510}*SharedItemsImports = 5 src\Compilers\VisualBasic\vbc\VbcCommandLine.projitems*{e58ee9d7-1239-4961-a0c1-f9ec3952c4c1}*SharedItemsImports = 5 @@ -1749,6 +1818,8 @@ Global src\Analyzers\Core\CodeFixes\CodeFixes.projitems*{edc68a0e-c68d-4a74-91b7-bf38ec909888}*SharedItemsImports = 5 src\Compilers\Core\AnalyzerDriver\AnalyzerDriver.projitems*{edc68a0e-c68d-4a74-91b7-bf38ec909888}*SharedItemsImports = 5 src\Dependencies\CodeAnalysis.Debugging\Microsoft.CodeAnalysis.Debugging.projitems*{edc68a0e-c68d-4a74-91b7-bf38ec909888}*SharedItemsImports = 5 + src\Dependencies\Contracts\Microsoft.CodeAnalysis.Contracts.projitems*{fa0e905d-ec46-466d-b7b2-3b5557f9428c}*SharedItemsImports = 5 src\ExpressionEvaluator\Core\Source\ResultProvider\ResultProvider.projitems*{fa0e905d-ec46-466d-b7b2-3b5557f9428c}*SharedItemsImports = 5 + src\Dependencies\Contracts\Microsoft.CodeAnalysis.Contracts.projitems*{fce88bbd-9bbd-4871-b9b0-de176d73a6b0}*SharedItemsImports = 5 EndGlobalSection EndGlobal diff --git a/azure-pipelines-integration.yml b/azure-pipelines-integration.yml index 241c0fec59dfc..afddf6a20c094 100644 --- a/azure-pipelines-integration.yml +++ b/azure-pipelines-integration.yml @@ -10,9 +10,9 @@ trigger: exclude: # Since the version of VS on the integration VM images are a moving target, # we are unable to reliably run integration tests on servicing branches. - - release/dev17.0-vs-deps - - release/dev17.2 - - release/dev17.3 + - release/dev17.8 + - release/dev17.10 + - release/dev17.12 # Branches that trigger builds on PR pr: @@ -26,19 +26,25 @@ pr: exclude: # Since the version of VS on the integration VM images are a moving target, # we are unable to reliably run integration tests on servicing branches. - - release/dev17.0-vs-deps - - release/dev17.2 - - release/dev17.3 + - release/dev17.8 + - release/dev17.10 + - release/dev17.12 paths: exclude: - docs/* - eng/config/OptProf.json - eng/config/PublishData.json + - eng/setup-pr-validation.ps1 - .vscode/* - .github/* - .devcontainer/* - .git-blame-ignore-revs - .vsconfig + - azure-pipelines-compliance.yml + - azure-pipelines-integration-dartlab.yml + - azure-pipelines-integration-scouting.yml + - azure-pipelines-official.yml + - azure-pipelines-pr-validation.yml - CODE-OF-CONDUCT.md - CONTRIBUTING.md - README.md diff --git a/azure-pipelines-official.yml b/azure-pipelines-official.yml index 69c371a7db6e0..f5b090c67753f 100644 --- a/azure-pipelines-official.yml +++ b/azure-pipelines-official.yml @@ -5,7 +5,9 @@ trigger: - main-vs-deps - release/dev16.*-vs-deps - release/dev17.* + - release/dev18.* - features/lsp_tools_host + - features/runtime-async exclude: - release/dev17.0 pr: none @@ -16,6 +18,11 @@ resources: type: git name: 1ESPipelineTemplates/1ESPipelineTemplates ref: refs/tags/release + pipelines: + - pipeline: profilingInputs + source: dotnet-vscode-csharp-profiling + branch: main + trigger: none parameters: - name: IbcDrop @@ -89,6 +96,9 @@ variables: - ${{ if and(notin(variables['Build.Reason'], 'PullRequest'), eq(variables['Build.SourceBranch'], 'refs/heads/main')) }}: - name: enableSourceIndex value: true + - name: VSCodeOptimizationDataRoot + value: $(Pipeline.Workspace)/profilingInputs/merged mibc + extends: template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelineTemplates @@ -154,7 +164,7 @@ extends: - output: pipelineArtifact displayName: 'Publish Ngen Logs' - condition: succeeded() + condition: and(succeeded(), ${{ not(parameters.SkipApplyOptimizationData) }}) targetPath: '$(Build.SourcesDirectory)\artifacts\log\$(BuildConfiguration)\ngen' artifactName: 'NGen Logs' publishLocation: Container @@ -202,6 +212,9 @@ extends: ArtifactName: AssetManifests steps: + - pwsh: Set-MpPreference -DisableRealtimeMonitoring $true + displayName: Disable Real-time Monitoring + - powershell: Write-Host "##vso[task.setvariable variable=SourceBranchName]$('$(Build.SourceBranch)'.Substring('refs/heads/'.Length))" displayName: Setting SourceBranchName variable condition: succeeded() @@ -266,16 +279,6 @@ extends: useGlobalJson: true workingDirectory: '$(Build.SourcesDirectory)' - # Needed to restore the Microsoft.DevDiv.Optimization.Data.PowerShell package - - task: NuGetCommand@2 - displayName: Restore internal tools - inputs: - command: restore - feedsToUse: config - restoreSolution: 'eng\common\internal\Tools.csproj' - nugetConfigPath: 'NuGet.config' - restoreDirectory: '$(Build.SourcesDirectory)\.packages' - - task: MicroBuildSigningPlugin@4 inputs: signType: $(SignType) @@ -283,6 +286,10 @@ extends: feedSource: https://dnceng.pkgs.visualstudio.com/_packaging/MicroBuildToolset/nuget/v3/index.json condition: and(succeeded(), in(variables['SignType'], 'test', 'real')) + - download: profilingInputs + artifact: merged mibc + displayName: Download VSCode optimization inputs + - task: PowerShell@2 displayName: Build inputs: @@ -298,17 +305,17 @@ extends: -configuration $(BuildConfiguration) -officialBuildId $(Build.BuildNumber) -officialSkipTests $(SkipTests) - -officialSkipApplyOptimizationData $(SkipApplyOptimizationData) + -officialSkipApplyOptimizationData ${{ parameters.SkipApplyOptimizationData }} -officialSourceBranchName $(SourceBranchName) -officialIbcDrop $(IbcDrop) -officialVisualStudioDropAccessToken $(_DevDivDropAccessToken) /p:RepositoryName=$(Build.Repository.Name) /p:VisualStudioDropName=$(VisualStudio.DropName) + /p:VSCodeOptimizationDataRoot="$(VSCodeOptimizationDataRoot)" /p:DotNetSignType=$(SignType) /p:DotnetPublishUsingPipelines=true /p:IgnoreIbcMergeErrors=true /p:GenerateSbom=true - /p:ForceAzureComSources=true condition: succeeded() - template: /eng/common/templates-official/steps/generate-sbom.yml@self diff --git a/azure-pipelines-pr-validation.yml b/azure-pipelines-pr-validation.yml index 5399ec92521dc..39295f2ece19a 100644 --- a/azure-pipelines-pr-validation.yml +++ b/azure-pipelines-pr-validation.yml @@ -13,6 +13,9 @@ parameters: type: number - name: CommitSHA type: string +- name: EnforceLatestCommit + type: boolean + default: true - name: VisualStudioBranchName type: string default: default @@ -95,7 +98,7 @@ extends: - output: pipelineArtifact displayName: 'Publish Ngen Logs' - condition: succeeded() + condition: and(succeeded(), ${{ not(parameters.SkipApplyOptimizationData) }}) targetPath: '$(Build.SourcesDirectory)\artifacts\log\$(BuildConfiguration)\ngen' artifactName: 'NGen Logs' publishLocation: Container @@ -143,6 +146,9 @@ extends: ArtifactName: AssetManifests steps: + - pwsh: Set-MpPreference -DisableRealtimeMonitoring $true + displayName: Disable Real-time Monitoring + - task: Powershell@2 displayName: Setting OriginalBuildNumber variable condition: succeeded() @@ -192,7 +198,7 @@ extends: displayName: Setup branch for insertion validation inputs: filePath: 'eng\setup-pr-validation.ps1' - arguments: '-sourceBranchName $(SourceBranchName) -prNumber ${{ parameters.PRNumber }} -commitSHA ${{ parameters.CommitSHA }}' + arguments: "-sourceBranchName $(SourceBranchName) -prNumber ${{ parameters.PRNumber }} -commitSHA ${{ parameters.CommitSHA }} -enforceLatestCommit ${{ iif(parameters.EnforceLatestCommit, '1', '0') }}" condition: succeeded() - powershell: Write-Host "##vso[task.setvariable variable=VisualStudio.DropName]Products/$(System.TeamProject)/$(Build.Repository.Name)/$(SourceBranchName)/$(OriginalBuildNumber)" @@ -215,16 +221,6 @@ extends: useGlobalJson: true workingDirectory: '$(Build.SourcesDirectory)' - # Needed to restore the Microsoft.DevDiv.Optimization.Data.PowerShell package - - task: NuGetCommand@2 - displayName: Restore internal tools - inputs: - command: restore - feedsToUse: config - restoreSolution: 'eng\common\internal\Tools.csproj' - nugetConfigPath: 'NuGet.config' - restoreDirectory: '$(Build.SourcesDirectory)\.packages' - - task: MicroBuildSigningPlugin@4 inputs: signType: $(SignType) @@ -246,7 +242,7 @@ extends: -configuration $(BuildConfiguration) -officialBuildId $(OriginalBuildNumber) -officialSkipTests $(SkipTests) - -officialSkipApplyOptimizationData $(SkipApplyOptimizationData) + -officialSkipApplyOptimizationData ${{ parameters.SkipApplyOptimizationData }} -officialSourceBranchName $(SourceBranchName) -officialIbcDrop $(IbcDrop) -officialVisualStudioDropAccessToken $(_DevDivDropAccessToken) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 0f26c4fff3483..494714e8fde8b 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -18,13 +18,20 @@ pr: paths: exclude: - docs/* + - eng/config/OptProf.json - eng/config/PublishData.json + - eng/setup-pr-validation.ps1 - src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/README.md - .vscode/* - .github/* - .devcontainer/* - .git-blame-ignore-revs - .vsconfig + - azure-pipelines-compliance.yml + - azure-pipelines-integration-dartlab.yml + - azure-pipelines-integration-scouting.yml + - azure-pipelines-official.yml + - azure-pipelines-pr-validation.yml - CODE-OF-CONDUCT.md - CONTRIBUTING.md - README.md @@ -61,9 +68,9 @@ variables: - name: UbuntuQueueName ${{ if eq(variables['System.TeamProject'], 'public') }}: - value: Build.Ubuntu.2004.Amd64.Open + value: Build.Ubuntu.2204.Amd64.Open ${{ else }}: - value: Build.Ubuntu.2004.Amd64 + value: Build.Ubuntu.2204.Amd64 - name: WindowsQueueName ${{ if eq(variables['System.TeamProject'], 'public') }}: @@ -85,15 +92,15 @@ variables: - name: HelixUbuntuQueueName ${{ if eq(variables['System.TeamProject'], 'public') }}: - value: Ubuntu.2004.Amd64.Open + value: Ubuntu.2204.Amd64.Open ${{ else }}: - value: Ubuntu.2004.Amd64 + value: Ubuntu.2204.Amd64 - name: HelixMacOsQueueName ${{ if eq(variables['System.TeamProject'], 'public') }}: - value: OSX.13.Amd64.Open + value: OSX.15.Amd64.Open ${{ else }}: - value: OSX.13.Amd64 + value: OSX.15.Amd64 parameters: # These pools allow us to configure the pools once for multiple jobs. @@ -399,7 +406,7 @@ stages: - powershell: eng/build.ps1 -configuration Release -prepareMachine -ci -restore -binaryLogName Restore.binlog displayName: Restore - - powershell: eng/build.ps1 -configuration Release -prepareMachine -ci -build -pack -publish -sign -binaryLogName Build.binlog /p:DotnetPublishUsingPipelines=true + - powershell: eng/build.ps1 -configuration Release -prepareMachine -ci -build -pack -publish -sign -binaryLogName Build.binlog /p:DotnetPublishUsingPipelines=true /p:ContinuousIntegrationBuildCorrectness=true displayName: Build # While this task is not executed in the official build, this serves as a PR check for whether symbol exclusions diff --git a/docs/Language Feature Status.md b/docs/Language Feature Status.md index 7061a36461d67..38a1ed4a00216 100644 --- a/docs/Language Feature Status.md +++ b/docs/Language Feature Status.md @@ -10,16 +10,17 @@ efforts behind them. | Feature | Branch | State | Developer | Reviewer | IDE Buddy | LDM Champ | | ------- | ------ | ----- | --------- | -------- | --------- | --------- | -| [Partial Events and Constructors](https://github.com/dotnet/csharplang/issues/9058) | [features/PartialEventsCtors](https://github.com/dotnet/roslyn/tree/features/PartialEventsCtors) | [In Progress](https://github.com/dotnet/roslyn/issues/76859) | [jjonescz](https://github.com/jjonescz) | [cston](https://github.com/cston), [RikkiGibson](https://github.com/RikkiGibson) | | | -| Runtime Async | [features/runtime-async](https://github.com/dotnet/roslyn/tree/features/runtime-async) | [In Progress](https://github.com/dotnet/roslyn/issues/75960) | [333fred](https://github.com/333fred) | [jcouv](https://github.com/jcouv), [RikkiGibson](https://github.com/RikkiGibson) | | | +| [User Defined Compound Assignment Operators](https://github.com/dotnet/csharplang/issues/9101) | [UserDefinedCompoundAssignment](https://github.com/dotnet/roslyn/tree/features/UserDefinedCompoundAssignment) | [In Progress](https://github.com/dotnet/roslyn/issues/76934) | [AlekseyTs](https://github.com/AlekseyTs) | [333fred](https://github.com/333fred), [cston](https://github.com/cston) | TBD | [AlekseyTs](https://github.com/AlekseyTs) | +| Runtime Async | [runtime-async](https://github.com/dotnet/roslyn/tree/features/runtime-async) | [In Progress](https://github.com/dotnet/roslyn/issues/75960) | [333fred](https://github.com/333fred) | [jcouv](https://github.com/jcouv), [RikkiGibson](https://github.com/RikkiGibson) | | | | [Null-conditional assignment](https://github.com/dotnet/csharplang/issues/6045) | [null-conditional-assignment](https://github.com/dotnet/roslyn/tree/features/null-conditional-assignment) | [In Progress](https://github.com/dotnet/roslyn/issues/75554) | [RikkiGibson](https://github.com/RikkiGibson) | [cston](https://github.com/cston), [jjonescz](https://github.com/jjonescz) | TBD | [RikkiGibson](https://github.com/RikkiGibson) | | [Extensions](https://github.com/dotnet/csharplang/issues/8697) | [extensions](https://github.com/dotnet/roslyn/tree/features/extensions) | [In Progress](https://github.com/dotnet/roslyn/issues/76130) | [jcouv](https://github.com/jcouv), [AlekseyTs](https://github.com/AlekseyTs) | [jjonescz](https://github.com/jjonescz), TBD | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [MadsTorgersen](https://github.com/MadsTorgersen) | | [Dictionary expressions](https://github.com/dotnet/csharplang/issues/8659) | [dictionary-expressions](https://github.com/dotnet/roslyn/tree/features/dictionary-expressions) | [In Progress](https://github.com/dotnet/roslyn/issues/76310) | [cston](https://github.com/cston), [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [333fred](https://github.com/333fred), [jcouv](https://github.com/jcouv) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | | [`field` keyword in properties](https://github.com/dotnet/csharplang/issues/140) | [field-keyword](https://github.com/dotnet/roslyn/tree/features/field-keyword) | [Merged into 17.12p3](https://github.com/dotnet/roslyn/issues/57012) | [Youssef1313](https://github.com/Youssef1313), [cston](https://github.com/cston) | [333fred](https://github.com/333fred), [RikkiGibson](https://github.com/RikkiGibson) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | | [First-class Span Types](https://github.com/dotnet/csharplang/issues/7905) | [FirstClassSpan](https://github.com/dotnet/roslyn/tree/features/FirstClassSpan) | [Merged into 17.13p1](https://github.com/dotnet/roslyn/issues/73445) | [jjonescz](https://github.com/jjonescz) | [cston](https://github.com/cston), [333fred](https://github.com/333fred) | | [333fred](https://github.com/333fred), [stephentoub](https://github.com/stephentoub) | | [Unbound generic types in `nameof`](https://github.com/dotnet/csharplang/issues/8480) | [PR](https://github.com/dotnet/roslyn/pull/75368) | [Merged into 17.13p2](https://github.com/dotnet/roslyn/pull/75368) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [jcouv](https://github.com/jcouv), [AlekseyTs](https://github.com/AlekseyTs) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | -| [String literals in data section as UTF8](https://github.com/dotnet/roslyn/blob/main/docs/features/string-literals-data-section.md) | [PR](https://github.com/dotnet/roslyn/pull/76036) | [Merged into 17.14p1](https://github.com/dotnet/roslyn/issues/76234) | [jjonescz](https://github.com/jjonescz) | [AlekseyTs](https://github.com/AlekseyTs), [cston](https://github.com/cston) | N/A | N/A | +| [String literals in data section as UTF8](https://github.com/dotnet/roslyn/blob/main/docs/features/string-literals-data-section.md) | [PR](https://github.com/dotnet/roslyn/pull/76036) | [Merged into 17.13p4](https://github.com/dotnet/roslyn/issues/76234) | [jjonescz](https://github.com/jjonescz) | [AlekseyTs](https://github.com/AlekseyTs), [cston](https://github.com/cston) | N/A | N/A | | [Simple lambda parameters with modifiers](https://github.com/dotnet/csharplang/blob/main/proposals/simple-lambda-parameters-with-modifiers.md) | [PR](https://github.com/dotnet/roslyn/pull/75400) | [Merged into 17.14p1](https://github.com/dotnet/roslyn/pull/75400) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [jjonescz](https://github.com/jjonescz), [cston](https://github.com/cston) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | +| [Partial Events and Constructors](https://github.com/dotnet/csharplang/issues/9058) | [PartialEventsCtors](https://github.com/dotnet/roslyn/tree/features/PartialEventsCtors) | [Merged into 17.14p3](https://github.com/dotnet/roslyn/issues/76859) | [jjonescz](https://github.com/jjonescz) | [cston](https://github.com/cston), [RikkiGibson](https://github.com/RikkiGibson) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [jaredpar](https://github.com/jaredpar) | # Working Set VB @@ -121,17 +122,17 @@ efforts behind them. | [Skip locals init](https://github.com/dotnet/csharplang/issues/1738) | [localsinit](https://github.com/dotnet/roslyn/tree/features/localsinit) | [Merged](https://github.com/dotnet/roslyn/issues/25780) | [t-camaia](https://github.com/t-camaia), [agocke](https://github.com/agocke) | [jaredpar](https://github.com/jaredpar) | [agocke](https://github.com/agocke) | | [Lambda discard parameters](https://github.com/dotnet/csharplang/issues/111) | main | [Merged](https://github.com/dotnet/roslyn/issues/38820) | [jcouv](https://github.com/jcouv) | [AlekseyTs](https://github.com/AlekseyTs), [chsienki](https://github.com/chsienki) | [jcouv](https://github.com/jcouv) | | [Native ints](https://github.com/dotnet/csharplang/issues/435) | main | [Merged into 16.7p1](https://github.com/dotnet/roslyn/issues/38821) | [cston](https://github.com/cston) | [333fred](https://github.com/333fred), [gafter](https://github.com/gafter) | [jaredpar](https://github.com/jaredpar) | -| [Attributes on local functions](https://github.com/dotnet/csharplang/issues/1888) | [features/local-function-attributes](https://github.com/dotnet/roslyn/tree/features/local-function-attributes) | [Merged](https://github.com/dotnet/roslyn/issues/38801) | [RikkiGibson](https://github.com/RikkiGibson) | [agocke](https://github.com/agocke) | [agocke](https://github.com/agocke) | +| [Attributes on local functions](https://github.com/dotnet/csharplang/issues/1888) | [local-function-attributes](https://github.com/dotnet/roslyn/tree/features/local-function-attributes) | [Merged](https://github.com/dotnet/roslyn/issues/38801) | [RikkiGibson](https://github.com/RikkiGibson) | [agocke](https://github.com/agocke) | [agocke](https://github.com/agocke) | | [Function pointers](https://github.com/dotnet/csharplang/issues/191) | main | [Merged into 16.7p3](https://github.com/dotnet/roslyn/issues/43321) | [333fred](https://github.com/333fred) | [AlekseyTs](https://github.com/AlekseyTs) | [jaredpar](https://github.com/jaredpar) | | [Pattern matching improvements](https://github.com/dotnet/csharplang/issues/2850) | main | [Merged into 16.7p1](https://github.com/dotnet/roslyn/issues/40727) | [gafter](https://github.com/gafter) | [RikkiGibson](https://github.com/RikkiGibson),[agocke](https://github.com/agocke) | [gafter](https://github.com/gafter) | | [Static lambdas](https://github.com/dotnet/csharplang/issues/275) | main | [Merged in 16.7p4](https://github.com/dotnet/roslyn/issues/39606) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [jcouv](https://github.com/jcouv) | [jcouv](https://github.com/jcouv) | | [Records](https://github.com/dotnet/csharplang/issues/39) | main | [Merged into 16.7p3](https://github.com/dotnet/roslyn/issues/40726) | [agocke](https://github.com/agocke) | [gafter](https://github.com/gafter), [333fred](https://github.com/333fred) | [agocke](https://github.com/agocke) | -| [Target-typed conditional](https://github.com/dotnet/csharplang/issues/2460) | [features/target-typing](https://github.com/dotnet/roslyn/tree/features/target-typing) | [Merged into 16.7p4](https://github.com/dotnet/roslyn/issues/43186) | [gafter](https://github.com/gafter) | [agocke](https://github.com/agocke), [RikkiGibson](https://github.com/RikkiGibson) | [gafter](https://github.com/gafter) | -| [Covariant](https://github.com/dotnet/csharplang/issues/49) [Returns](https://github.com/dotnet/csharplang/issues/2844) | [features/covariant-returns](https://github.com/dotnet/roslyn/tree/features/covariant-returns) | [Merged into 16.8p2](https://github.com/dotnet/roslyn/issues/43188) | [gafter](https://github.com/gafter) | [AlekseyTs](https://github.com/AlekseyTs), [agocke](https://github.com/agocke) | [gafter](https://github.com/gafter) | +| [Target-typed conditional](https://github.com/dotnet/csharplang/issues/2460) | [target-typing](https://github.com/dotnet/roslyn/tree/features/target-typing) | [Merged into 16.7p4](https://github.com/dotnet/roslyn/issues/43186) | [gafter](https://github.com/gafter) | [agocke](https://github.com/agocke), [RikkiGibson](https://github.com/RikkiGibson) | [gafter](https://github.com/gafter) | +| [Covariant](https://github.com/dotnet/csharplang/issues/49) [Returns](https://github.com/dotnet/csharplang/issues/2844) | [covariant-returns](https://github.com/dotnet/roslyn/tree/features/covariant-returns) | [Merged into 16.8p2](https://github.com/dotnet/roslyn/issues/43188) | [gafter](https://github.com/gafter) | [AlekseyTs](https://github.com/AlekseyTs), [agocke](https://github.com/agocke) | [gafter](https://github.com/gafter) | | [Extension GetEnumerator](https://github.com/dotnet/csharplang/issues/3194) | main | [Merged into 16.8p2](https://github.com/dotnet/roslyn/issues/43184) | [YairHalberstadt](https://github.com/YairHalberstadt) | [333fred](https://github.com/333fred) | [333fred](https://github.com/333fred) | | [Module initializers](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-9.0/module-initializers.md) | main | [Merged in 16.7p4](https://github.com/dotnet/roslyn/issues/40500) | [RikkiGibson](https://github.com/RikkiGibson) [jnm2](https://github.com/jnm2)| [AlekseyTs](https://github.com/AlekseyTs) | [gafter](https://github.com/gafter) | | [Extending Partial](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-9.0/extending-partial-methods.md) | main | [Merged into 16.7p2](https://github.com/dotnet/roslyn/issues/43795) | [RikkiGibson](https://github.com/RikkiGibson) | [chsienki](https://github.com/chsienki) | [jaredpar](https://github.com/jaredpar) | -| [Top-level statements](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-9.0/top-level-statements.md) | [features/SimplePrograms](https://github.com/dotnet/roslyn/tree/features/SimplePrograms) | [Merged into 16.7p3](https://github.com/dotnet/roslyn/issues/43563) | [AlekseyTs](https://github.com/AlekseyTs) | [cston](https://github.com/cston), [RikkiGibson](https://github.com/RikkiGibson) | [MadsTorgersen](https://github.com/MadsTorgersen) | +| [Top-level statements](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-9.0/top-level-statements.md) | [SimplePrograms](https://github.com/dotnet/roslyn/tree/features/SimplePrograms) | [Merged into 16.7p3](https://github.com/dotnet/roslyn/issues/43563) | [AlekseyTs](https://github.com/AlekseyTs) | [cston](https://github.com/cston), [RikkiGibson](https://github.com/RikkiGibson) | [MadsTorgersen](https://github.com/MadsTorgersen) | # C# 8.0 diff --git a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md index 6075637771e03..af85d951a3b53 100644 --- a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md +++ b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md @@ -291,3 +291,69 @@ unsafe record struct R( public bool Equals(R other) => true; } ``` + +## Emitting metadata-only executables requires an entrypoint + +***Introduced in Visual Studio 2022 version 17.14*** + +Previously, the entrypoint was [unintentionally unset](https://github.com/dotnet/roslyn/issues/76707) +when emitting executables in metadata-only mode (also known as ref assemblies). +That is now corrected but it also means that a missing entrypoint is a compilation error: + +```cs +// previously successful, now fails: +CSharpCompilation.Create("test").Emit(new MemoryStream(), + options: EmitOptions.Default.WithEmitMetadataOnly(true)) + +CSharpCompilation.Create("test", + // workaround - mark as DLL instead of EXE (the default): + options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)) + .Emit(new MemoryStream(), + options: EmitOptions.Default.WithEmitMetadataOnly(true)) +``` + +Similarly this can be observed when using the command-line argument `/refonly` +or the `ProduceOnlyReferenceAssembly` MSBuild property. + +## `partial` cannot be a return type of methods + +***Introduced in Visual Studio 2022 version 17.14*** + +The [partial events and constructors](https://github.com/dotnet/csharplang/issues/9058) language feature +allows the `partial` modifier in more places and so it cannot be a return type unless escaped: + +```cs +class C +{ + partial F() => new partial(); // previously worked + @partial F() => new partial(); // workaround +} + +class partial { } +``` + +## `extension` treated as a contextual keyword + +PROTOTYPE record which version this break is introduced in + +Starting with C# 14, the `extension` keyword serves a special purpose in denoting extension containers. +This changes how the compiler interprets certain code constructs. + +If you need to use "extension" as an identifier rather than a keyword, escape it with the `@` prefix: `@extension`. This tells the compiler to treat it as a regular identifier instead of a keyword. + +The compiler will parse this as an extension container rather than a constructor. +```csharp +class extension +{ + extension(object o) { } // parsed as an extension container +} +``` + +The compiler will fail to parse this as a method with return type `extension`. +```csharp +class extension +{ + extension M() { } // will not compile +} +``` + diff --git a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 8.md b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 8.md index 470853cd3c8f8..cbf8984cc876c 100644 --- a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 8.md +++ b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 8.md @@ -35,7 +35,7 @@ public class C ***Introduced in Visual Studio 2022 version 17.10*** *Conversion* of a collection expression to a `struct` or `class` that implements `System.Collections.IEnumerable` and *does not* have a strongly-typed `GetEnumerator()` -requires the elements in the collection expression are implicitly convertible to the `object`. +requires that the elements in the collection expression are implicitly convertible to `object`. Previously, the elements of a collection expression targeting an `IEnumerable` implementation were assumed to be convertible to `object`, and converted only when binding to the applicable `Add` method. This additional requirement means that collection expression conversions to `IEnumerable` implementations are treated consistently with other target types where the elements in the collection expression must be implicitly convertible to the *iteration type* of the target type. diff --git a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md index ce0ac3ee11fe5..ede353e5c7d71 100644 --- a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md +++ b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md @@ -157,3 +157,30 @@ class C ``` A workaround is to use explicit delegate types instead of relying on `var` inference in those cases. + +## `dotnet_style_require_accessibility_modifiers` now consistently applies to interface members + +PR: https://github.com/dotnet/roslyn/pull/76324 + +Prior to this change, the analyzer for dotnet_style_require_accessibility_modifiers would simply ignore interface +members. This was because C# initially disallowed modifiers for interface members entirely, having them always +be public. + +Later versions of the language relaxed this restriction, allowing users to provide accessibility modifiers on +interface members, including a redundant `public` modifier. + +The analyzer was updated to now enforce the value for this option on interface members as well. The meaning +of the value is as follows: + +1. `never`. The analyzer does no analysis. Redundant modifiers are allowed on all members. +2. `always`. Redundant modifiers are always required on all members (including interface members). For example: + a `private` modifier on a class member, and a `public` modifier on an interface member. This is the option to + use if you feel that all members no matter what should state their accessibility explicitly. +4. `for_non_interface_members`. Redundant modifiers are required on all members *that are not* part of an interface, + but disallowed for interface members. For example: `private` will be required on private class members. However, + a public interface member will not be allowed to have redundant `public` modifiers. This matches the standard + modifier approach present prior to the language allowing modifiers on interface members. +5. `omit_if_default`. Redundant modifiers are disallowed. For example a private class member will be disallowed from + using `private`, and a public interface member will be disallowed from using `public`. This is the option to use + if you feel that restating the accessibility when it matches what the language chooses by default is redundant and + should be disallowed. diff --git a/docs/compilers/CSharp/Runtime Async Design.md b/docs/compilers/CSharp/Runtime Async Design.md index e577604505e9f..f7dc760b13a78 100644 --- a/docs/compilers/CSharp/Runtime Async Design.md +++ b/docs/compilers/CSharp/Runtime Async Design.md @@ -27,20 +27,33 @@ We use the following helper APIs to indicate suspension points to the runtime, i ```cs namespace System.Runtime.CompilerServices; -// These methods are used to await things that cannot use runtime async signature form // TODO: Clarify which of these should be preferred? Should we always emit the `Unsafe` version when awaiting something that implements `ICriticalNotifyCompletion`? namespace System.Runtime.CompilerServices; public static class RuntimeHelpers { - [RuntimeAsyncMethod] - public static Task AwaitAwaiterFromRuntimeAsync(TAwaiter awaiter) where TAwaiter : INotifyCompletion; - [RuntimeAsyncMethod] - public static Task UnsafeAwaitAwaiterFromRuntimeAsync(TAwaiter awaiter) where TAwaiter : ICriticalNotifyCompletion; + // These methods are used to await things that cannot use the Await helpers below + [MethodImpl(MethodImplOptions.Async)] + public static void AwaitAwaiterFromRuntimeAsync(TAwaiter awaiter) where TAwaiter : INotifyCompletion; + [MethodImpl(MethodImplOptions.Async)] + public static void UnsafeAwaitAwaiterFromRuntimeAsync(TAwaiter awaiter) where TAwaiter : ICriticalNotifyCompletion; + + // These methods are used to directly await method calls + [MethodImpl(MethodImplOptions.Async)] + public static void Await(Task task); + [MethodImpl(MethodImplOptions.Async)] + public static T Await(Task task); + [MethodImpl(MethodImplOptions.Async)] + public static void Await(ValueTask task); + [MethodImpl(MethodImplOptions.Async)] + public static T Await(ValueTask task); } ``` -We presume the following `MethodImplOptions` bit is present. This is used to indicate to the JIT that it should generate an async state machine for the method. +We presume the following `MethodImplOptions` bit is present. This is used to indicate to the JIT that it should generate an async state machine for the method. This bit is not allowed to be used manually on any method; it is added by the compiler +to an `async` method. + +TODO: We may want to block directly calling `MethodImplOptions.Async` methods with non-`Task`/`ValueTask` return types. ```cs namespace System.Runtime.CompilerServices; @@ -77,6 +90,8 @@ public class RuntimeAsyncMethodGenerationAttribute(bool runtimeAsync) : Attribut As mentioned previously, we try to expose as little of this to initial binding as possible. The one major exception to this is our handling of the `MethodImplOption.Async`; we do not let this be applied to user code, and will issue an error if a user tries to do this by hand. +TODO: We may need special handling for the implementation of the `RuntimeHelpers.Await` methods in corelib to permit usage of `MethodImplOptions.Async` directly, as they will not be `async` as we think of it in C#. + Compiler generated async state machines and runtime generated async share some of the same building blocks. Both need to have `await`s with in `catch` and `finally` blocks rewritten to pend the exceptions, perform the `await` outside of the `catch`/`finally` region, and then have the exceptions restored as necessary. @@ -121,7 +136,12 @@ for given scenarios are elaborated in more detail below. TODO: Async iterators (returning `IAsyncEnumerable`) -#### Await `Task`-returning method +#### `Task`, `Task`, `ValueTask`, `ValueTask` Scenarios + +For any lvalue of one of these types, we'll generally rewrite `await expr` into `System.Runtime.CompilerServices.RuntimeHelpers.Await(expr)`. A number of different example scenarios for this are covered below. The +main interesting deviations are when `struct` rvalues need to be hoisted across an `await`, and exception handling rewriting. + +##### Await `Task`-returning method ```cs class C @@ -132,8 +152,15 @@ class C await C.M(); ``` +Translated C#: + +```cs +System.Runtime.CompilerServices.RuntimeHelpers.Await(C.M()); +``` + ```il -call modreq(class [System.Runtime]System.Threading.Tasks.Task) void C::M() +call [System.Runtime]System.Threading.Tasks.Task C::M() +call void [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::Await(class [System.Runtime]System.Threading.Tasks.Task) ``` --------------------------- @@ -148,12 +175,23 @@ class C } ``` +Translated C#: + +```cs +var c = new C(); +System.Runtime.CompilerServices.RuntimeHelpers.Await(c.M()); +``` + ```il newobj instance void C::.ctor() -callvirt instance modreq(class [System.Runtime]System.Threading.Tasks.Task) void C::M() +callvirt instance class [System.Runtime]System.Threading.Tasks.Task C::M() +call void [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::Await(class [System.Runtime]System.Threading.Tasks.Task) ``` -#### Await a concrete `T` `Task`-returning method +
+Extended examples of further variations on the simple `await expr` scenario + +##### Await a concrete `T` `Task`-returning method ```cs int i = await C.M(); @@ -164,8 +202,15 @@ class C } ``` +Translated C#: + +```cs +int i = System.Runtime.CompilerServices.RuntimeHelpers.Await(C.M()); +``` + ```il -call modreq(class [System.Runtime]System.Threading.Tasks.Task`1) int32 C::M() +call class [System.Runtime]System.Threading.Tasks.Task`1 C::M() +call int32 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::Await(class [System.Runtime]System.Threading.Tasks.Task`1) stloc.0 ``` @@ -181,13 +226,21 @@ class C } ``` +Translated C#: + +```cs +var c = new C(); +int i = System.Runtime.CompilerServices.RuntimeHelpers.Await(c.M()); +``` + ```il newobj instance void C::.ctor() -callvirt instance modreq(class [System.Runtime]System.Threading.Tasks.Task`1) int32 C::M() +callvirt instance class [System.Runtime]System.Threading.Tasks.Task`1 C::M() +call int32 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::Await(class [System.Runtime]System.Threading.Tasks.Task`1) stloc.0 ``` -#### Await local of type `Task` +##### Await local of type `Task` ```cs var local = M(); @@ -203,14 +256,7 @@ Translated C#: ```cs var local = C.M(); -{ - var awaiter = local.GetAwaiter(); - if (!awaiter.IsComplete) - { - /* Runtime-Async Call */ System.Runtime.CompilerServices.RuntimeHelpers.AwaitAwaiterFromRuntimeAsync(awaiter); - } - awaiter.GetResult() -} +System.Runtime.CompilerServices.RuntimeHelpers.Await(local); ``` ```il @@ -220,26 +266,14 @@ var local = C.M(); ) IL_0000: call class [System.Runtime]System.Threading.Tasks.Task C::M() - IL_0005: callvirt instance valuetype [System.Runtime]System.Runtime.CompilerServices.TaskAwaiter [System.Runtime]System.Threading.Tasks.Task::GetAwaiter() - IL_000a: stloc.0 - IL_000b: ldloca.s 0 - IL_000d: call instance bool [System.Runtime]System.Runtime.CompilerServices.TaskAwaiter::get_IsCompleted() - IL_0012: brtrue.s IL_001b - - IL_0014: ldloc.0 - IL_0015: call class [System.Runtime]System.Threading.Tasks.Task System.Runtime.CompilerServices.RuntimeHelpers::AwaitAwaiterFromRuntimeAsync(!!0) - IL_001a: pop - - IL_001b: ldloca.s 0 - IL_001d: call instance void [System.Runtime]System.Runtime.CompilerServices.TaskAwaiter::GetResult() - IL_0022: ret + IL_0005: stloc.0 + IL_0006: ldloc.0 + IL_0007: call void [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::Await(class [System.Runtime]System.Threading.Tasks.Task) + IL_000c: ret } ``` -#### Await local of concrete type `Task` - -This strategy will also be used for `Task`-like types that are not `Task`, `ValueTask`, `Task`, or `ValueTask`, both in value form, and in direct method call form. We will use either `AwaitAwaiterFromRuntimeAsync` or -`UnsafeAwaitAwaiterFromRuntimeAsync`, depending on the interface implemented by the custom awaitable. +##### Await local of concrete type `Task` ```cs var local = M(); @@ -255,42 +289,26 @@ Translated C#: ```cs var local = C.M(); -var i = -{ - var awaiter = local.GetAwaiter(); - if (!awaiter.IsComplete) - { - /* Runtime-Async Call */ System.Runtime.CompilerServices.RuntimeHelpers.AwaitAwaiterFromRuntimeAsync(awaiter); - } - awaiter.GetResult() -}; +var i = System.Runtime.CompilerServices.RuntimeHelpers.Await(local); ``` ```il { .locals init ( - [0] valuetype [System.Runtime]System.Runtime.CompilerServices.TaskAwaiter`1 awaiter + [0] class [System.Runtime]System.Threading.Tasks.Task`1 local, + [1] int32 i ) IL_0000: call class [System.Runtime]System.Threading.Tasks.Task`1 C::M() - IL_0005: callvirt instance valuetype [System.Runtime]System.Runtime.CompilerServices.TaskAwaiter`1 class [System.Runtime]System.Threading.Tasks.Task`1::GetAwaiter() - IL_000a: stloc.0 - IL_000b: ldloca.s 0 - IL_000d: call instance bool valuetype [System.Runtime]System.Runtime.CompilerServices.TaskAwaiter`1::get_IsCompleted() - IL_0012: brtrue.s IL_001b - - IL_0014: ldloc.0 - IL_0015: call class [System.Runtime]System.Threading.Tasks.Task System.Runtime.CompilerServices.RuntimeHelpers::AwaitAwaiterFromRuntimeAsync>(!!0) - IL_001a: pop - - IL_001b: ldloca.s 0 - IL_001d: call instance !0 valuetype [System.Runtime]System.Runtime.CompilerServices.TaskAwaiter`1::GetResult() - IL_0022: pop - IL_0023: ret + IL_0005: stloc.0 + IL_0006: ldloc.0 + IL_0007: call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::Await(class [System.Runtime]System.Threading.Tasks.Task`1) + IL_000c: stloc.1 + IL_000d: ret } ``` -#### Await a `T`-returning method +##### Await a `T`-returning method ```cs await C.M(); @@ -301,14 +319,24 @@ class C } ``` +Translated C#: + +```cs +System.Runtime.CompilerServices.RuntimeHelpers.Await(C.M()); +``` + ```il -TODO: https://github.com/dotnet/runtime/issues/109632 +{ + IL_0000: call !!0 C::M() + IL_0005: call void [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::Await(class [System.Runtime]System.Threading.Tasks.Task) + IL_000a: ret +} ``` -#### Await a generic `T` `Task`-returning method +##### Await a generic `T` `Task`-returning method ```cs -await C.M(); +int i = await C.M(); class C { @@ -316,11 +344,22 @@ class C } ``` +Translated C#: + +```cs +int i = System.Runtime.CompilerServices.RuntimeHelpers.Await(C.M()); +``` + ```il -TODO: https://github.com/dotnet/runtime/issues/109632 +{ + IL_0000: call class [System.Runtime]System.Threading.Tasks.Task`1 C::M() + IL_0005: call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::Await(class [System.Runtime]System.Threading.Tasks.Task`1) + IL_000a: stloc.0 + IL_000b: ret +} ``` -#### Await a `Task`-returning delegate +##### Await a `Task`-returning delegate ```cs AsyncDelegate d = C.M; @@ -334,11 +373,33 @@ class C } ``` +Translated C# + +```cs +AsyncDelegate d = C.M; +System.Runtime.CompilerServices.RuntimeHelpers.Await(d()); +``` + ```il -TODO: https://github.com/dotnet/runtime/issues/109632 +{ + IL_0000: ldsfld class AsyncDelegate Program/'<>O'::'<0>__M' + IL_0005: dup + IL_0006: brtrue.s IL_001b + + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn class [System.Runtime]System.Threading.Tasks.Task C::M() + IL_0010: newobj instance void AsyncDelegate::.ctor(object, native int) + IL_0015: dup + IL_0016: stsfld class AsyncDelegate Program/'<>O'::'<0>__M' + + IL_001b: callvirt instance class [System.Runtime]System.Threading.Tasks.Task AsyncDelegate::Invoke() + IL_0020: call void [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::Await(class [System.Runtime]System.Threading.Tasks.Task) + IL_0025: ret +} ``` -#### Await a `T`-returning delegate +##### Await a `T`-returning delegate where `T` becomes `Task` ```cs Func d = C.M; @@ -350,11 +411,35 @@ class C } ``` +Translated C#: + +```cs +Func d = C.M; +System.Runtime.CompilerServices.RuntimeHelpers.Await(d()); +``` + ```il -TODO: https://github.com/dotnet/runtime/issues/109632 +{ + IL_0000: ldsfld class [System.Runtime]System.Func`1 Program/'<>O'::'<0>__M' + IL_0005: dup + IL_0006: brtrue.s IL_001b + + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn class [System.Runtime]System.Threading.Tasks.Task C::M() + IL_0010: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, native int) + IL_0015: dup + IL_0016: stsfld class [System.Runtime]System.Func`1 Program/'<>O'::'<0>__M' + + IL_001b: callvirt instance !0 class [System.Runtime]System.Func`1::Invoke() + IL_0020: call void [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::Await(class [System.Runtime]System.Threading.Tasks.Task) + IL_0025: ret +} ``` -#### Awaiting in a `catch` block +
+ +##### Awaiting in a `catch` block ```cs try @@ -390,7 +475,7 @@ catch (Exception e) if (pendingCatch == 1) { - /* Runtime-Async Call */ C.M(); + System.Runtime.CompilerServices.RuntimeHelpers.Await(C.M()); throw pendingException; } ``` @@ -402,33 +487,35 @@ if (pendingCatch == 1) [1] class [System.Runtime]System.Exception pendingException ) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 .try { - IL_0000: newobj instance void [System.Runtime]System.Exception::.ctor() - IL_0005: throw - } + IL_0002: newobj instance void [System.Runtime]System.Exception::.ctor() + IL_0007: throw + } // end .try catch [System.Runtime]System.Exception { - IL_0006: stloc.1 - IL_0007: ldc.i4.1 - IL_0008: stloc.0 - IL_0009: leave.s IL_000b - } + IL_0008: ldc.i4.1 + IL_0009: stloc.0 + IL_000a: stloc.1 + IL_000b: leave.s IL_000d + } // end handler - IL_000b: ldloc.0 - IL_000c: ldc.i4.1 - IL_000d: bne.un.s IL_0017 + IL_000d: ldloc.0 + IL_000e: ldc.i4.1 + IL_000f: bne.un.s IL_001d - IL_000f: ldloc.1 - IL_0010: call modreq(class [System.Runtime]System.Threading.Tasks.Task) void C::M() - IL_0015: pop - IL_0016: throw + IL_0011: call class [System.Runtime]System.Threading.Tasks.Task C::M() + IL_0016: call void [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::Await(class [System.Runtime]System.Threading.Tasks.Task) + IL_001b: ldloc.1 + IL_001c: throw - IL_0017: ret + IL_001d: ret } ``` -#### Awaiting in a `finally` block +##### Awaiting in a `finally` block ```cs try @@ -459,7 +546,7 @@ catch (Exception e) pendingException = e; } -/* Runtime-Async Call */ C.M(); +System.Runtime.CompilerServices.RuntimeHelpers.Await(C.M()); if (pendingException != null) { @@ -477,26 +564,26 @@ if (pendingException != null) { IL_0000: newobj instance void [System.Runtime]System.Exception::.ctor() IL_0005: throw - } + } // end .try catch [System.Runtime]System.Exception { IL_0006: stloc.0 IL_0007: leave.s IL_0009 - } + } // end handler - IL_0009: call modreq(class [System.Runtime]System.Threading.Tasks.Task) void C::M() - IL_000e: pop - IL_000f: ldloc.0 - IL_0010: brfalse.s IL_0014 + IL_0009: call class [System.Runtime]System.Threading.Tasks.Task C::M() + IL_000e: call void [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::Await(class [System.Runtime]System.Threading.Tasks.Task) + IL_0013: ldloc.0 + IL_0014: brfalse.s IL_0018 - IL_0012: ldloc.0 - IL_0013: throw + IL_0016: ldloc.0 + IL_0017: throw - IL_0014: ret + IL_0018: ret } ``` -#### Preserving compound assignments +##### Preserving compound assignments ```cs int[] a = new int[] { }; @@ -515,36 +602,152 @@ Translated C#: int[] a = new int[] { }; int _tmp1 = C.M2(); int _tmp2 = a[_tmp1]; -int _tmp3 = /* Runtime-Async Call */ C.M1(); +int _tmp3 = System.Runtime.CompilerServices.RuntimeHelpers.Await(C.M1()); a[_tmp1] = _tmp2 + _tmp3; ``` ```il { .locals init ( - [0] int32[] a, - [1] int32 _tmp1, - [2] int32 _tmp2, - [3] int32 _tmp3 + [0] int32 _tmp1, + [1] int32 _tmp2, + [2] int32 _tmp3 ) IL_0000: ldc.i4.0 IL_0001: newarr [System.Runtime]System.Int32 - IL_0006: stloc.0 - IL_0007: call int32 C::M2() - IL_000c: stloc.1 + IL_0006: call int32 C::M2() + IL_000b: stloc.0 + IL_000c: dup IL_000d: ldloc.0 - IL_000e: ldloc.1 - IL_000f: ldelem.i4 - IL_0010: stloc.2 - IL_0011: call modreq(class [System.Runtime]System.Threading.Tasks.Task) int32 C::M1() - IL_0016: stloc.3 - IL_0017: ldloc.0 - IL_0018: ldloc.1 - IL_0019: ldloc.2 - IL_001a: ldloc.3 - IL_001b: add - IL_001c: stelem.i4 - IL_001d: ret + IL_000e: ldelem.i4 + IL_000f: stloc.1 + IL_0010: call class [System.Runtime]System.Threading.Tasks.Task`1 C::M1() + IL_0015: call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::Await(class [System.Runtime]System.Threading.Tasks.Task`1) + IL_001a: stloc.2 + IL_001b: ldloc.0 + IL_001c: ldloc.1 + IL_001d: ldloc.2 + IL_001e: add + IL_001f: stelem.i4 + IL_0020: ret } ``` + +#### Await a non-Task/ValueTask + +For anything that isn't a `Task`, `Task`, `ValueTask`, and `ValueTask`, we instead use `System.Runtime.CompilerServices.RuntimeHelpers.AwaitAwaiterFromRuntimeAsync` or +`System.Runtime.CompilerServices.RuntimeHelpers.UnsafeAwaitAwaiterFromRuntimeAsync`. These are covered below. + +##### Implementor of ICriticalNotifyCompletion + +`ICriticalNotifyCompletion` lowering is always preferred over `INotifyCompletion` lowering, when we statically know `ICriticalNotifyCompletion` is implemented by the expression. + +```cs +var c = new C(); +await c; + +class C +{ + public class Awaiter : ICriticalNotifyCompletion + { + public void OnCompleted(Action continuation) { } + public void UnsafeOnCompleted(Action continuation) { } + public bool IsCompleted => true; + public void GetResult() { } + } + + public Awaiter GetAwaiter() => new Awaiter(); +} +``` + +Translated C#: + +```cs +var c = new C(); +_ = { + var awaiter = c.GetAwaiter(); + if (!awaiter.IsCompleted) + { + System.Runtime.CompilerServices.RuntimeHelpers.UnsafeAwaitAwaiterFromRuntimeAsync(awaiter); + } + awaiter.GetResult() +}; +``` + +```il +{ + .locals init ( + [0] class C/Awaiter awaiter + ) + + IL_0000: newobj instance void C::.ctor() + IL_0005: callvirt instance class C/Awaiter C::GetAwaiter() + IL_000a: stloc.0 + IL_000b: ldloc.0 + IL_000c: callvirt instance bool C/Awaiter::get_IsCompleted() + IL_0011: brtrue.s IL_0019 + + IL_0013: ldloc.0 + IL_0014: call void [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::UnsafeAwaitAwaiterFromRuntimeAsync(!!0) + + IL_0019: ldloc.0 + IL_001a: callvirt instance void C/Awaiter::GetResult() + IL_001f: ret +} +``` + +##### Implementor of INotifyCompletion + +```cs +var c = new C(); +await c; + +class C +{ + public class Awaiter : INotifyCompletion + { + public void OnCompleted(Action continuation) { } + public bool IsCompleted => true; + public void GetResult() { } + } + + public Awaiter GetAwaiter() => new Awaiter(); +} +``` + +Translated C#: + +```cs +var c = new C(); +_ = { + var awaiter = c.GetAwaiter(); + if (!awaiter.IsCompleted) + { + System.Runtime.CompilerServices.RuntimeHelpers.AwaitAwaiterFromRuntimeAsync(awaiter); + } + awaiter.GetResult() +}; +``` + +```il +{ + .locals init ( + [0] class C/Awaiter awaiter + ) + + IL_0000: newobj instance void C::.ctor() + IL_0005: callvirt instance class C/Awaiter C::GetAwaiter() + IL_000a: stloc.0 + IL_000b: ldloc.0 + IL_000c: callvirt instance bool C/Awaiter::get_IsCompleted() + IL_0011: brtrue.s IL_0019 + + IL_0013: ldloc.0 + IL_0014: call void [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::AwaitAwaiterFromRuntimeAsync(!!0) + + IL_0019: ldloc.0 + IL_001a: callvirt instance void C/Awaiter::GetResult() + IL_001f: ret +} +``` diff --git a/docs/contributing/Building, Debugging, and Testing on Windows.md b/docs/contributing/Building, Debugging, and Testing on Windows.md index 87a3722a7adb5..235ae3e82854c 100644 --- a/docs/contributing/Building, Debugging, and Testing on Windows.md +++ b/docs/contributing/Building, Debugging, and Testing on Windows.md @@ -223,15 +223,16 @@ Before pushing a relevant fix to CI, you can validate locally using the `-testUs ### Running the PublicAPI fixer -1. Install `dotnet-format` as a global tool. It does ship as part of the SDK, but a separate version can be installed as a global tool and invoked with `dotnet-format {options}`. -`C:\Source\roslyn> dotnet tool install -g dotnet-format --version "6.*" --add-source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet6/nuget/v3/index.json` -2. Restore and build `Compilers.slnf`. This is necessary to ensure the source generator project is built and we can load the generator assembly when running `dotnet-format`. -`C:\Source\roslyn> .\restore.cmd` -`C:\Source\roslyn> .\build.cmd` -3. Invoke the `dotnet-format` global tool. Running only the analyzers subcommand and fixing only the "missing Public API signature" diagnostic. We must also pass the `--include-generated` flag to include source generated documents in the analysis. -`C:\Source\roslyn> cd ..` -`C:\Source> dotnet-format analyzers .\roslyn\Compilers.slnf --diagnostics=RS0016 --no-restore --include-generated -v diag` - +1. Restore and build `Compilers.slnf`. This is necessary to ensure the source generator project is built and we can load the generator assembly when running `dotnet format`. + ```ps1 + C:\Source\roslyn> .\restore.cmd + C:\Source\roslyn> .\build.cmd + ``` +2. Invoke `dotnet format` (the one included in .NET SDK, not the global tool `dotnet-format` which is deprecated). Running only the analyzers subcommand and fixing only the "missing Public API signature" diagnostic. We must also pass the `--include-generated` flag to include source generated documents in the analysis. + ```ps1 + C:\Source\roslyn> cd .. + C:\Source> dotnet format analyzers .\roslyn\Compilers.slnf --diagnostics=RS0016 --no-restore --include-generated -v diag + ``` ## Contributing diff --git a/docs/contributing/bootstrap-builds.md b/docs/contributing/bootstrap-builds.md index 128a4d59fe740..fd062621eaec0 100644 --- a/docs/contributing/bootstrap-builds.md +++ b/docs/contributing/bootstrap-builds.md @@ -93,6 +93,26 @@ These type of errors, when not paired with a `Debug.Assert` failure, are almost Note: when you encounter a case where the log file does not have an actionable description of why a build failed, strongly consider sending a PR that fixes this. This approach is why the log is such a valuable tool for tracking down bootstrap failures. +### Reproducing locally + +Locally reproducing and attaching a debugger to a bootstrap build failure is fairly simple with use of `src/Tools/Replay`, which can replay a binlog with the checked-out Roslyn compiler source. To do this, run a build locally with the `-bl` flag to get a binary log, then use replay to replay the binary log: + +**Windows** + +```powershell +.\build.ps1 -bl +dotnet run --framework net9.0 src\Tools\Replay\ artifacts\log\Debug\Build.binlog -w +``` + +**Linux** + +```sh +./build.sh -bl +dotnet run --framework net9.0 src/Tools/Replay/ artifacts/log/Debug/Build.binlog -w +``` + +The `-w` flag will cause replay to print the process ID of the compiler and wait until you hit a key, so that you can attach a debugger to the process and set breakpoints for exceptions you are interested in. + ## Debugging To debug a bootstrap build failure locally do the following. diff --git a/docs/features/field-nullability.md b/docs/features/field-nullability.md new file mode 100644 index 0000000000000..5dd2f97992271 --- /dev/null +++ b/docs/features/field-nullability.md @@ -0,0 +1,23 @@ +# `field` keyword nullable analysis implementation + +See also [specification](https://github.com/dotnet/csharplang/blob/94205582d0f5c73e5765cb5888311c2f14890b95/proposals/field-keyword.md#nullability). + +## Symbol API behavior + +In order to decide the NullableAnnotation of a SynthesizedBackingFieldSymbol we need to: +1. Decide if the getter associated with this field requires a null-resilience analysis. +2. If it *doesn't* require such an analysis, then the nullable annotation of the property is used. +3. If it *does*, then a binding+nullable analysis of the getter must be performed to decide the nullability of the backing field. + +There are some significant problems with directly exposing the nullable annotation on this field symbol. +1. Cost. It's not clear if it's OK for reading the NullableAnnotation off a field to cause us to bind and nullable analyze something. If some tooling is traversing member symbols for indexing or some such, it may be a problem if that causes unexpected method binding to occur where it didn't before. +2. Stack cycles. In the process of binding+flow analyzing, we may want to access the nullable annotation of the field. If we are *already* in the process of determining that field's nullable annotation, then we would need to "short-circuit" and return some "placeholder" value. We would need to take care to isolate the "internal" implementation from any public implementation, in order to ensure that a consistent answer is given to users of the public API. +... + +It's tempting to avoid exposing the inferred nullable annotation in the public symbol model. This might be problematic for automated tooling which is trying to reason about nullable initialization. For example, if a diagnostic suppressor wants to suppress `CS8618` nullable initialization warnings under certain conditions. How should it decide whether/why a property like `string Prop => field ??= GetValue();` requires initialization in constructors? It's unclear to me whether this matters. + +In the interests of *simplicity* (first make it correct, then make it fast), I'd like to move forward by *not* exposing the inferred annotation in the symbol model. Rather, we introduce a new internal API `SynthesizedBackingFieldSymbol.GetInferredNullableAnnotation()`, which `NullableWalker` will use to decide initial nullable state, report warnings, and so on. The implementation simply does an on-demand binding of the get accessor, then nullable analyzes and decides the nullable annotation. Care needs to be taken to avoid using this API in a re-entrant manner--so, the `NullableWalker` passes which are used to infer the nullability annotation must avoid calling it. + +This means that the ordinary `FieldSymbol.TypeWithAnnotations` API would not expose the inferred nullability, and neither would `IFieldSymbol.Type` or `IFieldSymbol.NullableAnnotation`. Instead the field's nullability would always match the property's. This is something I would actually like to fix, maybe before merging to main. It feels like Quick Info, etc., should expose the inferred nullability through the ordinary APIs. + +Once we get a handle on the behaviors of the getter null resilience, we can start talking about how to reduce cost associated with it. For example, we could try to reduce redundant binding, by forcing nullable annotations to be inferred prior to analyzing certain methods. Before processing a constructor in `MethodCompiler`, for example, maybe we would identify the getters that need to be compiled for purposes of inference, and force those to compile first. \ No newline at end of file diff --git a/docs/features/string-literals-data-section.md b/docs/features/string-literals-data-section.md index 6d61a39a0cf14..adda3e666eaf0 100644 --- a/docs/features/string-literals-data-section.md +++ b/docs/features/string-literals-data-section.md @@ -54,7 +54,7 @@ The utf8 string literal encoding emit strategy emits `ldsfld` of a field in a ge For every unique string literal, a unique internal static class is generated which: - has name composed of `` followed by a hex-encoded XXH128 hash of the string - (collisions [should not happen][xxh128] with XXH128 and so they aren't currently detected or reported, the behavior in that case is undefined), + (collisions [should not happen][xxh128] with XXH128, but if there are string literals which would result in the same XXH128 hash, a compile-time error is reported), - is nested in the `` type to avoid polluting the global namespace and to avoid having to enforce name uniqueness across modules, - has one internal static readonly `string` field which is initialized in a static constructor of the class, @@ -62,6 +62,7 @@ For every unique string literal, a unique internal static class is generated whi There is also an internal static readonly `.data` field generated into `` containing the actual bytes, similar to [u8 string literals][u8-literals] and [constant array initializers][constant-array-init]. +This field uses hex-encoded SHA-256 hash for its name and collisions are currently not reported by the compiler. These other scenarios might also reuse the data field, e.g., the following statements could all reuse the same data field: ```cs @@ -136,15 +137,63 @@ albeit with a disclaimer during the experimental phase of the feature. Throughput of `ldstr` vs `ldsfld` is very similar (both result in one or two move instructions). In the `ldsfld` emit strategy, the `string` instances won't ever be collected by the GC once the generated class is initialized. -`ldstr` has similar behavior, but there are some optimizations in the runtime around `ldstr`, +`ldstr` has similar behavior (GC does not collect the string literals either until the assembly is unloaded), +but there are some optimizations in the runtime around `ldstr`, e.g., they are loaded into a different frozen heap so machine codegen can be more efficient (no need to worry about pointer moves). Generating new types by the compiler means more type loads and hence runtime impact, e.g., startup performance and the overhead of keeping track of these types. +On the other hand, the PE size might be smaller due to UTF-8 vs UTF-16 encoding, +which can result in memory savings since the binary is also loaded to memory by the runtime. +See [below](#runtime-overhead-benchmark) for a more detailed analysis. The generated types are returned from reflection like `Assembly.GetTypes()` which might impact the performance of Dependency Injection and similar systems. +### Runtime overhead benchmark + +| [cost per string literal](https://github.com/jkotas/stringliteralperf) | feature on | feature off | +| --- | --- | --- | +| bytes | 1037 | 550 | +| microseconds | 20.3 | 3.1 | + +The benchmark results above [show](https://github.com/dotnet/roslyn/pull/76139#discussion_r1944144978) +that the runtime overhead of this feature per 100 char string literal +is ~500 bytes of working set memory (~2x of regular string literal) +and ~17 microseconds of startup time (~7x of regular string literal). + +The startup time overhead does depend on the length of the string literal. +It is cost of the type loads and JITing the static constructor. + +The working set has two components: private working set (r/w pages) and non-private working set (r/o pages backed by the binary). +The private working set overhead (~600 bytes) does not depend on the length of the string literal. +Again, it is the cost of the type loads and the static constructor code. +Non-private working set is reduced by this feature since the binary is smaller. +Once the string literal is about 600 characters, +the private working set overhead and non-private working set improvement will break even. +For string literals longer than 600 characters, this feature is total working set improvement. + +
+Why 600 bytes? + +When the feature is off, ~550 bytes cost of 100 char string literal is composed from: +- The string in the binary (~200 bytes). +- The string allocated on the GC heap (~200 bytes). +- Fixed overheads: metadata encoding, runtime hashtable of all allocated string literals, code that referenced the string in the benchmark (~150 bytes). + +When the feature is on, ~1050 bytes cost of 100 char string literal is composed from: +- The string in the binary (~100 bytes). +- The string allocated on the GC heap (~200 bytes). +- Fixed overheads: metadata encoding, the extra types, code that referenced the string in the benchmark (~750 bytes). + +750 - 150 = 600. Vast majority of it are the extra types. + +A bit of the extra fixed overheads with the feature on is probably in the non-private working set. +It is difficult to measure it since there is no managed API to get private vs. non-private working set. +It does not impact the estimate of the break-even point for the total working set. + +
+ ## Implementation `CodeGenerator` obtains [configuration of the feature flag](#configuration) from `Compilation` passed to its constructor. @@ -168,7 +217,7 @@ but that seems to require similar amount of implemented abstract properties/meth as the implementations of `Cci` interfaces require. But implementing `Cci` directly allows us to reuse the same implementation for VB if needed in the future. -## Future work +## Future work and alternatives ### Edit and Continue @@ -193,6 +242,9 @@ This fixup phase already exists in the compiler in `MetadataWriter.WriteInstruct It is called from `SerializeMethodBodies` which precedes `PopulateSystemTables` call, hence synthesizing the utf8 string classes in the former should be possible and they would be emitted in the latter. +Alternatively, we could collect string literals during binding, then before emit sort them by length and content (for determinism) +to find the ones that are over the threshold and should be emitted with this new strategy. + ### Statistics The compiler could emit an info diagnostic with useful statistics for customers to determine what threshold to set. @@ -209,7 +261,7 @@ We would generate a single `__StaticArrayInitTypeSize=*` structure for the entir add a single `.data` field to `` that points to the blob. At runtime, we would do an offset to where the required data reside in the blob and decode the required length from UTF-8 to UTF-16. -## Alternatives +However, this would be unfriendly to IL trimming. ### Configuration/emit granularity @@ -221,7 +273,8 @@ The idea is that strings from one class are likely used "together" so there is n ### GC -To avoid rooting the `string` references forever, we could turn the fields into `WeakReference`s. +To avoid rooting the `string` references forever, we could turn the fields into `WeakReference`s +(note that this would be quite expensive for both direct overhead and indirectly for the GC due to longer GC pause times). Or we could avoid the caching altogether (each eligible `ldstr` would be replaced with a direct call to `Encoding.UTF8.GetString`). This could be configurable as well. @@ -247,6 +300,24 @@ static class However, that would likely result in worse machine code due to more branches and function calls. +### String interning + +The compiler should report a diagnostic when the feature is enabled together with +`[assembly: System.Runtime.CompilerServices.CompilationRelaxations(0)]`, i.e., string interning enabled, +because that is incompatible with the feature. + +### Avoiding hash collisions + +Instead of XXH128 for the type names and SHA-256 for the data field names, we could use index-based names. +- The compiler could assign names lazily based on metadata tokens which are deterministic. + If building on the current approach, that might require some refactoring, + because internal data structures in the compiler might not be ready for lazy names like that. + But it would be easier if combined with the first strategy suggested for [automatic threshold](#automatic-threshold) above, + where we would not synthesize the types until very late in the emit phase (during fixup of the metadata tokens). +- We could build on the second strategy suggested for [automatic threshold](#automatic-threshold) where we would collect string literals during binding + (and perhaps also constant arrays and u8 strings if we want to extend this support to them as well), + then before emit we would sort them by length and content and assign indices to them to be then used for the synthesized names. + [u8-literals]: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-11.0/utf8-string-literals [constant-array-init]: https://github.com/dotnet/roslyn/pull/24621 diff --git a/docs/wiki/NuGet-packages.md b/docs/wiki/NuGet-packages.md index 3caad8005c828..f7a0c0c41b582 100644 --- a/docs/wiki/NuGet-packages.md +++ b/docs/wiki/NuGet-packages.md @@ -51,6 +51,7 @@ Below are the versions of the language available in the NuGet packages. Remember - Version `4.10` includes C# 12.0 (Visual Studio 2022 version 17.10, .NET 8) - Version `4.11` includes C# 12.0 (Visual Studio 2022 version 17.11, .NET 8) - Version `4.12` includes C# 13.0 (Visual Studio 2022 version 17.12, .NET 9) +- Version `4.13` includes C# 13.0 (Visual Studio 2022 version 17.13, .NET 9) See the [history of C# language features](https://github.com/dotnet/csharplang/blob/main/Language-Version-History.md) for more details. diff --git a/eng/Directory.Packages.props b/eng/Directory.Packages.props index e28bb02fdaa1c..780303429343d 100644 --- a/eng/Directory.Packages.props +++ b/eng/Directory.Packages.props @@ -8,11 +8,10 @@ <_BasicReferenceAssembliesVersion>1.7.9 4.8.0-3.final - 17.12.145-preview + 17.13.226 9.0.0-rc.2.24462.10 6.0.0-rtm.21518.12 7.0.0-alpha.1.22060.1 - <_MicrosoftTestPlatformVersion>17.5.0 - + - + @@ -92,36 +91,36 @@ Subset of Microsoft.VisualStudio.Sdk meta-package (run `csi generate-vssdk-versions.csx` to update based on VSSDK meta-package). See https://github.com/dotnet/arcade/blob/main/Documentation/MirroringPackages.md if any of these packages fail to restore. --> - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - + + + + + + + + + - + - + @@ -142,8 +141,8 @@ --> - - + + - - - $(RestoreSources); - https://devdiv.pkgs.visualstudio.com/_packaging/Engineering/nuget/v3/index.json; - https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public/nuget/v3/index.json; - - - $(RestoreSources); - https://pkgs.dev.azure.com/devdiv/_packaging/dotnet-core-internal-tooling/nuget/v3/index.json - - - - - https://pkgs.dev.azure.com/devdiv/_packaging/dotnet-core-internal-tooling/nuget/v3/index.json; - https://pkgs.dev.azure.com/devdiv/_packaging/VS/nuget/v3/index.json; - https://pkgs.dev.azure.com/devdiv/_packaging/Engineering/nuget/v3/index.json; - https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public/nuget/v3/index.json; - https://pkgs.dev.azure.com/devdiv/_packaging/dotnet-core-internal-tooling/nuget/v3/index.json - - - @@ -29,5 +8,4 @@ - diff --git a/eng/SourceBuildPrebuiltBaseline.xml b/eng/SourceBuildPrebuiltBaseline.xml index 140179baf5d0d..b0ff6e9a88c54 100644 --- a/eng/SourceBuildPrebuiltBaseline.xml +++ b/eng/SourceBuildPrebuiltBaseline.xml @@ -13,42 +13,42 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 3391513cd61fd..7991cb0c27923 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -8,9 +8,9 @@ - + https://github.com/dotnet/source-build-reference-packages - be366997dfae0aa6e3c9a78bad10bfb3f79cbde1 + d2fc98192bb9780acbe2ad3df284da19203cc26d @@ -24,123 +24,117 @@ - + https://github.com/dotnet/runtime - 5535e31a712343a63f5d7d796cd874e563e5ac14 + 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3 - + https://github.com/dotnet/runtime - 5535e31a712343a63f5d7d796cd874e563e5ac14 + 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3 - + https://github.com/dotnet/runtime - 5535e31a712343a63f5d7d796cd874e563e5ac14 + 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3 - + https://github.com/dotnet/runtime - 5535e31a712343a63f5d7d796cd874e563e5ac14 + 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3 - + https://github.com/dotnet/runtime - 5535e31a712343a63f5d7d796cd874e563e5ac14 + 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3 - + https://github.com/dotnet/runtime - 5535e31a712343a63f5d7d796cd874e563e5ac14 + 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3 https://github.com/dotnet/runtime 5535e31a712343a63f5d7d796cd874e563e5ac14 - + https://github.com/dotnet/runtime - 5535e31a712343a63f5d7d796cd874e563e5ac14 + 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3 - + https://github.com/dotnet/runtime - 5535e31a712343a63f5d7d796cd874e563e5ac14 + 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3 - + https://github.com/dotnet/runtime - 5535e31a712343a63f5d7d796cd874e563e5ac14 + 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3 - + https://github.com/dotnet/runtime - 5535e31a712343a63f5d7d796cd874e563e5ac14 + 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3 - + https://github.com/dotnet/runtime - 5535e31a712343a63f5d7d796cd874e563e5ac14 + 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3 - + https://github.com/dotnet/runtime - 5535e31a712343a63f5d7d796cd874e563e5ac14 + 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3 - + https://github.com/dotnet/runtime - 5535e31a712343a63f5d7d796cd874e563e5ac14 + 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3 - + https://github.com/dotnet/runtime - 5535e31a712343a63f5d7d796cd874e563e5ac14 + 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3 - + https://github.com/dotnet/runtime - 5535e31a712343a63f5d7d796cd874e563e5ac14 + 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3 - + https://github.com/dotnet/runtime - 5535e31a712343a63f5d7d796cd874e563e5ac14 + 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3 - + https://github.com/dotnet/runtime - 5535e31a712343a63f5d7d796cd874e563e5ac14 + 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3 - + https://github.com/dotnet/runtime - 5535e31a712343a63f5d7d796cd874e563e5ac14 + 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3 - + https://github.com/dotnet/runtime - 5535e31a712343a63f5d7d796cd874e563e5ac14 + 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3 - + https://github.com/dotnet/runtime - 5535e31a712343a63f5d7d796cd874e563e5ac14 + 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3 - + https://github.com/dotnet/runtime - 5535e31a712343a63f5d7d796cd874e563e5ac14 + 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3 - + https://github.com/dotnet/runtime - 5535e31a712343a63f5d7d796cd874e563e5ac14 + 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3 - + https://github.com/dotnet/runtime - 5535e31a712343a63f5d7d796cd874e563e5ac14 + 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3 - + https://github.com/dotnet/arcade - c4bbc67763bf0c5a868862df874079380e647d61 + 5ba9ca776c1d0bb72b2791591e54cf51fc52dfee - + https://github.com/dotnet/arcade - c4bbc67763bf0c5a868862df874079380e647d61 + 5ba9ca776c1d0bb72b2791591e54cf51fc52dfee - - https://github.com/dotnet/xliff-tasks - 73f0850939d96131c28cf6ea6ee5aacb4da0083a - - - - https://github.com/dotnet/xliff-tasks - 73f0850939d96131c28cf6ea6ee5aacb4da0083a - + + https://github.com/dotnet/arcade + 5ba9ca776c1d0bb72b2791591e54cf51fc52dfee https://github.com/dotnet/symreader @@ -156,9 +150,9 @@ https://github.com/dotnet/roslyn 5d10d428050c0d6afef30a072c4ae68776621877 - + https://github.com/dotnet/arcade - c4bbc67763bf0c5a868862df874079380e647d61 + 5ba9ca776c1d0bb72b2791591e54cf51fc52dfee https://github.com/dotnet/roslyn-analyzers @@ -166,9 +160,9 @@ - + https://github.com/dotnet/runtime - 5535e31a712343a63f5d7d796cd874e563e5ac14 + 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3 https://github.com/dotnet/roslyn-analyzers diff --git a/eng/Versions.props b/eng/Versions.props index 24ca795bf3570..93ef5b3ac8bae 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -8,7 +8,7 @@ 4 14 0 - 1 + 3 $(MajorVersion).$(MinorVersion).$(PatchVersion) - 6.1.0 - 4.6.0 + 6.1.2 + 4.6.1 4.9.0 - 4.6.0 - 4.6.0 - 6.1.0 - 4.6.0 + 4.6.2 + 4.6.1 + 6.1.1 + 4.6.2 6.0.1 @@ -47,37 +47,37 @@ --> 2.0.0-beta4.24528.1 - 8.0.0 - 8.0.0 - 8.0.0 - 8.0.0 - 8.0.0 - 8.0.1 - 8.0.0 - 8.0.0 - 8.0.0 - 8.0.0 - 8.0.0 - 8.0.0 - 8.0.0 + 9.0.0 + 9.0.0 + 9.0.0 + 9.0.0 + 9.0.0 + 9.0.0 + 9.0.0 + 9.0.0 + 9.0.0 + 9.0.0 + 9.0.0 + 9.0.0 + 9.0.0 - 8.0.5 - 8.0.0 - 8.0.0 - 8.0.0 + 9.0.0 + 9.0.0 + 9.0.0 + 9.0.0 3.11.0 3.3.0 8.0.0-preview.23468.1 2.0.0 - 8.0.0 - 8.0.0 + 9.0.0 + 9.0.0 8.0.0 - 8.0.0 - 8.0.0 - 8.0.0 + 9.0.0 + 9.0.0 + 9.0.0 8.0.0 - 8.0.0 - 8.0.0 + 9.0.0 + 9.0.0 17.9.3137-preview3 2.4.1 - 9.0.0-beta.24076.5 4.61.3 6.34.0 @@ -99,12 +97,21 @@ false true true - true - true + + true + true true false true true + + + 17.5.0 + diff --git a/eng/build.ps1 b/eng/build.ps1 index 2a173ce151b73..e2d2d58e609b9 100644 --- a/eng/build.ps1 +++ b/eng/build.ps1 @@ -46,6 +46,7 @@ param ( [switch]$sourceBuild = $false, [switch]$oop64bit = $true, [switch]$lspEditor = $false, + [string]$solution = "Roslyn.sln", # official build settings [string]$officialBuildId = "", @@ -112,6 +113,7 @@ function Print-Usage() { Write-Host " -useGlobalNuGetCache Use global NuGet cache." Write-Host " -warnAsError Treat all warnings as errors" Write-Host " -sourceBuild Simulate building source-build" + Write-Host " -solution Solution to build (default is Roslyn.sln)" Write-Host "" Write-Host "Official build settings:" Write-Host " -officialBuildId An official build id, e.g. 20190102.3" @@ -221,9 +223,15 @@ function Process-Arguments() { } } -function BuildSolution() { - $solution = "Roslyn.sln" +function RestoreInternalTooling() { + $internalToolingProject = Join-Path $RepoRoot 'eng/common/internal/Tools.csproj' + # The restore config file might be set via env var. Ignore that for this operation, + # as the internal nuget.config should be used. + $restoreConfigFile = Join-Path $RepoRoot 'eng/common/internal/NuGet.config' + MSBuild $internalToolingProject /t:Restore /p:RestoreConfigFile=$restoreConfigFile +} +function BuildSolution() { Write-Host "$($solution):" $bl = "" @@ -333,6 +341,9 @@ function GetIbcDropName() { return "" } + # Ensure that we have the internal tooling restored before attempting to load the powershell module. + RestoreInternalTooling + # Bring in the ibc tools $packagePath = Join-Path (Get-PackageDir "Microsoft.DevDiv.Optimization.Data.PowerShell") "lib\net472" Import-Module (Join-Path $packagePath "Optimization.Data.PowerShell.dll") diff --git a/eng/build.sh b/eng/build.sh index 3cbeeb841e536..53fd09baa4451 100755 --- a/eng/build.sh +++ b/eng/build.sh @@ -38,7 +38,7 @@ usage() echo " --prepareMachine Prepare machine for CI run, clean up processes after build" echo " --warnAsError Treat all warnings as errors" echo " --sourceBuild Simulate building for source-build" - echo " --solution Soluton to build (Default is Compilers.slnf)" + echo " --solution Solution to build (default is Compilers.slnf)" echo "" echo "Command line arguments starting with '/p:' are passed through to MSBuild." } @@ -209,7 +209,7 @@ function MakeBootstrapBuild { mkdir -p $dir local package_name="Microsoft.Net.Compilers.Toolset" - local project_path=src/NuGet/$package_name/$package_name.Package.csproj + local project_path=src/NuGet/$package_name/AnyCpu/$package_name.Package.csproj dotnet pack -nologo "$project_path" -p:ContinuousIntegrationBuild=$ci -p:DotNetUseShippingVersions=true -p:InitialDefineConstants=BOOTSTRAP -p:PackageOutputPath="$dir" -bl:"$log_dir/Bootstrap.binlog" unzip "$dir/$package_name.*.nupkg" -d "$dir" diff --git a/eng/common/core-templates/steps/generate-sbom.yml b/eng/common/core-templates/steps/generate-sbom.yml index d938b60e1bb53..56a090094824f 100644 --- a/eng/common/core-templates/steps/generate-sbom.yml +++ b/eng/common/core-templates/steps/generate-sbom.yml @@ -38,7 +38,7 @@ steps: PackageName: ${{ parameters.packageName }} BuildDropPath: ${{ parameters.buildDropPath }} PackageVersion: ${{ parameters.packageVersion }} - ManifestDirPath: ${{ parameters.manifestDirPath }} + ManifestDirPath: ${{ parameters.manifestDirPath }}/$(ARTIFACT_NAME) ${{ if ne(parameters.IgnoreDirectories, '') }}: AdditionalComponentDetectorArgs: '--IgnoreDirectories ${{ parameters.IgnoreDirectories }}' diff --git a/eng/common/generate-sbom-prep.ps1 b/eng/common/generate-sbom-prep.ps1 index 3e5c1c74a1c50..a0c7d792a76fb 100644 --- a/eng/common/generate-sbom-prep.ps1 +++ b/eng/common/generate-sbom-prep.ps1 @@ -4,18 +4,26 @@ Param( . $PSScriptRoot\pipeline-logging-functions.ps1 +# Normally - we'd listen to the manifest path given, but 1ES templates will overwrite if this level gets uploaded directly +# with their own overwriting ours. So we create it as a sub directory of the requested manifest path. +$ArtifactName = "${env:SYSTEM_STAGENAME}_${env:AGENT_JOBNAME}_SBOM" +$SafeArtifactName = $ArtifactName -replace '["/:<>\\|?@*"() ]', '_' +$SbomGenerationDir = Join-Path $ManifestDirPath $SafeArtifactName + +Write-Host "Artifact name before : $ArtifactName" +Write-Host "Artifact name after : $SafeArtifactName" + Write-Host "Creating dir $ManifestDirPath" + # create directory for sbom manifest to be placed -if (!(Test-Path -path $ManifestDirPath)) +if (!(Test-Path -path $SbomGenerationDir)) { - New-Item -ItemType Directory -path $ManifestDirPath - Write-Host "Successfully created directory $ManifestDirPath" + New-Item -ItemType Directory -path $SbomGenerationDir + Write-Host "Successfully created directory $SbomGenerationDir" } else{ Write-PipelineTelemetryError -category 'Build' "Unable to create sbom folder." } Write-Host "Updating artifact name" -$artifact_name = "${env:SYSTEM_STAGENAME}_${env:AGENT_JOBNAME}_SBOM" -replace '["/:<>\\|?@*"() ]', '_' -Write-Host "Artifact name $artifact_name" -Write-Host "##vso[task.setvariable variable=ARTIFACT_NAME]$artifact_name" +Write-Host "##vso[task.setvariable variable=ARTIFACT_NAME]$SafeArtifactName" diff --git a/eng/common/generate-sbom-prep.sh b/eng/common/generate-sbom-prep.sh index d5c76dc827b49..b8ecca72bbf50 100644 --- a/eng/common/generate-sbom-prep.sh +++ b/eng/common/generate-sbom-prep.sh @@ -14,19 +14,24 @@ done scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" . $scriptroot/pipeline-logging-functions.sh + +# replace all special characters with _, some builds use special characters like : in Agent.Jobname, that is not a permissible name while uploading artifacts. +artifact_name=$SYSTEM_STAGENAME"_"$AGENT_JOBNAME"_SBOM" +safe_artifact_name="${artifact_name//["/:<>\\|?@*$" ]/_}" manifest_dir=$1 -if [ ! -d "$manifest_dir" ] ; then - mkdir -p "$manifest_dir" - echo "Sbom directory created." $manifest_dir +# Normally - we'd listen to the manifest path given, but 1ES templates will overwrite if this level gets uploaded directly +# with their own overwriting ours. So we create it as a sub directory of the requested manifest path. +sbom_generation_dir="$manifest_dir/$safe_artifact_name" + +if [ ! -d "$sbom_generation_dir" ] ; then + mkdir -p "$sbom_generation_dir" + echo "Sbom directory created." $sbom_generation_dir else Write-PipelineTelemetryError -category 'Build' "Unable to create sbom folder." fi -artifact_name=$SYSTEM_STAGENAME"_"$AGENT_JOBNAME"_SBOM" echo "Artifact name before : "$artifact_name -# replace all special characters with _, some builds use special characters like : in Agent.Jobname, that is not a permissible name while uploading artifacts. -safe_artifact_name="${artifact_name//["/:<>\\|?@*$" ]/_}" echo "Artifact name after : "$safe_artifact_name export ARTIFACT_NAME=$safe_artifact_name echo "##vso[task.setvariable variable=ARTIFACT_NAME]$safe_artifact_name" diff --git a/eng/common/internal/Tools.csproj b/eng/common/internal/Tools.csproj index 32f79dfb3402c..feaa6d20812d8 100644 --- a/eng/common/internal/Tools.csproj +++ b/eng/common/internal/Tools.csproj @@ -15,16 +15,6 @@ - - - - https://devdiv.pkgs.visualstudio.com/_packaging/dotnet-core-internal-tooling/nuget/v3/index.json; - - - $(RestoreSources); - https://devdiv.pkgs.visualstudio.com/_packaging/VS/nuget/v3/index.json; - - diff --git a/eng/common/templates-official/job/job.yml b/eng/common/templates-official/job/job.yml index 605692d2fb770..817555505aa60 100644 --- a/eng/common/templates-official/job/job.yml +++ b/eng/common/templates-official/job/job.yml @@ -16,6 +16,7 @@ jobs: parameters: PackageVersion: ${{ parameters.packageVersion }} BuildDropPath: ${{ parameters.buildDropPath }} + ManifestDirPath: $(Build.ArtifactStagingDirectory)/sbom publishArtifacts: false # publish artifacts diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 index a46b6deb75986..22b49e09d09b5 100644 --- a/eng/common/tools.ps1 +++ b/eng/common/tools.ps1 @@ -42,7 +42,7 @@ [bool]$useInstalledDotNetCli = if (Test-Path variable:useInstalledDotNetCli) { $useInstalledDotNetCli } else { $true } # Enable repos to use a particular version of the on-line dotnet-install scripts. -# default URL: https://dotnet.microsoft.com/download/dotnet/scripts/v1/dotnet-install.ps1 +# default URL: https://builds.dotnet.microsoft.com/dotnet/scripts/v1/dotnet-install.ps1 [string]$dotnetInstallScriptVersion = if (Test-Path variable:dotnetInstallScriptVersion) { $dotnetInstallScriptVersion } else { 'v1' } # True to use global NuGet cache instead of restoring packages to repository-local directory. @@ -262,7 +262,7 @@ function GetDotNetInstallScript([string] $dotnetRoot) { if (!(Test-Path $installScript)) { Create-Directory $dotnetRoot $ProgressPreference = 'SilentlyContinue' # Don't display the console progress UI - it's a huge perf hit - $uri = "https://dotnet.microsoft.com/download/dotnet/scripts/$dotnetInstallScriptVersion/dotnet-install.ps1" + $uri = "https://builds.dotnet.microsoft.com/dotnet/scripts/$dotnetInstallScriptVersion/dotnet-install.ps1" Retry({ Write-Host "GET $uri" diff --git a/eng/common/tools.sh b/eng/common/tools.sh index 1159726a10fd6..01b09b65796c1 100755 --- a/eng/common/tools.sh +++ b/eng/common/tools.sh @@ -54,7 +54,7 @@ warn_as_error=${warn_as_error:-true} use_installed_dotnet_cli=${use_installed_dotnet_cli:-true} # Enable repos to use a particular version of the on-line dotnet-install scripts. -# default URL: https://dotnet.microsoft.com/download/dotnet/scripts/v1/dotnet-install.sh +# default URL: https://builds.dotnet.microsoft.com/dotnet/scripts/v1/dotnet-install.sh dotnetInstallScriptVersion=${dotnetInstallScriptVersion:-'v1'} # True to use global NuGet cache instead of restoring packages to repository-local directory. @@ -295,7 +295,7 @@ function with_retries { function GetDotNetInstallScript { local root=$1 local install_script="$root/dotnet-install.sh" - local install_script_url="https://dotnet.microsoft.com/download/dotnet/scripts/$dotnetInstallScriptVersion/dotnet-install.sh" + local install_script_url="https://builds.dotnet.microsoft.com/dotnet/scripts/$dotnetInstallScriptVersion/dotnet-install.sh" if [[ ! -a "$install_script" ]]; then mkdir -p "$root" diff --git a/eng/config/PublishData.json b/eng/config/PublishData.json index c53c5dc821844..a6c3e79de0e96 100644 --- a/eng/config/PublishData.json +++ b/eng/config/PublishData.json @@ -31,9 +31,11 @@ "Microsoft.Net.Compilers.Toolset.Arm64": "arcade", "Microsoft.Net.Compilers.Toolset.Framework": "arcade", "Microsoft.NETCore.Compilers": "arcade", + "Microsoft.CodeAnalysis.Contracts": "arcade", "Microsoft.CodeAnalysis.Debugging": "arcade", "Microsoft.CodeAnalysis.PooledObjects": "arcade", "Microsoft.CodeAnalysis.Collections": "arcade", + "Microsoft.CodeAnalysis.Threading": "arcade", "Microsoft.CodeAnalysis.Features": "arcade", "Microsoft.CodeAnalysis.EditorFeatures": "vssdk", "Microsoft.CodeAnalysis.EditorFeatures.Common": "vssdk", @@ -76,18 +78,21 @@ "Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.CSharp": "arcade", "Microsoft.CodeAnalysis.ExternalAccess.AspNetCore": "vs-impl", "Microsoft.CodeAnalysis.ExternalAccess.Razor": "vs-impl", + "Microsoft.CodeAnalysis.ExternalAccess.Razor.Features": "vs-impl", "Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler": "vs-impl", "Microsoft.CodeAnalysis.ExternalAccess.TypeScript": "vs-impl", "Microsoft.CodeAnalysis.ExternalAccess.UnitTesting": "vs-impl", "Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics": "vs-impl", "Microsoft.CodeAnalysis.ExternalAccess.Xamarin.Remote": "vs-impl", - "Microsoft.CodeAnalysis.ExternalAccess.Xaml": "vs-impl", + "Microsoft.CodeAnalysis.ExternalAccess.Xaml": "vs-impl", "Microsoft.CodeAnalysis.ExternalAccess.DotNetWatch": "vs-impl", + "Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot": "vs-impl", "Microsoft.CodeAnalysis.Remote.Razor.ServiceHub": "vs-impl", "Microsoft.CodeAnalysis.Remote.ServiceHub": "vs-impl", "Microsoft.CodeAnalysis.Remote.Workspaces": "vs-impl", "Microsoft.VisualStudio.LanguageServices.LiveShare": "vs-impl", "Microsoft.VisualStudio.LanguageServices.Razor.RemoteClient": "vs-impl", + "Microsoft.VisualStudio.LanguageServices.ExternalAccess.Copilot": "vs-impl", "Microsoft.CommonLanguageServerProtocol.Framework": "vs-impl", "Microsoft.CommonLanguageServerProtocol.Framework.Binary": "vs-impl" } @@ -108,14 +113,6 @@ "vsBranch": "rel/d15.9", "vsMajorVersion": 15 }, - "release/dev16.9-vs-deps": { - "nugetKind": [ - "Shipping", - "NonShipping" - ], - "vsBranch": "rel/d16.9", - "vsMajorVersion": 16 - }, "release/dev16.11-vs-deps": { "nugetKind": [ "Shipping", @@ -125,51 +122,6 @@ "vsMajorVersion": 16, "insertionTitlePrefix": "[d16.11]" }, - "release/dev17.0-vs-deps": { - "nugetKind": [ - "Shipping", - "NonShipping" - ], - "vsBranch": "rel/d17.0", - "vsMajorVersion": 17, - "insertionTitlePrefix": "[d17.0]" - }, - "release/dev17.2": { - "nugetKind": [ - "Shipping", - "NonShipping" - ], - "vsBranch": "rel/d17.2", - "vsMajorVersion": 17, - "insertionTitlePrefix": "[d17.2]" - }, - "release/dev17.3": { - "nugetKind": [ - "Shipping", - "NonShipping" - ], - "vsBranch": "rel/d17.3", - "vsMajorVersion": 17, - "insertionTitlePrefix": "[d17.3]" - }, - "release/dev17.6": { - "nugetKind": [ - "Shipping", - "NonShipping" - ], - "vsBranch": "rel/d17.6", - "vsMajorVersion": 17, - "insertionTitlePrefix": "[d17.6]" - }, - "release/dev17.7": { - "nugetKind": [ - "Shipping", - "NonShipping" - ], - "vsBranch": "rel/d17.7", - "vsMajorVersion": 17, - "insertionTitlePrefix": "[d17.7]" - }, "release/dev17.8": { "nugetKind": [ "Shipping", @@ -179,15 +131,6 @@ "vsMajorVersion": 17, "insertionTitlePrefix": "[d17.8]" }, - "release/dev17.9": { - "nugetKind": [ - "Shipping", - "NonShipping" - ], - "vsBranch": "rel/d17.9", - "vsMajorVersion": 17, - "insertionTitlePrefix": "[d17.9]" - }, "release/dev17.10": { "nugetKind": [ "Shipping", @@ -197,15 +140,6 @@ "vsMajorVersion": 17, "insertionTitlePrefix": "[d17.10]" }, - "release/dev17.11": { - "nugetKind": [ - "Shipping", - "NonShipping" - ], - "vsBranch": "rel/d17.11", - "vsMajorVersion": 17, - "insertionTitlePrefix": "[d17.11]" - }, "release/dev17.12": { "nugetKind": [ "Shipping", @@ -215,15 +149,6 @@ "vsMajorVersion": 17, "insertionTitlePrefix": "[d17.12]" }, - "release/dev17.12-telmet": { - "nugetKind": [ - "Shipping", - "NonShipping" - ], - "vsBranch": "rel/d17.12telmet", - "vsMajorVersion": 17, - "insertionTitlePrefix": "[d17.12]" - }, "release/dev17.13": { "nugetKind": [ "Shipping", @@ -231,56 +156,37 @@ ], "vsBranch": "rel/d17.13", "vsMajorVersion": 17, - "insertionTitlePrefix": "[d17.13 P3]" + "insertionTitlePrefix": "[d17.13]" }, - "release/dev17.13-preview2.1": { + "release/dev17.14": { "nugetKind": [ "Shipping", "NonShipping" ], - "vsBranch": "rel/d17.13", + "vsBranch": "rel/d17.14", "vsMajorVersion": 17, - "insertionTitlePrefix": "[d17.13 P2]" - }, - "main": { - "nugetKind": [ - "Shipping", - "NonShipping" - ], - "vsBranch": "main", - "vsMajorVersion": 17, - "insertionCreateDraftPR": false, - "insertionTitlePrefix": "[d17.14 P1]" - }, - "dev/andrha/telemetry": { - "nugetKind": [ - "Shipping", - "NonShipping" - ], - "vsBranch": "main", - "vsMajorVersion": 17, - "insertionCreateDraftPR": true, - "insertionTitlePrefix": "[Telemetry Validation]" + "insertionTitlePrefix": "[d17.14 P2]", + "insertionCreateDraftPR": false }, - "dev/jorobich/pr-val-v3-publishing": { + "release/dev17.15": { "nugetKind": [ "Shipping", "NonShipping" ], - "vsBranch": "main", + "vsBranch": "feature/d18initial", "vsMajorVersion": 17, - "insertionCreateDraftPR": true, - "insertionTitlePrefix": "[PR Validation]" + "insertionTitlePrefix": "[d17.15 P1]", + "insertionCreateDraftPR": false }, - "demo/razor-lexer": { + "main": { "nugetKind": [ "Shipping", "NonShipping" ], "vsBranch": "main", - "insertionTitlePrefix": "[Do not merge, please close me]", "vsMajorVersion": 17, - "insertionCreateDraftPR": false + "insertionCreateDraftPR": false, + "insertionTitlePrefix": "[d17.14 P3]" } } } diff --git a/eng/config/branch-merge.jsonc b/eng/config/branch-merge.jsonc new file mode 100644 index 0000000000000..7b4de316fb23c --- /dev/null +++ b/eng/config/branch-merge.jsonc @@ -0,0 +1,9 @@ +// Used by .github/workflows/main-merge.yml +{ + "merge-flow-configurations": { + "main": { + "MergeToBranch": "release/dev17.15", + "ExtraSwitches": "-QuietComments" + } + } +} diff --git a/eng/setup-pr-validation.ps1 b/eng/setup-pr-validation.ps1 index 44f3e7d07f6c8..d5d594deb41cd 100644 --- a/eng/setup-pr-validation.ps1 +++ b/eng/setup-pr-validation.ps1 @@ -2,7 +2,8 @@ param ( [string]$sourceBranchName, [string]$prNumber, - [string]$commitSHA) + [string]$commitSHA, + [boolean]$enforceLatestCommit) try { # name and email are only used for merge commit, it doesn't really matter what we put in there. @@ -13,28 +14,39 @@ try { Write-Host "##vso[task.LogIssue type=warning;]The base branch for insertion validation is $sourceBranchName, which is not a vs-deps branch." } - Write-Host "Validating the PR head matches the specified commit SHA ($commitSHA)..." if ($commitSHA.Length -lt 7) { Write-Host "##vso[task.LogIssue type=error;]The PR Commit SHA must be at least 7 characters long." exit 1 } + + if ($enforceLatestCommit) { + Write-Host "Validating the PR head matches the specified commit SHA ($commitSHA)..." + Write-Host "Getting the hash of refs/pull/$prNumber/head..." + $remoteRef = git ls-remote origin refs/pull/$prNumber/head + Write-Host ($remoteRef | Out-String) - Write-Host "Getting the hash of refs/pull/$prNumber/head..." - $remoteRef = git ls-remote origin refs/pull/$prNumber/head - Write-Host ($remoteRef | Out-String) - - $prHeadSHA = $remoteRef.Split()[0] - if (!$prHeadSHA.StartsWith($commitSHA)) { - Write-Host "##vso[task.LogIssue type=error;]The PR's Head SHA ($prHeadSHA) does not begin with the specified commit SHA ($commitSHA). Unreviewed changes may have been pushed to the PR." - exit 1 + $prHeadSHA = $remoteRef.Split()[0] + if (!$prHeadSHA.StartsWith($commitSHA)) { + Write-Host "##vso[task.LogIssue type=error;]The PR's Head SHA ($prHeadSHA) does not begin with the specified commit SHA ($commitSHA). Unreviewed changes may have been pushed to the PR." + exit 1 + } } - Write-Host "Setting up the build for PR validation by merging refs/pull/$prNumber/merge into $sourceBranchName..." + Write-Host "Setting up the build for PR validation by pulling refs/pull/$prNumber/merge..." git pull origin refs/pull/$prNumber/merge if (!$?) { - Write-Host "##vso[task.LogIssue type=error;]Merging branch refs/pull/$prNumber/merge failed." + Write-Host "##vso[task.LogIssue type=error;]Pulling branch refs/pull/$prNumber/merge failed." exit 1 } + + if (!$enforceLatestCommit) { + Write-Host "Checking out the specified commit SHA ($commitSHA)..." + git checkout $commitSHA + if (!$?) { + Write-Host "##vso[task.LogIssue type=error;]Checking out commit SHA $commitSHA failed." + exit 1 + } + } } catch { Write-Host $_ diff --git a/eng/targets/Imports.targets b/eng/targets/Imports.targets index fdd6d2f8e4eaa..c646c49984d5d 100644 --- a/eng/targets/Imports.targets +++ b/eng/targets/Imports.targets @@ -4,7 +4,6 @@ - + + + + + + + + + + + + + + $(CollectUpToDateCheckInputDesignTimeDependsOn);AddUpToDateCheckVSIXSourceItems + + + + + + + + + + + + + \ No newline at end of file diff --git a/eng/targets/VisualStudio.targets b/eng/targets/VisualStudio.targets index 64e8116ca4adf..66e5c18c7bce1 100644 --- a/eng/targets/VisualStudio.targets +++ b/eng/targets/VisualStudio.targets @@ -147,6 +147,10 @@ + + + - - - + @@ -1121,7 +1117,8 @@ void Foo() { } --> - + + @@ -1165,11 +1162,11 @@ - + - + @@ -1177,11 +1174,11 @@ - + - + - + diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundTreeRewriter.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundTreeRewriter.cs index e55fc8af21250..bf47f1f5062bd 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundTreeRewriter.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundTreeRewriter.cs @@ -7,6 +7,7 @@ using Microsoft.CodeAnalysis.PooledObjects; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp { @@ -59,6 +60,142 @@ private ImmutableArray DoVisitList(ImmutableArray list) where T : Bound return list; } + + [return: NotNullIfNotNull(nameof(symbol))] + public virtual AliasSymbol? VisitAliasSymbol(AliasSymbol? symbol) => symbol; + + public virtual DiscardSymbol VisitDiscardSymbol(DiscardSymbol symbol) + { + Debug.Assert(symbol is not null); + return symbol; + } + + public virtual EventSymbol VisitEventSymbol(EventSymbol symbol) + { + Debug.Assert(symbol is not null); + return symbol; + } + + [return: NotNullIfNotNull(nameof(symbol))] + public virtual LabelSymbol? VisitLabelSymbol(LabelSymbol? symbol) => symbol; + + public virtual LocalSymbol VisitLocalSymbol(LocalSymbol symbol) + { + Debug.Assert(symbol is not null); + return symbol; + } + + public virtual NamespaceSymbol VisitNamespaceSymbol(NamespaceSymbol symbol) + { + Debug.Assert(symbol is not null); + return symbol; + } + + [return: NotNullIfNotNull(nameof(symbol))] + public virtual RangeVariableSymbol? VisitRangeVariableSymbol(RangeVariableSymbol? symbol) => symbol; + + [return: NotNullIfNotNull(nameof(symbol))] + public virtual FieldSymbol? VisitFieldSymbol(FieldSymbol? symbol) => symbol; + + public virtual ParameterSymbol VisitParameterSymbol(ParameterSymbol symbol) + { + Debug.Assert(symbol is not null); + return symbol; + } + + [return: NotNullIfNotNull(nameof(symbol))] + public virtual PropertySymbol? VisitPropertySymbol(PropertySymbol? symbol) => symbol; + + [return: NotNullIfNotNull(nameof(symbol))] + public virtual MethodSymbol? VisitMethodSymbol(MethodSymbol? symbol) => symbol; + + [return: NotNullIfNotNull(nameof(symbol))] + public Symbol? VisitSymbol(Symbol? symbol) + { + if (symbol is null) + { + return null; + } + + switch (symbol.Kind) + { + case SymbolKind.Alias: + return VisitAliasSymbol((AliasSymbol)symbol); + case SymbolKind.Discard: + return VisitDiscardSymbol((DiscardSymbol)symbol); + case SymbolKind.Event: + return VisitEventSymbol((EventSymbol)symbol); + case SymbolKind.Label: + return VisitLabelSymbol((LabelSymbol)symbol); + case SymbolKind.Local: + return VisitLocalSymbol((LocalSymbol)symbol); + case SymbolKind.Namespace: + return VisitNamespaceSymbol((NamespaceSymbol)symbol); + case SymbolKind.RangeVariable: + return VisitRangeVariableSymbol((RangeVariableSymbol)symbol); + case SymbolKind.Field: + return VisitFieldSymbol((FieldSymbol)symbol); + case SymbolKind.Parameter: + return VisitParameterSymbol((ParameterSymbol)symbol); + case SymbolKind.Property: + return VisitPropertySymbol((PropertySymbol)symbol); + case SymbolKind.Method: + return VisitMethodSymbol((MethodSymbol)symbol); + + default: + if (symbol is TypeSymbol type) + { + return VisitType(type); + } + + throw ExceptionUtilities.UnexpectedValue(symbol.Kind); + } + } + + [return: NotNullIfNotNull(nameof(symbol))] + protected FunctionTypeSymbol? VisitFunctionTypeSymbol(FunctionTypeSymbol? symbol) + { + return (FunctionTypeSymbol?)VisitType(symbol); + } + + public ImmutableArray VisitSymbols(ImmutableArray symbols) where T : Symbol? + { + if (symbols.IsDefault) + { + return symbols; + } + + ArrayBuilder? builder = null; + + for (int i = 0; i < symbols.Length; i++) + { + T symbol = symbols[i]; + + var newSymbol = (T?)VisitSymbol(symbol); + if (newSymbol != (object?)symbol) + { + Debug.Assert(newSymbol is not null); + + if (builder is null) + { + builder = ArrayBuilder.GetInstance(symbols.Length); + builder.AddRange(symbols, i); + } + + builder.Add(newSymbol); + } + else if (builder is not null) + { + builder.Add(symbol); + } + } + + return builder is null ? symbols : builder.ToImmutableAndFree(); + } + + protected virtual ImmutableArray VisitLocals(ImmutableArray locals) => locals; + + protected virtual ImmutableArray VisitDeclaredLocalFunctions(ImmutableArray localFunctions) => localFunctions; } internal abstract class BoundTreeRewriterWithStackGuard : BoundTreeRewriter @@ -112,7 +249,7 @@ protected BoundTreeRewriterWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperat if (child.Kind != BoundKind.BinaryOperator) { - return base.VisitBinaryOperator(node); + return node.Update(node.OperatorKind, VisitBinaryOperatorData(node), node.ResultKind, (BoundExpression)this.Visit(node.Left), (BoundExpression)this.Visit(node.Right), this.VisitType(node.Type)); } var stack = ArrayBuilder.GetInstance(); @@ -142,7 +279,7 @@ protected BoundTreeRewriterWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperat var right = (BoundExpression?)this.Visit(binary.Right); Debug.Assert(right is { }); var type = this.VisitType(binary.Type); - left = binary.Update(binary.OperatorKind, binary.Data, binary.ResultKind, left, right, type); + left = binary.Update(binary.OperatorKind, VisitBinaryOperatorData(binary), binary.ResultKind, left, right, type); } while (stack.Count > 0); @@ -152,6 +289,11 @@ protected BoundTreeRewriterWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperat return left; } + protected virtual BoundBinaryOperator.UncommonData? VisitBinaryOperatorData(BoundBinaryOperator node) + { + return node.Data; + } + public sealed override BoundNode? VisitIfStatement(BoundIfStatement node) { if (node.AlternativeOpt is not BoundIfStatement ifStatement) diff --git a/src/Compilers/CSharp/Portable/BoundTree/Constructors.cs b/src/Compilers/CSharp/Portable/BoundTree/Constructors.cs index 259af1aa8fdf1..3aa692af65ad8 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/Constructors.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/Constructors.cs @@ -336,7 +336,6 @@ public static BoundConversion SynthesizedNonUserDefined(SyntaxNode syntax, Bound explicitCastInCode: false, conversionGroupOpt: null, constantValueOpt: constantValueOpt, - originalUserDefinedConversionsOpt: default, type: type) { WasCompilerGenerated = true }; } @@ -391,35 +390,9 @@ public BoundConversion( explicitCastInCode: explicitCastInCode, constantValueOpt: constantValueOpt, conversionGroupOpt, - conversion.OriginalUserDefinedConversions, type: type, hasErrors: hasErrors || !conversion.IsValid) { } - - public BoundConversion( - SyntaxNode syntax, - BoundExpression operand, - Conversion conversion, - bool isBaseConversion, - bool @checked, - bool explicitCastInCode, - ConstantValue? constantValueOpt, - ConversionGroup? conversionGroupOpt, - TypeSymbol type, - bool hasErrors = false) : - this(syntax, operand, conversion, isBaseConversion, @checked, explicitCastInCode, constantValueOpt, conversionGroupOpt, originalUserDefinedConversionsOpt: default, type, hasErrors) - { - } - - public BoundConversion Update(BoundExpression operand, - Conversion conversion, - bool isBaseConversion, - bool @checked, - bool explicitCastInCode, - ConstantValue? constantValueOpt, - ConversionGroup? conversionGroupOpt, - TypeSymbol type) - => Update(operand, conversion, isBaseConversion, @checked, explicitCastInCode, constantValueOpt, conversionGroupOpt, this.OriginalUserDefinedConversionsOpt, type); } internal sealed partial class BoundBinaryOperator @@ -512,17 +485,6 @@ public BoundUserDefinedConditionalLogicalOperator( { Debug.Assert(operatorKind.IsUserDefined() && operatorKind.IsLogical()); } - - public BoundUserDefinedConditionalLogicalOperator Update(BinaryOperatorKind operatorKind, - MethodSymbol logicalOperator, - MethodSymbol trueOperator, - MethodSymbol falseOperator, - TypeSymbol? constrainedToTypeOpt, - LookupResultKind resultKind, - BoundExpression left, - BoundExpression right, - TypeSymbol type) - => Update(operatorKind, logicalOperator, trueOperator, falseOperator, constrainedToTypeOpt, resultKind, this.OriginalUserDefinedOperatorsOpt, left, right, type); } internal sealed partial class BoundParameter @@ -653,7 +615,7 @@ public BoundGotoStatement(SyntaxNode syntax, LabelSymbol label, bool hasErrors = internal partial class BoundBlock { public BoundBlock(SyntaxNode syntax, ImmutableArray locals, ImmutableArray statements, bool hasErrors = false) - : this(syntax, locals, ImmutableArray.Empty, hasUnsafeModifier: false, instrumentation: null, statements, hasErrors) + : this(syntax, locals, ImmutableArray.Empty, hasUnsafeModifier: false, instrumentation: null, statements, hasErrors) { } diff --git a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs index 27d00fddb1c63..b1fba6ed796dc 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs @@ -819,7 +819,7 @@ private BoundLambda ReallyBind(NamedTypeSymbol delegateType, bool inExpressionTr refKind == CodeAnalysis.RefKind.None && _returnInferenceCache!.TryGetValue(cacheKey, out BoundLambda? returnInferenceLambda) && GetLambdaExpressionBody(returnInferenceLambda.Body) is BoundExpression expression && - (lambdaSymbol = returnInferenceLambda.Symbol).RefKind == refKind && + (lambdaSymbol = (LambdaSymbol)returnInferenceLambda.Symbol).RefKind == refKind && (object)LambdaSymbol.InferenceFailureReturnType != lambdaSymbol.ReturnType && lambdaSymbol.ReturnTypeWithAnnotations.Equals(returnType, TypeCompareKind.ConsiderEverything)) { @@ -1273,7 +1273,7 @@ private BoundLambda ReallyBindForErrorRecovery( // If multiple candidates have the same number of diagnostics, order them by delegate type name. // It's not great, but it should be stable. return minDiagnosticsGroup - .OrderBy(lambda => GetLambdaSortString(lambda.Value.Symbol)) + .OrderBy(lambda => GetLambdaSortString((LambdaSymbol)lambda.Value.Symbol)) .FirstOrDefault() .Value; } diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 8bc7ad5c62869..9bb756590897b 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -1171,7 +1171,7 @@ Cannot implicitly convert type '{0}' to '{1}'. An explicit conversion exists (are you missing a cast?) - The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. + The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. Imported type '{0}' is invalid. It contains a circular base type dependency. @@ -2543,7 +2543,7 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep Extension methods must be defined in a top level static class; {0} is a nested class - Cannot define a new extension method because the compiler required type '{0}' cannot be found. Are you missing a reference to System.Core.dll? + Cannot define a new extension because the compiler required type '{0}' cannot be found. Are you missing a reference to System.Core.dll? Do not use 'System.Runtime.CompilerServices.ExtensionAttribute'. Use the 'this' keyword instead. @@ -2600,7 +2600,7 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep Invalid preprocessor expression - Invalid token '{0}' in class, record, struct, or interface member declaration + Invalid token '{0}' in a member declaration Method must have a return type @@ -6900,10 +6900,10 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ The loaded assembly references .NET Framework, which is not supported. - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - The analyzer assembly references a newer version of the compiler than the currently running version. + Analyzer assembly cannot be used because it references a newer version of the compiler than the currently running version. The type '{0}' may not be used for a field of a record. @@ -7483,7 +7483,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ file types - Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specifc numeric type. + Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specific numeric type. array access @@ -7983,14 +7983,14 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Property accessor '{0}' must be '{1}' to match the definition part - - Both partial property declarations must have the same type. + + Both partial member declarations must have the same type. - - Partial property declarations '{0}' and '{1}' have signature differences. + + Partial member declarations '{0}' and '{1}' have signature differences. - - Partial property declarations have signature differences. + + Partial member declarations have signature differences. Both partial property declarations must be required or neither may be required @@ -8014,11 +8014,11 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Attribute 'System.Runtime.CompilerServices.InlineArray' cannot be applied to a record struct. - Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or safely handling the case where 'field' is null in the 'get' accessor. Similar diagnostic message as 'WRN_UninitializedNonNullableField' - Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. first-class Span types @@ -8047,6 +8047,81 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + Cannot emit this string literal into the data section because it has XXHash128 collision with another string literal: {0} + + + partial events and constructors + + + Partial member '{0}' must have an implementation part. + + + Partial member '{0}' must have a definition part. + + + Partial member '{0}' may not have multiple defining declarations. + + + Partial member '{0}' may not have multiple implementing declarations. + + + '{0}': partial event cannot have initializer + + + '{0}': only the implementing declaration of a partial constructor can have an initializer + + + extensions + + + Extension declarations may not have a name. + + + Extension declarations can include only methods or properties + + + Extensions must be declared in a top-level, non-generic, static class + + + The receiver parameter of an extension cannot have a default value + + + An extension container can have only one receiver parameter + + + '{0}' does not contain a definition for '{1}' and no accessible extension member '{1}' for receiver of type '{0}' could be found (are you missing a using directive or an assembly reference?) + + + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + + + Type parameter '{0}' has the same name as an extension container type parameter + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + + + 'value': an automatically-generated parameter name conflicts with an extension parameter name + + + Type parameter '{0}' has the same name as an extension parameter + + + Cannot use extension parameter '{0}' in this context. + + + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + + + The extended type '{0}' must reference all the type parameters declared by the extension, but type parameter '{1}' is not referenced. + + + An expression tree may not contain an extension property access + user-defined compound assignment operators diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs index 26f9586b15fc1..0b8cfbc2f54b7 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs @@ -596,7 +596,7 @@ private void EmitLoweredConditionalAccessExpression(BoundLoweredConditionalAcces /// /// We must use a temp when there is a chance that evaluation of the call arguments - /// could actually modify value of the reference type reciever. The call must use + /// could actually modify value of the reference type receiver. The call must use /// the original (unmodified) receiver. /// private sealed class IsConditionalConstrainedCallThatMustUseTempForReferenceTypeReceiverWalker : BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator @@ -3588,7 +3588,7 @@ private void EmitParameterIdExpression(BoundParameterId node) if (node.HoistedField is null) { - _builder.EmitIntConstant(node.Parameter.Ordinal); + _builder.EmitIntConstant(node.Parameter.Ordinal); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Follow up } else { diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index d5fee9089cef0..e23c3b07ded64 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs @@ -3503,6 +3503,29 @@ internal override bool CompileMethods( } SynthesizedMetadataCompiler.ProcessSynthesizedMembers(this, moduleBeingBuilt, cancellationToken); + + if (moduleBeingBuilt.OutputKind.IsApplication()) + { + var entryPointDiagnostics = BindingDiagnosticBag.GetInstance(withDiagnostics: true, withDependencies: false); + var entryPoint = MethodCompiler.GetEntryPoint( + this, + moduleBeingBuilt, + hasDeclarationErrors: false, + emitMethodBodies: false, + entryPointDiagnostics, + cancellationToken); + diagnostics.AddRange(entryPointDiagnostics.DiagnosticBag!); + bool shouldSetEntryPoint = entryPoint != null && !entryPointDiagnostics.HasAnyErrors(); + entryPointDiagnostics.Free(); + if (shouldSetEntryPoint) + { + moduleBeingBuilt.SetPEEntryPoint(entryPoint, diagnostics); + } + else + { + return false; + } + } } else { diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs index 33c4e8adad8b9..4aa31399de20c 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs @@ -1399,7 +1399,7 @@ private void CheckModelAndSyntaxNodeToSpeculate(CSharpSyntaxNode syntax) /// scope around position is used. /// The name of the symbol to find. If null is specified then symbols /// with any names are returned. - /// Consider (reduced) extension methods. + /// Consider extension members. Classic extension methods will be returned in reduced form. /// A list of symbols that were found. If no symbols were found, an empty list is returned. /// /// The "position" is used to determine what variables are visible and accessible. Even if "container" is @@ -1408,15 +1408,15 @@ private void CheckModelAndSyntaxNodeToSpeculate(CSharpSyntaxNode syntax) /// /// Labels are not considered (see ). /// - /// Non-reduced extension methods are considered regardless of the value of . + /// Non-reduced extension methods are considered regardless of the value of . /// public ImmutableArray LookupSymbols( int position, NamespaceOrTypeSymbol container = null, string name = null, - bool includeReducedExtensionMethods = false) + bool includeExtensions = false) { - var options = includeReducedExtensionMethods ? LookupOptions.IncludeExtensionMethods : LookupOptions.Default; + var options = includeExtensions ? LookupOptions.IncludeExtensionMembers : LookupOptions.Default; return LookupSymbolsInternal(position, container, name, options, useBaseReferenceAccessibility: false); } @@ -1576,7 +1576,7 @@ private ImmutableArray LookupSymbolsInternal( if ((object)container == null || container.Kind == SymbolKind.Namespace) { - options &= ~LookupOptions.IncludeExtensionMethods; + options &= ~LookupOptions.IncludeExtensionMembers; } var binder = GetEnclosingBinder(position); @@ -1652,25 +1652,33 @@ private ImmutableArray LookupSymbolsInternal( info.Free(); - if ((options & LookupOptions.IncludeExtensionMethods) != 0) + if ((options & LookupOptions.IncludeExtensionMembers) != 0 && container is TypeSymbol receiverType) { var lookupResult = LookupResult.GetInstance(); options |= LookupOptions.AllMethodsOnArityZero; options &= ~LookupOptions.MustBeInstance; - var discardedUseSiteInfo = CompoundUseSiteInfo.Discarded; - binder.LookupExtensionMethods(lookupResult, name, 0, options, ref discardedUseSiteInfo); + binder.LookupAllExtensions(lookupResult, name, options); if (lookupResult.IsMultiViable) { - TypeSymbol containingType = (TypeSymbol)container; - foreach (MethodSymbol extensionMethod in lookupResult.Symbols) + foreach (Symbol symbol in lookupResult.Symbols) { - var reduced = extensionMethod.ReduceExtensionMethod(containingType, Compilation); - if ((object)reduced != null) + if (symbol is MethodSymbol { IsExtensionMethod: true } extensionMethod) + { + if (extensionMethod.ReduceExtensionMethod(receiverType, Compilation) is { } reduced) + { + results.Add(reduced.GetPublicSymbol()); + } + } + else { - results.Add(reduced.GetPublicSymbol()); + Debug.Assert(symbol.GetIsNewExtensionMember()); + if (SourceNamedTypeSymbol.GetCompatibleSubstitutedMember(binder.Compilation, symbol, receiverType) is { } compatibleSubstitutedMember) + { + results.Add(compatibleSubstitutedMember.GetPublicSymbol()); + } } } } @@ -1679,7 +1687,7 @@ private ImmutableArray LookupSymbolsInternal( } if (name == null) - results.RemoveWhere(static (symbol, _, _) => !symbol.CanBeReferencedByName, arg: default(VoidResult)); + results.RemoveWhere(static (symbol, _, _) => !symbol.CanBeReferencedByName, arg: 0); return results.ToImmutableAndFree(); } @@ -1739,7 +1747,7 @@ private void AppendSymbolsWithNameAndArity( name, arity, basesBeingResolved: null, - options: options & ~LookupOptions.IncludeExtensionMethods, + options: options & ~LookupOptions.IncludeExtensionMembers, diagnose: false, useSiteInfo: ref discardedUseSiteInfo); @@ -3361,6 +3369,7 @@ private OneOrMany GetSemanticSymbols( case BoundKind.PropertyGroup: symbols = GetPropertyGroupSemanticSymbols((BoundPropertyGroup)boundNode, boundNodeForSyntacticParent, binderOpt, out resultKind, out memberGroup); break; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : handle BoundPropertyAccess (which now may have a member group) case BoundKind.BadExpression: { @@ -3446,7 +3455,7 @@ private OneOrMany GetSemanticSymbols( } else { - symbols = StaticCast.From(CreateReducedExtensionMethodsFromOriginalsIfNecessary(call, Compilation)); + symbols = CreateReducedAndFilteredSymbolsFromOriginals(call, Compilation); resultKind = call.ResultKind; } } @@ -3470,7 +3479,7 @@ private OneOrMany GetSemanticSymbols( // group result in the call below. symbols = GetMethodGroupSemanticSymbols( ((BoundUnconvertedAddressOfOperator)boundNode).Operand, - boundNodeForSyntacticParent, binderOpt, out resultKind, out isDynamic, methodGroup: out _); + boundNodeForSyntacticParent, binderOpt, out resultKind, out isDynamic, memberGroup: out _); break; } @@ -3534,7 +3543,7 @@ boundNode.ExpressionSymbol is Symbol accessSymbol && } else if (conversion.ConversionKind.IsUserDefinedConversion()) { - GetSymbolsAndResultKind(conversion, conversion.SymbolOpt, conversion.OriginalUserDefinedConversionsOpt, out symbols, out resultKind); + GetSymbolsAndResultKind(conversion, conversion.SymbolOpt, conversion.Conversion.OriginalUserDefinedConversions, out symbols, out resultKind); } else { @@ -4235,7 +4244,7 @@ private OneOrMany GetMethodGroupSemanticSymbols( Binder binderOpt, out LookupResultKind resultKind, out bool isDynamic, - out ImmutableArray methodGroup) + out ImmutableArray memberGroup) { Debug.Assert(binderOpt != null || IsInTree(boundNode.Syntax)); @@ -4251,7 +4260,7 @@ private OneOrMany GetMethodGroupSemanticSymbols( // The method group needs filtering. Binder binder = binderOpt ?? GetEnclosingBinder(GetAdjustedNodePosition(boundNode.Syntax)); - methodGroup = GetReducedAndFilteredMethodGroupSymbols(binder, boundNode).Cast(); + memberGroup = GetReducedAndFilteredMethodGroupSymbols(binder, boundNode); // We want to get the actual node chosen by overload resolution, if possible. if (boundNodeForSyntacticParent != null) @@ -4274,7 +4283,7 @@ private OneOrMany GetMethodGroupSemanticSymbols( else { resultKind = call.ResultKind.WorseResultKind(LookupResultKind.OverloadResolutionFailure); - symbols = StaticCast.From(CreateReducedExtensionMethodsFromOriginalsIfNecessary(call, Compilation)); + symbols = CreateReducedAndFilteredSymbolsFromOriginals(call, Compilation); } } break; @@ -4329,7 +4338,7 @@ private OneOrMany GetMethodGroupSemanticSymbols( case BoundKind.BadExpression: // If the bad expression has symbol(s) from this method group, it better indicates any problems. - ImmutableArray myMethodGroup = methodGroup; + ImmutableArray myMethodGroup = memberGroup; symbols = OneOrMany.Create(((BoundBadExpression)boundNodeForSyntacticParent).Symbols.WhereAsArray((sym, myMethodGroup) => myMethodGroup.Contains(sym), myMethodGroup)); if (symbols.Any()) @@ -4339,12 +4348,12 @@ private OneOrMany GetMethodGroupSemanticSymbols( break; case BoundKind.NameOfOperator: - symbols = OneOrMany.Create(methodGroup); + symbols = OneOrMany.Create(memberGroup); resultKind = resultKind.WorseResultKind(LookupResultKind.MemberGroup); break; default: - symbols = OneOrMany.Create(methodGroup); + symbols = OneOrMany.Create(memberGroup); if (symbols.Count > 0) { resultKind = resultKind.WorseResultKind(LookupResultKind.OverloadResolutionFailure); @@ -4352,14 +4361,14 @@ private OneOrMany GetMethodGroupSemanticSymbols( break; } } - else if (methodGroup.Length == 1 && !boundNode.HasAnyErrors) + else if (memberGroup.Length == 1 && !boundNode.HasAnyErrors) { // During speculative binding, there won't be a parent bound node. The parent bound // node may also be absent if the syntactic parent has errors or if one is simply // not specified (see SemanticModel.GetSymbolInfoForNode). However, if there's exactly // one candidate, then we should probably succeed. - symbols = OneOrMany.Create(methodGroup); + symbols = OneOrMany.Create(memberGroup); if (symbols.Count > 0) { resultKind = resultKind.WorseResultKind(LookupResultKind.OverloadResolutionFailure); @@ -4371,7 +4380,7 @@ private OneOrMany GetMethodGroupSemanticSymbols( // If we didn't find a better set of symbols, then assume this is a method group that didn't // get resolved. Return all members of the method group, with a resultKind of OverloadResolutionFailure // (unless the method group already has a worse result kind). - symbols = OneOrMany.Create(methodGroup); + symbols = OneOrMany.Create(memberGroup); if (!isDynamic && resultKind > LookupResultKind.OverloadResolutionFailure) { resultKind = LookupResultKind.OverloadResolutionFailure; @@ -4558,10 +4567,10 @@ private static ParameterSymbol FindNamedParameter(ImmutableArray GetReducedAndFilteredMethodGroupSymbols(Binder binder, BoundMethodGroup node) + internal static ImmutableArray GetReducedAndFilteredMethodGroupSymbols(Binder binder, BoundMethodGroup node) { - var methods = ArrayBuilder.GetInstance(); - var filteredMethods = ArrayBuilder.GetInstance(); + var members = ArrayBuilder.GetInstance(); + var filteredMembers = ArrayBuilder.GetInstance(); var resultKind = LookupResultKind.Empty; var typeArguments = node.TypeArgumentsOpt; @@ -4576,12 +4585,12 @@ internal static ImmutableArray GetReducedAndFilteredMethodGroupSym foreach (var method in nonHiddenMethods) { - MergeReducedAndFilteredMethodGroupSymbol( - methods, - filteredMethods, + MergeReducedAndFilteredSymbol( + members, + filteredMembers, new SingleLookupResult(node.ResultKind, method, node.LookupError), typeArguments, - null, + receiverType: null, ref resultKind, binder.Compilation); } @@ -4591,12 +4600,12 @@ internal static ImmutableArray GetReducedAndFilteredMethodGroupSym var otherSymbol = node.LookupSymbolOpt; if (((object)otherSymbol != null) && (otherSymbol.Kind == SymbolKind.Method)) { - MergeReducedAndFilteredMethodGroupSymbol( - methods, - filteredMethods, + MergeReducedAndFilteredSymbol( + members, + filteredMembers, new SingleLookupResult(node.ResultKind, otherSymbol, node.LookupError), typeArguments, - null, + receiverType: null, ref resultKind, binder.Compilation); } @@ -4605,8 +4614,8 @@ internal static ImmutableArray GetReducedAndFilteredMethodGroupSym var receiver = node.ReceiverOpt; var name = node.Name; - // Extension methods, all scopes. - if (node.SearchExtensionMethods) + // Extension members, all scopes. + if (node.SearchExtensions && receiver.Type is { } receiverType) { Debug.Assert(receiver != null); int arity; @@ -4623,84 +4632,78 @@ internal static ImmutableArray GetReducedAndFilteredMethodGroupSym } binder = binder.WithAdditionalFlags(BinderFlags.SemanticModel); - foreach (var scope in new ExtensionMethodScopes(binder)) + var discardedUseSiteInfo = CompoundUseSiteInfo.Discarded; + + var singleLookupResults = ArrayBuilder.GetInstance(); + foreach (var scope in new ExtensionScopes(binder)) { - var extensionMethods = ArrayBuilder.GetInstance(); - var otherBinder = scope.Binder; - otherBinder.GetCandidateExtensionMethods(extensionMethods, - name, - arity, - options, - originalBinder: binder); - - foreach (var method in extensionMethods) + singleLookupResults.Clear(); + scope.Binder.EnumerateAllExtensionMembersInSingleBinder(singleLookupResults, name, arity, options, originalBinder: binder, useSiteInfo: ref discardedUseSiteInfo, classicExtensionUseSiteInfo: ref discardedUseSiteInfo); + + foreach (SingleLookupResult singleLookupResult in singleLookupResults) { - var discardedUseSiteInfo = CompoundUseSiteInfo.Discarded; - MergeReducedAndFilteredMethodGroupSymbol( - methods, - filteredMethods, - binder.CheckViability(method, arity, options, accessThroughType: null, diagnose: false, useSiteInfo: ref discardedUseSiteInfo), + if (singleLookupResult.Symbol is not (MethodSymbol or PropertySymbol)) + { + continue; + } + + MergeReducedAndFilteredSymbol( + members, + filteredMembers, + singleLookupResult, typeArguments, - receiver.Type, + receiverType, ref resultKind, binder.Compilation); } - - extensionMethods.Free(); } + + singleLookupResults.Free(); } - methods.Free(); - return filteredMethods.ToImmutableAndFree(); + members.Free(); + return filteredMembers.ToImmutableAndFree(); } - // Reduce extension methods to their reduced form, and remove: +#nullable enable + // Reduce classic extension methods to their reduced form, and remove: // a) Extension methods are aren't applicable to receiverType // including constraint checking. // b) Duplicate methods // c) Methods that are hidden or overridden by another method in the group. - private static bool AddReducedAndFilteredMethodGroupSymbol( - ArrayBuilder methods, - ArrayBuilder filteredMethods, - MethodSymbol method, + // For new extension members, infer type arguments for the extension declaration based on the receiver type, + // perform the substitution, and remove: + // a) Members that would break constraints + // b) Members that are not applicable to the receiver type. + private static bool AddReducedAndFilteredSymbol( + ArrayBuilder members, + ArrayBuilder filteredMembers, + Symbol member, ImmutableArray typeArguments, TypeSymbol receiverType, CSharpCompilation compilation) { - MethodSymbol constructedMethod; - if (!typeArguments.IsDefaultOrEmpty && method.Arity == typeArguments.Length) + Symbol? substitutedMember = member.GetReducedAndFilteredSymbol(typeArguments, receiverType, compilation, checkFullyInferred: false); + if (substitutedMember is null) { - constructedMethod = method.Construct(typeArguments); - Debug.Assert((object)constructedMethod != null); - } - else - { - constructedMethod = method; - } - - if ((object)receiverType != null) - { - constructedMethod = constructedMethod.ReduceExtensionMethod(receiverType, compilation); - if ((object)constructedMethod == null) - { - return false; - } + return false; } // Don't add exact duplicates. - if (filteredMethods.Contains(constructedMethod)) + if (filteredMembers.Contains(substitutedMember)) { return false; } - methods.Add(method); - filteredMethods.Add(constructedMethod); + members.Add(member); + filteredMembers.Add(substitutedMember); return true; } +#nullable disable - private static void MergeReducedAndFilteredMethodGroupSymbol( - ArrayBuilder methods, - ArrayBuilder filteredMethods, + private static void MergeReducedAndFilteredSymbol( + ArrayBuilder members, + ArrayBuilder filteredMembers, SingleLookupResult singleResult, ImmutableArray typeArguments, TypeSymbol receiverType, @@ -4712,65 +4715,63 @@ private static void MergeReducedAndFilteredMethodGroupSymbol( return; } - Debug.Assert(singleResult.Symbol.Kind == SymbolKind.Method); + Symbol member = singleResult.Symbol; - var singleKind = singleResult.Kind; + LookupResultKind singleKind = singleResult.Kind; if (resultKind > singleKind) { return; } else if (resultKind < singleKind) { - methods.Clear(); - filteredMethods.Clear(); + members.Clear(); + filteredMembers.Clear(); resultKind = LookupResultKind.Empty; } - var method = (MethodSymbol)singleResult.Symbol; - if (AddReducedAndFilteredMethodGroupSymbol(methods, filteredMethods, method, typeArguments, receiverType, compilation)) + if (AddReducedAndFilteredSymbol(members, filteredMembers, member, typeArguments, receiverType, compilation)) { - Debug.Assert(methods.Count > 0); + Debug.Assert(members.Count > 0); if (resultKind < singleKind) { resultKind = singleKind; } } - Debug.Assert((methods.Count == 0) == (resultKind == LookupResultKind.Empty)); - Debug.Assert(methods.Count == filteredMethods.Count); + Debug.Assert((members.Count == 0) == (resultKind == LookupResultKind.Empty)); + Debug.Assert(members.Count == filteredMembers.Count); } /// - /// If the call represents an extension method invocation with an explicit receiver, return the original + /// If the call represents a classic extension method invocation with an explicit receiver, return the original /// methods as ReducedExtensionMethodSymbols. Otherwise, return the original methods unchanged. /// - private static OneOrMany CreateReducedExtensionMethodsFromOriginalsIfNecessary(BoundCall call, CSharpCompilation compilation) + private static OneOrMany CreateReducedAndFilteredSymbolsFromOriginals(BoundCall call, CSharpCompilation compilation) { var methods = call.OriginalMethodsOpt; - TypeSymbol extensionThisType = null; + TypeSymbol receiverType = null; Debug.Assert(!methods.IsDefault); + // Note: A call including new extension members may be marked as InvokedAsExtensionMethod in error scenarios if (call.InvokedAsExtensionMethod) { - // If the call was invoked as an extension method, the receiver - // should be non-null and all methods should be extension methods. if (call.ReceiverOpt != null) { - extensionThisType = call.ReceiverOpt.Type; + receiverType = call.ReceiverOpt.Type; } else { - extensionThisType = call.Arguments[0].Type; + receiverType = call.Arguments[0].Type; } - Debug.Assert((object)extensionThisType != null); + Debug.Assert((object)receiverType != null); } - var methodBuilder = ArrayBuilder.GetInstance(); - var filteredMethodBuilder = ArrayBuilder.GetInstance(); + var methodBuilder = ArrayBuilder.GetInstance(); + var filteredMethodBuilder = ArrayBuilder.GetInstance(); foreach (var method in FilterOverriddenOrHiddenMethods(methods)) { - AddReducedAndFilteredMethodGroupSymbol(methodBuilder, filteredMethodBuilder, method, default(ImmutableArray), extensionThisType, compilation); + AddReducedAndFilteredSymbol(methodBuilder, filteredMethodBuilder, method, typeArguments: default, receiverType, compilation); } methodBuilder.Free(); return filteredMethodBuilder.ToOneOrManyAndFree(); diff --git a/src/Compilers/CSharp/Portable/Compilation/MethodBodySemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/MethodBodySemanticModel.cs index 04d209c27c4be..65979e5f2a402 100644 --- a/src/Compilers/CSharp/Portable/Compilation/MethodBodySemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/MethodBodySemanticModel.cs @@ -98,6 +98,7 @@ internal override BoundNode Bind(Binder binder, CSharpSyntaxNode node, BindingDi case SyntaxKind.CompilationUnit: case SyntaxKind.RecordDeclaration: case SyntaxKind.ClassDeclaration: + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : likely needs work for semantic model return binder.BindMethodBody(node, diagnostics); } diff --git a/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs index 10b7050bbd0b3..412116cbb00d3 100644 --- a/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs @@ -801,6 +801,7 @@ private MemberSemanticModel GetMemberModel(int position) break; case SyntaxKind.ClassDeclaration: case SyntaxKind.RecordDeclaration: + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : likely needs work for semantic model { var typeDecl = (TypeDeclarationSyntax)memberDecl; @@ -871,6 +872,7 @@ internal override MemberSemanticModel GetMemberModel(SyntaxNode node) case SyntaxKind.ClassDeclaration: case SyntaxKind.RecordDeclaration: + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : likely needs work for semantic model { var typeDecl = (TypeDeclarationSyntax)memberDecl; return typeDecl.ParameterList is object && @@ -1089,6 +1091,7 @@ private MemberSemanticModel CreateMemberModel(CSharpSyntaxNode node) case SyntaxKind.ClassDeclaration: case SyntaxKind.RecordDeclaration: + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : likely needs work for semantic model { SynthesizedPrimaryConstructor symbol = TryGetSynthesizedPrimaryConstructor((TypeDeclarationSyntax)node); @@ -1378,10 +1381,37 @@ private NamedTypeSymbol GetDeclaredType(BaseTypeDeclarationSyntax declarationSyn { Debug.Assert(declarationSyntax != null); + if (declarationSyntax is ExtensionDeclarationSyntax extensionDeclaration) + { + return GetDeclaredExtension(extensionDeclaration); + } + var name = declarationSyntax.Identifier.ValueText; return GetDeclaredNamedType(declarationSyntax, name); } + private NamedTypeSymbol GetDeclaredExtension(ExtensionDeclarationSyntax extensionDeclaration) + { + Debug.Assert(extensionDeclaration != null); + + var container = GetDeclaredTypeMemberContainer(extensionDeclaration); + Debug.Assert(container is not null); + + // look for any extension declaration with same declaration location + var collection = container.GetMembersUnordered(); + var declarationSpan = extensionDeclaration.Span; + foreach (var symbol in collection) + { + if (symbol is TypeSymbol { IsExtension: true } && symbol.HasLocationContainedWithin(this.SyntaxTree, declarationSpan, out var wasZeroWidthMatch)) + { + if (!wasZeroWidthMatch) + return (NamedTypeSymbol)symbol; + } + } + + return null; + } + private NamedTypeSymbol GetDeclaredType(DelegateDeclarationSyntax declarationSyntax) { Debug.Assert(declarationSyntax != null); @@ -1800,13 +1830,7 @@ private Symbol GetDeclaredMember(NamespaceOrTypeSymbol container, TextSpan decla } // Handle the case of the implementation of a partial member. - Symbol partial = symbol switch - { - MethodSymbol method => method.PartialImplementationPart, - SourcePropertySymbol property => property.PartialImplementationPart, - _ => null - }; - + Symbol partial = symbol.GetPartialImplementationPart(); if ((object)partial != null) { var loc = partial.GetFirstLocation(); @@ -2003,6 +2027,37 @@ public override IAliasSymbol GetDeclaredSymbol( return builder.ToImmutableAndFree(); } + private ParameterSymbol GetExtensionParameterSymbol( + ParameterSyntax parameter, + CancellationToken cancellationToken) + { + Debug.Assert(parameter != null); + + if (parameter.Parent is not ParameterListSyntax { Parent: ExtensionDeclarationSyntax extensionDecl }) + { + return null; + } + + INamedTypeSymbol extension = GetDeclaredSymbol(extensionDecl, cancellationToken); + if (extension is null) + { + return null; + } + + IParameterSymbol extensionParameter = extension.ExtensionParameter; + foreach (var location in extensionParameter.Locations) + { + cancellationToken.ThrowIfCancellationRequested(); + + if (location.SourceTree == this.SyntaxTree && parameter.Span.Contains(location.SourceSpan)) + { + return extensionParameter.GetSymbol(); + } + } + + return null; + } + private ParameterSymbol GetMethodParameterSymbol( ParameterSyntax parameter, CancellationToken cancellationToken) @@ -2125,7 +2180,8 @@ private ParameterSymbol GetDelegateParameterSymbol( return GetMethodParameterSymbol(declarationSyntax, cancellationToken) ?? GetIndexerParameterSymbol(declarationSyntax, cancellationToken) ?? - GetDelegateParameterSymbol(declarationSyntax, cancellationToken); + GetDelegateParameterSymbol(declarationSyntax, cancellationToken) ?? + GetExtensionParameterSymbol(declarationSyntax, cancellationToken); } /// diff --git a/src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.cs index edd5c97d36375..ec6661e4541b2 100644 --- a/src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.cs @@ -258,13 +258,7 @@ public override void DefaultVisit(Symbol symbol) bool shouldSkipPartialDefinitionComments = false; if (symbol.IsPartialDefinition()) { - Symbol? implementationPart = symbol switch - { - MethodSymbol method => method.PartialImplementationPart, - SourcePropertySymbol property => property.PartialImplementationPart, - _ => null - }; - + Symbol? implementationPart = symbol.GetPartialImplementationPart(); if (implementationPart is not null) { Visit(implementationPart); diff --git a/src/Compilers/CSharp/Portable/Compiler/MethodBodySynthesizer.Lowered.cs b/src/Compilers/CSharp/Portable/Compiler/MethodBodySynthesizer.Lowered.cs index 8c793b4eb6f45..7a4d807a82fcc 100644 --- a/src/Compilers/CSharp/Portable/Compiler/MethodBodySynthesizer.Lowered.cs +++ b/src/Compilers/CSharp/Portable/Compiler/MethodBodySynthesizer.Lowered.cs @@ -259,7 +259,7 @@ internal override void GenerateMethodBody(TypeCompilationState compilationState, } } - internal sealed partial class SynthesizedSealedPropertyAccessor : SynthesizedInstanceMethodSymbol + internal sealed partial class SynthesizedSealedPropertyAccessor : SynthesizedMethodSymbol { internal override bool SynthesizesLoweredBoundBody { @@ -296,7 +296,7 @@ internal override void GenerateMethodBody(TypeCompilationState compilationState, internal abstract partial class MethodToClassRewriter { - private sealed partial class BaseMethodWrapperSymbol : SynthesizedMethodBaseSymbol + internal sealed partial class BaseMethodWrapperSymbol : SynthesizedMethodBaseSymbol { internal sealed override bool GenerateDebugInfo { diff --git a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs index 632a09ab48501..0036b26480517 100644 --- a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs @@ -218,7 +218,7 @@ public static void CompileMethodBodies( // Returns the MethodSymbol for the assembly entrypoint. If the user has a Task returning main, // this function returns the synthesized Main MethodSymbol. - private static MethodSymbol GetEntryPoint(CSharpCompilation compilation, PEModuleBuilder moduleBeingBuilt, bool hasDeclarationErrors, bool emitMethodBodies, BindingDiagnosticBag diagnostics, CancellationToken cancellationToken) + internal static MethodSymbol GetEntryPoint(CSharpCompilation compilation, PEModuleBuilder moduleBeingBuilt, bool hasDeclarationErrors, bool emitMethodBodies, BindingDiagnosticBag diagnostics, CancellationToken cancellationToken) { Debug.Assert(diagnostics.DiagnosticBag != null); @@ -252,6 +252,7 @@ private static MethodSymbol GetEntryPoint(CSharpCompilation compilation, PEModul if (((object)synthesizedEntryPoint != null) && (moduleBeingBuilt != null) && !hasDeclarationErrors && + !moduleBeingBuilt.EmitOptions.EmitMetadataOnly && !diagnostics.HasAnyErrors()) { BoundStatement body = synthesizedEntryPoint.CreateBody(diagnostics); @@ -270,6 +271,7 @@ private static MethodSymbol GetEntryPoint(CSharpCompilation compilation, PEModul var loweredBody = LowerBodyOrInitializer( synthesizedEntryPoint, + extensionImplementationMethod: null, methodOrdinal, body, previousSubmissionFields: null, @@ -534,7 +536,17 @@ private void CompileNamedType(NamedTypeSymbol containingType) method.MethodKind == MethodKind.StaticConstructor ? processedStaticInitializers : default(Binder.ProcessedFieldInitializers); - CompileMethod(method, memberOrdinal, ref processedInitializers, synthesizedSubmissionFields, compilationState); + // Compile extension methods without implementation normally, to bind the body and get errors. + // Also, extension marker method should always be compiled normally. + if (containingType.IsExtension && + method.TryGetCorrespondingExtensionImplementationMethod() is not null) + { + EmitSkeletonMethodInExtension(method); + } + else + { + CompileMethod(method, memberOrdinal, ref processedInitializers, synthesizedSubmissionFields, compilationState); + } break; } @@ -892,6 +904,16 @@ private void CompileMethod( SynthesizedSubmissionFields previousSubmissionFields, TypeCompilationState compilationState) { + var extensionImplementation = methodSymbol as SourceExtensionImplementationMethodSymbol; + + if (extensionImplementation is not null) + { + // Binding and analysis is performed on the user declared method + methodSymbol = extensionImplementation.UnderlyingMethod; + + Debug.Assert(!methodSymbol.SynthesizesLoweredBoundBody); + } + _cancellationToken.ThrowIfCancellationRequested(); SourceMemberMethodSymbol sourceMethod = methodSymbol as SourceMemberMethodSymbol; @@ -1139,6 +1161,7 @@ forSemanticModel.Syntax is { } semanticModelSyntax && }); } + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Ensure we are not messing up relative order of events for extension members (with relation to events for enclosing types, etc.) _compilation.EventQueue.TryEnqueue(new SymbolDeclaredCompilationEvent( _compilation, methodSymbol, semanticModelWithCachedBoundNodes)); } @@ -1178,6 +1201,7 @@ forSemanticModel.Syntax is { } semanticModelSyntax && { loweredBodyOpt = LowerBodyOrInitializer( methodSymbol, + extensionImplementation, methodOrdinal, flowAnalyzedBody, previousSubmissionFields, @@ -1254,6 +1278,7 @@ forSemanticModel.Syntax is { } semanticModelSyntax && BoundStatement lowered = LowerBodyOrInitializer( methodSymbol, + extensionImplementation, methodOrdinal, analyzedInitializers, previousSubmissionFields, @@ -1324,7 +1349,7 @@ forSemanticModel.Syntax is { } semanticModelSyntax && var emittedBody = GenerateMethodBody( _moduleBeingBuiltOpt, - methodSymbol, + extensionImplementation ?? methodSymbol, methodOrdinal, boundBody, lambdaDebugInfoBuilder.ToImmutable(), @@ -1340,7 +1365,7 @@ forSemanticModel.Syntax is { } semanticModelSyntax && codeCoverageSpans, entryPointOpt: null); - _moduleBeingBuiltOpt.SetMethodBody(methodSymbol.PartialDefinitionPart ?? methodSymbol, emittedBody); + _moduleBeingBuiltOpt.SetMethodBody(GetSymbolForEmittedBody(extensionImplementation ?? methodSymbol), emittedBody); } } @@ -1361,9 +1386,63 @@ forSemanticModel.Syntax is { } semanticModelSyntax && } } + private void EmitSkeletonMethodInExtension(MethodSymbol methodSymbol) + { + if (!_emitMethodBodies) + { + return; + } + + ILBuilder builder = new ILBuilder(_moduleBeingBuiltOpt, new LocalSlotManager(slotAllocator: null), OptimizationLevel.Release, areLocalsZeroed: false); + + // Emit methods in extensions as skeletons: + // => throw null; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Should we throw NotSupportedException instead? + builder.EmitOpCode(System.Reflection.Metadata.ILOpCode.Ldnull); + builder.EmitThrow(isRethrow: false); + builder.Realize(); + + _moduleBeingBuiltOpt.TestData?.SetMethodILBuilder(methodSymbol, builder); + + _moduleBeingBuiltOpt.SetMethodBody( + methodSymbol, + new MethodBody( + builder.RealizedIL, + maxStack: 1, + methodSymbol.GetCciAdapter(), + new DebugId(ordinal: -1, _moduleBeingBuiltOpt.CurrentGenerationOrdinal), + locals: [], + SequencePointList.Empty, + debugDocumentProvider: null, + exceptionHandlers: ImmutableArray.Empty, + areLocalsZeroed: false, + hasStackalloc: false, + localScopes: ImmutableArray.Empty, + hasDynamicLocalVariables: false, + importScopeOpt: null, + lambdaDebugInfo: ImmutableArray.Empty, + orderedLambdaRuntimeRudeEdits: ImmutableArray.Empty, + closureDebugInfo: ImmutableArray.Empty, + stateMachineTypeNameOpt: null, + stateMachineHoistedLocalScopes: default(ImmutableArray), + stateMachineHoistedLocalSlots: default(ImmutableArray), + stateMachineAwaiterSlots: default(ImmutableArray), + StateMachineStatesDebugInfo.Create(variableSlotAllocator: null, ImmutableArray.Empty), + stateMachineMoveNextDebugInfoOpt: null, + codeCoverageSpans: ImmutableArray.Empty, + isPrimaryConstructor: false) + ); + } + + private static MethodSymbol GetSymbolForEmittedBody(MethodSymbol methodSymbol) + { + return methodSymbol.PartialDefinitionPart ?? methodSymbol; + } + // internal for testing internal static BoundStatement LowerBodyOrInitializer( MethodSymbol method, + SourceExtensionImplementationMethodSymbol extensionImplementationMethod, int methodOrdinal, BoundStatement body, SynthesizedSubmissionFields previousSubmissionFields, @@ -1412,6 +1491,22 @@ internal static BoundStatement LowerBodyOrInitializer( return loweredBody; } + if (extensionImplementationMethod is not null) + { + var extensionRewriter = new ExtensionMethodBodyRewriter(method, extensionImplementationMethod); + loweredBody = (BoundStatement)extensionRewriter.Visit(loweredBody); + method = extensionImplementationMethod; + } + else + { + loweredBody = ExtensionMethodReferenceRewriter.Rewrite(loweredBody); + } + + if (loweredBody.HasErrors) + { + return loweredBody; + } + if (sawAwaitInExceptionHandler) { // If we have awaits in handlers, we need to @@ -1600,9 +1695,6 @@ private static MethodBody GenerateMethodBody( return null; } - // We will only save the IL builders when running tests. - moduleBuilder.TestData?.SetMethodILBuilder(method, builder.GetSnapshot()); - var stateMachineHoistedLocalSlots = default(ImmutableArray); var stateMachineAwaiterSlots = default(ImmutableArray); if (optimizations == OptimizationLevel.Debug && (object)stateMachineTypeOpt != null) @@ -1612,10 +1704,15 @@ private static MethodBody GenerateMethodBody( Debug.Assert(!diagnostics.HasAnyErrors()); } + MethodSymbol methodBodyParentSymbol = GetSymbolForEmittedBody(method); + + // We will only save the IL builders when running tests. + moduleBuilder.TestData?.SetMethodILBuilder(methodBodyParentSymbol, builder.GetSnapshot()); + return new MethodBody( builder.RealizedIL, builder.MaxStack, - (method.PartialDefinitionPart ?? method).GetCciAdapter(), + methodBodyParentSymbol.GetCciAdapter(), variableSlotAllocatorOpt?.MethodId ?? new DebugId(methodOrdinal, moduleBuilder.CurrentGenerationOrdinal), localVariables, builder.RealizedSequencePoints, diff --git a/src/Compilers/CSharp/Portable/Declarations/DeclarationKind.cs b/src/Compilers/CSharp/Portable/Declarations/DeclarationKind.cs index 4e24d98fdc81c..20d2c9b3156ee 100644 --- a/src/Compilers/CSharp/Portable/Declarations/DeclarationKind.cs +++ b/src/Compilers/CSharp/Portable/Declarations/DeclarationKind.cs @@ -23,7 +23,8 @@ internal enum DeclarationKind : byte Submission, ImplicitClass, Record, - RecordStruct + RecordStruct, + Extension, } internal static partial class EnumConversions @@ -42,6 +43,7 @@ internal static DeclarationKind ToDeclarationKind(this SyntaxKind kind) case SyntaxKind.DelegateDeclaration: return DeclarationKind.Delegate; case SyntaxKind.RecordDeclaration: return DeclarationKind.Record; case SyntaxKind.RecordStructDeclaration: return DeclarationKind.RecordStruct; + case SyntaxKind.ExtensionDeclaration: return DeclarationKind.Extension; default: throw ExceptionUtilities.UnexpectedValue(kind); } diff --git a/src/Compilers/CSharp/Portable/Declarations/DeclarationTreeBuilder.cs b/src/Compilers/CSharp/Portable/Declarations/DeclarationTreeBuilder.cs index 966c576b4e75c..f880a1884ad12 100644 --- a/src/Compilers/CSharp/Portable/Declarations/DeclarationTreeBuilder.cs +++ b/src/Compilers/CSharp/Portable/Declarations/DeclarationTreeBuilder.cs @@ -115,6 +115,7 @@ DeclarationKind.Submission or DeclarationKind.ImplicitClass or DeclarationKind.Record or DeclarationKind.RecordStruct => true, + DeclarationKind.Extension => true, _ => throw ExceptionUtilities.UnexpectedValue(typeDeclaration.Kind) }; @@ -680,6 +681,11 @@ public override SingleNamespaceOrTypeDeclaration VisitRecordDeclaration(RecordDe return VisitTypeDeclaration(node, declarationKind); } + public override SingleNamespaceOrTypeDeclaration VisitExtensionDeclaration(ExtensionDeclarationSyntax node) + { + return VisitTypeDeclaration(node, DeclarationKind.Extension); + } + private SingleTypeDeclaration VisitTypeDeclaration(TypeDeclarationSyntax node, DeclarationKind kind) { var declFlags = node.AttributeLists.Any() @@ -766,14 +772,15 @@ private SingleTypeDeclaration VisitTypeDeclaration(TypeDeclarationSyntax node, D } } + bool isExtension = kind == DeclarationKind.Extension; return new SingleTypeDeclaration( kind: kind, - name: node.Identifier.ValueText, + name: isExtension ? "" : node.Identifier.ValueText, arity: node.Arity, modifiers: modifiers, declFlags: declFlags, syntaxReference: _syntaxTree.GetReference(node), - nameLocation: new SourceLocation(node.Identifier), + nameLocation: new SourceLocation(isExtension ? node.Keyword : node.Identifier), memberNames: memberNames, children: VisitTypeChildren(node), diagnostics: diagnostics.ToReadOnlyAndFree(), @@ -917,6 +924,7 @@ private BoxedMemberNames GetNonTypeMemberNames( bool hasPrimaryCtor = false) { bool anyMethodHadExtensionSyntax = false; + bool anyExtensionDeclarationSyntax = false; bool anyMemberHasAttributes = false; bool anyNonTypeMembers = false; bool anyRequiredMembers = false; @@ -936,6 +944,11 @@ private BoxedMemberNames GetNonTypeMemberNames( anyMethodHadExtensionSyntax = true; } + if (!anyExtensionDeclarationSyntax && member.Kind == SyntaxKind.ExtensionDeclaration) + { + anyExtensionDeclarationSyntax = true; + } + if (!anyMemberHasAttributes && CheckMemberForAttributes(member)) { anyMemberHasAttributes = true; @@ -947,7 +960,7 @@ private BoxedMemberNames GetNonTypeMemberNames( } // Break early if we've hit all sorts of members. - if (anyNonTypeMembers && anyMethodHadExtensionSyntax && anyMemberHasAttributes && anyRequiredMembers) + if (anyNonTypeMembers && anyMethodHadExtensionSyntax && anyExtensionDeclarationSyntax && anyMemberHasAttributes && anyRequiredMembers) { break; } @@ -958,6 +971,11 @@ private BoxedMemberNames GetNonTypeMemberNames( declFlags |= SingleTypeDeclaration.TypeDeclarationFlags.AnyMemberHasExtensionMethodSyntax; } + if (anyExtensionDeclarationSyntax) + { + declFlags |= SingleTypeDeclaration.TypeDeclarationFlags.AnyExtensionDeclarationSyntax; + } + if (anyMemberHasAttributes) { declFlags |= SingleTypeDeclaration.TypeDeclarationFlags.AnyMemberHasAttributes; @@ -1089,6 +1107,7 @@ private static bool CheckMemberForAttributes(Syntax.InternalSyntax.CSharpSyntaxN case SyntaxKind.EnumDeclaration: case SyntaxKind.RecordDeclaration: case SyntaxKind.RecordStructDeclaration: + case SyntaxKind.ExtensionDeclaration: return (((Syntax.InternalSyntax.BaseTypeDeclarationSyntax)member).AttributeLists).Any(); case SyntaxKind.DelegateDeclaration: diff --git a/src/Compilers/CSharp/Portable/Declarations/MergedTypeDeclaration.cs b/src/Compilers/CSharp/Portable/Declarations/MergedTypeDeclaration.cs index 4521376e4b5d5..293c5765bde10 100644 --- a/src/Compilers/CSharp/Portable/Declarations/MergedTypeDeclaration.cs +++ b/src/Compilers/CSharp/Portable/Declarations/MergedTypeDeclaration.cs @@ -78,6 +78,7 @@ public ImmutableArray> GetAttributeDeclarations( case SyntaxKind.InterfaceDeclaration: case SyntaxKind.RecordDeclaration: case SyntaxKind.RecordStructDeclaration: + case SyntaxKind.ExtensionDeclaration: attributesSyntaxList = ((TypeDeclarationSyntax)typeDecl).AttributeLists; break; @@ -129,6 +130,20 @@ public bool ContainsExtensionMethods } } + public bool ContainsExtensionDeclarations + { + get + { + foreach (var decl in this.Declarations) + { + if (decl.AnyExtensionDeclarationSyntax) + return true; + } + + return false; + } + } + public bool HasPrimaryConstructor { get @@ -253,7 +268,8 @@ public ICollection MemberNames internal string GetDebuggerDisplay() { - return $"{nameof(MergedTypeDeclaration)} {Name}"; + string identifier = (Kind is DeclarationKind.Extension) ? "extension" : Name; + return $"{nameof(MergedTypeDeclaration)} {identifier}"; } } } diff --git a/src/Compilers/CSharp/Portable/Declarations/SingleTypeDeclaration.cs b/src/Compilers/CSharp/Portable/Declarations/SingleTypeDeclaration.cs index 3ef6b8c3ac27b..f51334bd3baf8 100644 --- a/src/Compilers/CSharp/Portable/Declarations/SingleTypeDeclaration.cs +++ b/src/Compilers/CSharp/Portable/Declarations/SingleTypeDeclaration.cs @@ -67,6 +67,11 @@ internal enum TypeDeclarationFlags : ushort HasRequiredMembers = 1 << 10, HasPrimaryConstructor = 1 << 11, + + /// + /// Set when is present. + /// + AnyExtensionDeclarationSyntax = 1 << 12, } internal SingleTypeDeclaration( @@ -136,6 +141,14 @@ public bool AnyMemberHasExtensionMethodSyntax } } + public bool AnyExtensionDeclarationSyntax + { + get + { + return (_flags & TypeDeclarationFlags.AnyExtensionDeclarationSyntax) != 0; + } + } + public bool HasAnyAttributes { get @@ -260,9 +273,9 @@ public bool Equals(TypeDeclarationIdentity other) return false; } - if (thisDecl._kind == DeclarationKind.Enum || thisDecl._kind == DeclarationKind.Delegate) + if (thisDecl._kind is DeclarationKind.Enum or DeclarationKind.Delegate or DeclarationKind.Extension) { - // oh, so close, but enums and delegates cannot be partial + // oh, so close, but enums, delegates and extensions cannot be partial return false; } diff --git a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs index 636dd4a119a61..c565c056a507c 100644 --- a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs +++ b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs @@ -112,7 +112,7 @@ internal static EmitBaseline.MetadataSymbols GetOrCreateMetadataSymbols(EmitBase internal static SynthesizedTypeMaps GetSynthesizedTypesFromMetadata(MetadataReader reader, MetadataDecoder metadataDecoder) { var anonymousTypes = ImmutableSegmentedDictionary.CreateBuilder(); - var anonymousDelegatesWithIndexedNames = new Dictionary>(); + var anonymousDelegatesWithIndexedNames = PooledDictionary>.GetInstance(); var anonymousDelegates = ImmutableSegmentedDictionary.CreateBuilder(); foreach (var handle in reader.TypeDefinitions) diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/ExpandedVarargsMethodReference.cs b/src/Compilers/CSharp/Portable/Emitter/Model/ExpandedVarargsMethodReference.cs index 5902f478f2db2..c4e2e505af41a 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/ExpandedVarargsMethodReference.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/ExpandedVarargsMethodReference.cs @@ -225,13 +225,13 @@ private static void Append(PooledStringBuilder result, object value) public sealed override bool Equals(object obj) { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } public sealed override int GetHashCode() { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } } } diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/NamedTypeReference.cs b/src/Compilers/CSharp/Portable/Emitter/Model/NamedTypeReference.cs index da87c2a8b6779..0636eb1fa9634 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/NamedTypeReference.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/NamedTypeReference.cs @@ -168,13 +168,13 @@ Cci.IDefinition Cci.IReference.AsDefinition(EmitContext context) public sealed override bool Equals(object obj) { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } public sealed override int GetHashCode() { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } } } diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/NamedTypeSymbolAdapter.cs b/src/Compilers/CSharp/Portable/Emitter/Model/NamedTypeSymbolAdapter.cs index 19a7bb6dc27da..9fb7c177d3854 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/NamedTypeSymbolAdapter.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/NamedTypeSymbolAdapter.cs @@ -287,7 +287,7 @@ Cci.ITypeReference Cci.ITypeDefinition.GetBaseClass(EmitContext context) Debug.Assert(((Cci.ITypeReference)this).AsTypeDefinition(context) != null); NamedTypeSymbol baseType = AdaptedNamedTypeSymbol.BaseTypeNoUseSiteDiagnostics; - if (AdaptedNamedTypeSymbol.IsScriptClass) + if (AdaptedNamedTypeSymbol.IsScriptClass || AdaptedNamedTypeSymbol.IsExtension) // Tracked by https://github.com/dotnet/roslyn/issues/76130 : we should have checked the presence of System.Object { // although submission and scripts semantically doesn't have a base we need to emit one into metadata: Debug.Assert((object)baseType == null); @@ -628,7 +628,7 @@ bool Cci.ITypeDefinition.IsSealed { Debug.Assert((object)method != null); - if ((alwaysIncludeConstructors && method.MethodKind == MethodKind.Constructor) || method.GetCciAdapter().ShouldInclude(context)) + if ((alwaysIncludeConstructors && method.MethodKind == MethodKind.Constructor) || method is SynthesizedExtensionMarker || method.GetCciAdapter().ShouldInclude(context)) { yield return method.GetCciAdapter(); } @@ -779,6 +779,11 @@ string Cci.INamedEntity.Name { get { + if (AdaptedNamedTypeSymbol.IsExtension) + { + return AdaptedNamedTypeSymbol.ExtensionName; + } + string unsuffixedName = AdaptedNamedTypeSymbol.Name; // CLR generally allows names with dots, however some APIs like IMetaDataImport diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs index f19d7f8e9f6dd..eec2ef91da292 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs @@ -301,7 +301,7 @@ private void ValidateReferencedAssembly(AssemblySymbol assembly, AssemblyReferen /// private static void GetDocumentsForMethodsAndNestedTypes(PooledHashSet documentList, ArrayBuilder typesToProcess, EmitContext context) { - // Temporarily disable assert to unblock getting net8.0 teststing re-nabled on Unix. Will + // Temporarily disable assert to unblock getting net8.0 testing re-enabled on Unix. Will // remove this shortly. // https://github.com/dotnet/roslyn/issues/71571 // Debug.Assert(!context.MetadataOnly); @@ -2090,5 +2090,29 @@ internal bool TryGetTranslatedImports(ImportChain chain, out ImmutableArray true, @@ -2462,8 +2464,8 @@ or ErrorCode.ERR_PartialPropertyDuplicateImplementation or ErrorCode.ERR_PartialPropertyMissingAccessor or ErrorCode.ERR_PartialPropertyUnexpectedAccessor or ErrorCode.ERR_PartialPropertyInitMismatch - or ErrorCode.ERR_PartialPropertyTypeDifference - or ErrorCode.WRN_PartialPropertySignatureDifference + or ErrorCode.ERR_PartialMemberTypeDifference + or ErrorCode.WRN_PartialMemberSignatureDifference or ErrorCode.ERR_PartialPropertyRequiredDifference or ErrorCode.WRN_FieldIsAmbiguous or ErrorCode.ERR_InlineArrayAttributeOnRecord @@ -2479,6 +2481,28 @@ or ErrorCode.WRN_UnscopedRefAttributeOldRules or ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature or ErrorCode.ERR_ImplicitlyTypedParamsParameter or ErrorCode.ERR_VariableDeclarationNamedField + or ErrorCode.ERR_PartialMemberMissingImplementation + or ErrorCode.ERR_PartialMemberMissingDefinition + or ErrorCode.ERR_PartialMemberDuplicateDefinition + or ErrorCode.ERR_PartialMemberDuplicateImplementation + or ErrorCode.ERR_PartialEventInitializer + or ErrorCode.ERR_PartialConstructorInitializer + or ErrorCode.ERR_ExtensionDisallowsName + or ErrorCode.ERR_ExtensionDisallowsMember + or ErrorCode.ERR_BadExtensionContainingType + or ErrorCode.ERR_ExtensionParameterDisallowsDefaultValue + or ErrorCode.ERR_ReceiverParameterOnlyOne + or ErrorCode.ERR_ExtensionResolutionFailed + or ErrorCode.ERR_ReceiverParameterSameNameAsTypeParameter + or ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter + or ErrorCode.ERR_TypeParameterSameNameAsExtensionTypeParameter + or ErrorCode.ERR_LocalSameNameAsExtensionParameter + or ErrorCode.ERR_ValueParameterSameNameAsExtensionParameter + or ErrorCode.ERR_TypeParameterSameNameAsExtensionParameter + or ErrorCode.ERR_InvalidExtensionParameterReference + or ErrorCode.ERR_ValueParameterSameNameAsExtensionTypeParameter + or ErrorCode.ERR_UnderspecifiedExtension + or ErrorCode.ERR_ExpressionTreeContainsExtensionPropertyAccess or ErrorCode.ERR_OperatorsMustBePublic or ErrorCode.ERR_BadIncrementOpArgs or ErrorCode.ERR_OperatorMustReturnVoid diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index 902baae6f7a2b..2b7bdc6a6c509 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -297,6 +297,10 @@ internal enum MessageID IDS_FeatureUnboundGenericTypesInNameof = MessageBase + 12850, IDS_FeatureSimpleLambdaParameterModifiers = MessageBase + 12851, + IDS_FeaturePartialEventsAndConstructors = MessageBase + 12852, + + IDS_FeatureExtensions = MessageBase + 12853, + IDS_FeatureUserDefinedCompoundAssignmentOperators = MessageBase + 12901, // PROTOTYPE: Pack numbers } @@ -482,6 +486,8 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) case MessageID.IDS_FeatureFirstClassSpan: case MessageID.IDS_FeatureUnboundGenericTypesInNameof: case MessageID.IDS_FeatureSimpleLambdaParameterModifiers: + case MessageID.IDS_FeaturePartialEventsAndConstructors: + case MessageID.IDS_FeatureExtensions: case MessageID.IDS_FeatureUserDefinedCompoundAssignmentOperators: return LanguageVersion.Preview; diff --git a/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs b/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs index cdd1ca8b7f5f2..ba05a944c54bd 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs @@ -250,6 +250,7 @@ public override void ReportDuplicateMetadataReferenceWeak(DiagnosticBag diagnost public override int ERR_EncUpdateFailedMissingSymbol => (int)ErrorCode.ERR_EncUpdateFailedMissingSymbol; public override int ERR_InvalidDebugInfo => (int)ErrorCode.ERR_InvalidDebugInfo; public override int ERR_FunctionPointerTypesInAttributeNotSupported => (int)ErrorCode.ERR_FunctionPointerTypesInAttributeNotSupported; + public override int ERR_DataSectionStringLiteralHashCollision => (int)ErrorCode.ERR_DataSectionStringLiteralHashCollision; // Generators: public override int WRN_GeneratorFailedDuringInitialization => (int)ErrorCode.WRN_GeneratorFailedDuringInitialization; diff --git a/src/Compilers/CSharp/Portable/Errors/SameDiagnosticComparer.cs b/src/Compilers/CSharp/Portable/Errors/SameDiagnosticComparer.cs new file mode 100644 index 0000000000000..2972d0ea70542 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Errors/SameDiagnosticComparer.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp; + +internal sealed class SameDiagnosticComparer : EqualityComparer +{ + public static readonly SameDiagnosticComparer Instance = new SameDiagnosticComparer(); + public override bool Equals(Diagnostic? x, Diagnostic? y) => x is null ? y is null : x.Equals(y); + public override int GetHashCode(Diagnostic obj) => obj.GetHashCode(); +} diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs index 9331dab2b5c2e..43b5e7678aa68 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs @@ -1129,7 +1129,7 @@ public override BoundNode VisitConvertedTupleLiteral(BoundConvertedTupleLiteral private BoundNode VisitTupleExpression(BoundTupleExpression node) { - VisitArguments(node.Arguments, default(ImmutableArray), null); + VisitArguments(node.Arguments, default(ImmutableArray), null, default, false); return null; } @@ -1142,7 +1142,7 @@ public override BoundNode VisitTupleBinaryOperator(BoundTupleBinaryOperator node public override BoundNode VisitDynamicObjectCreationExpression(BoundDynamicObjectCreationExpression node) { - VisitArguments(node.Arguments, node.ArgumentRefKindsOpt, null); + VisitArguments(node.Arguments, node.ArgumentRefKindsOpt, null, node.ArgsToParamsOpt, node.Expanded); VisitRvalue(node.InitializerExpressionOpt); return null; } @@ -1150,7 +1150,7 @@ public override BoundNode VisitDynamicObjectCreationExpression(BoundDynamicObjec public override BoundNode VisitDynamicIndexerAccess(BoundDynamicIndexerAccess node) { VisitRvalue(node.Receiver); - VisitArguments(node.Arguments, node.ArgumentRefKindsOpt, null); + VisitArguments(node.Arguments, node.ArgumentRefKindsOpt, null, default, false); return null; } @@ -1163,7 +1163,7 @@ public override BoundNode VisitDynamicMemberAccess(BoundDynamicMemberAccess node public override BoundNode VisitDynamicInvocation(BoundDynamicInvocation node) { VisitRvalue(node.Expression); - VisitArguments(node.Arguments, node.ArgumentRefKindsOpt, null); + VisitArguments(node.Arguments, node.ArgumentRefKindsOpt, null, default, false); return null; } @@ -1246,7 +1246,7 @@ public override BoundNode VisitArgList(BoundArgList node) public override BoundNode VisitArgListOperator(BoundArgListOperator node) { // When we have M(__arglist(x, y, z)) we must visit x, y and z. - VisitArguments(node.Arguments, node.ArgumentRefKindsOpt, null); + VisitArguments(node.Arguments, node.ArgumentRefKindsOpt, null, default, false); return null; } @@ -1387,7 +1387,7 @@ void visitArgumentsAndCompleteAnalysis(BoundCall node) VisitLocalFunctionUse(localFunc, node.Syntax, isCall: true); } - VisitArgumentsAfterCall(node.Arguments, node.ArgumentRefKindsOpt, node.Method); + VisitArgumentsAfterCall(node.Arguments, node.ArgumentRefKindsOpt, node.Method, node.ArgsToParamsOpt, node.Expanded); VisitReceiverAfterCall(node.ReceiverOpt, node.Method); } } @@ -1481,7 +1481,7 @@ public override BoundNode VisitIndexerAccess(BoundIndexerAccess node) { var method = GetReadMethod(node.Indexer); VisitReceiverBeforeCall(node.ReceiverOpt, method); - VisitArguments(node.Arguments, node.ArgumentRefKindsOpt, method); + VisitArguments(node.Arguments, node.ArgumentRefKindsOpt, method, node.ArgsToParamsOpt, node.Expanded); if ((object)method != null) { VisitReceiverAfterCall(node.ReceiverOpt, method); @@ -1513,11 +1513,11 @@ public override BoundNode VisitEventAssignmentOperator(BoundEventAssignmentOpera /// /// Do not call for a local function. /// - protected virtual void VisitArguments(ImmutableArray arguments, ImmutableArray refKindsOpt, MethodSymbol method) + protected virtual void VisitArguments(ImmutableArray arguments, ImmutableArray refKindsOpt, MethodSymbol method, ImmutableArray argsToParamsOpt, bool expanded) { Debug.Assert(method?.OriginalDefinition.MethodKind != MethodKind.LocalFunction); VisitArgumentsBeforeCall(arguments, refKindsOpt); - VisitArgumentsAfterCall(arguments, refKindsOpt, method); + VisitArgumentsAfterCall(arguments, refKindsOpt, method, argsToParamsOpt, expanded); } private void VisitArgumentsBeforeCall(ImmutableArray arguments, ImmutableArray refKindsOpt) @@ -1537,10 +1537,11 @@ private void VisitArgumentsBeforeCall(ImmutableArray arguments, } } +#nullable enable /// /// Writes ref and out parameters /// - private void VisitArgumentsAfterCall(ImmutableArray arguments, ImmutableArray refKindsOpt, MethodSymbol method) + private void VisitArgumentsAfterCall(ImmutableArray arguments, ImmutableArray refKindsOpt, MethodSymbol? method, ImmutableArray argsToParamsOpt, bool expanded) { for (int i = 0; i < arguments.Length; i++) { @@ -1553,6 +1554,11 @@ private void VisitArgumentsAfterCall(ImmutableArray arguments, case RefKindExtensions.StrictIn: break; case RefKind.Ref: + if (method is null || Binder.GetCorrespondingParameter(i, method.Parameters, argsToParamsOpt, expanded)?.RefKind.IsWritableReference() != false) + { + goto case RefKind.Out; + } + break; case RefKind.Out: // passing as a byref argument is also a potential write WriteArgument(arguments[i], refKind, method); @@ -1562,6 +1568,7 @@ private void VisitArgumentsAfterCall(ImmutableArray arguments, } } } +#nullable disable protected static RefKind GetRefKind(ImmutableArray refKindsOpt, int index) { @@ -1635,7 +1642,7 @@ public override BoundNode VisitDelegateCreationExpression(BoundDelegateCreationE static bool ignoreReceiver(MethodSymbol method) { // static methods that aren't extensions get an implicit `this` receiver that should be ignored - return method.IsStatic && !method.IsExtensionMethod; + return method.IsStatic && !method.IsExtensionMethod; // Tracked by https://github.com/dotnet/roslyn/issues/76130: Test this code path with new extensions } } @@ -2060,7 +2067,7 @@ protected virtual void VisitLvalueParameter(BoundParameter node) public override BoundNode VisitObjectCreationExpression(BoundObjectCreationExpression node) { - VisitArguments(node.Arguments, node.ArgumentRefKindsOpt, node.Constructor); + VisitArguments(node.Arguments, node.ArgumentRefKindsOpt, node.Constructor, node.ArgsToParamsOpt, node.Expanded); VisitRvalue(node.InitializerExpressionOpt); return null; } @@ -3193,6 +3200,11 @@ public override BoundNode VisitSequencePointWithSpan(BoundSequencePointWithSpan return null; } + public override BoundNode VisitModuleCancellationTokenExpression(ModuleCancellationTokenExpression node) + { + return null; + } + public override BoundNode VisitStatementList(BoundStatementList node) { return VisitStatementListWorker(node); @@ -3530,7 +3542,7 @@ public override BoundNode VisitConvertedStackAllocExpression(BoundConvertedStack public override BoundNode VisitAnonymousObjectCreationExpression(BoundAnonymousObjectCreationExpression node) { // visit arguments as r-values - VisitArguments(node.Arguments, default(ImmutableArray), node.Constructor); + VisitArguments(node.Arguments, default(ImmutableArray), node.Constructor, default, false); return null; } @@ -3592,7 +3604,7 @@ public override BoundNode VisitObjectInitializerMember(BoundObjectInitializerMem method = GetReadMethod(property); } - VisitArguments(node.Arguments, node.ArgumentRefKindsOpt, method); + VisitArguments(node.Arguments, node.ArgumentRefKindsOpt, method, node.ArgsToParamsOpt, node.Expanded); } return null; @@ -3614,13 +3626,13 @@ public override BoundNode VisitCollectionElementInitializer(BoundCollectionEleme TLocalState savedState = savedState = this.State.Clone(); SetUnreachable(); - VisitArguments(node.Arguments, default(ImmutableArray), node.AddMethod); + VisitArguments(node.Arguments, default(ImmutableArray), node.AddMethod, node.ArgsToParamsOpt, node.Expanded); this.State = savedState; } else { - VisitArguments(node.Arguments, default(ImmutableArray), node.AddMethod); + VisitArguments(node.Arguments, default(ImmutableArray), node.AddMethod, node.ArgsToParamsOpt, node.Expanded); } return null; @@ -3628,7 +3640,7 @@ public override BoundNode VisitCollectionElementInitializer(BoundCollectionEleme public override BoundNode VisitDynamicCollectionElementInitializer(BoundDynamicCollectionElementInitializer node) { - VisitArguments(node.Arguments, default(ImmutableArray), method: null); + VisitArguments(node.Arguments, default(ImmutableArray), method: null, default, false); return null; } @@ -3746,7 +3758,7 @@ public override BoundNode VisitReadOnlySpanFromArray(BoundReadOnlySpanFromArray public override BoundNode VisitFunctionPointerInvocation(BoundFunctionPointerInvocation node) { VisitRvalue(node.InvokedExpression); - VisitArguments(node.Arguments, node.ArgumentRefKindsOpt, node.FunctionPointer.Signature); + VisitArguments(node.Arguments, node.ArgumentRefKindsOpt, node.FunctionPointer.Signature, default, false); return null; } diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass_LocalFunctions.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass_LocalFunctions.cs index ca468e82e76c2..9acb3c455cd77 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass_LocalFunctions.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass_LocalFunctions.cs @@ -94,7 +94,7 @@ protected bool HasLocalFuncUsagesCreated(LocalFunctionSymbol localFunc) // transition the state of captured variables if the variables have state changes // across all branches leaving the local function - var localFunctionState = GetOrCreateLocalFuncUsages(localFuncSymbol); + var localFunctionState = GetOrCreateLocalFuncUsages((LocalFunctionSymbol)localFuncSymbol); var savedLocalFunctionState = LocalFunctionStart(localFunctionState); var oldPending2 = SavePending(); diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractRegionDataFlowPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractRegionDataFlowPass.cs index 153aa9b03f482..237b2ab5ad9e2 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractRegionDataFlowPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractRegionDataFlowPass.cs @@ -33,6 +33,10 @@ protected override ImmutableArray Scan(ref bool badRegion) { MakeSlots(MethodParameters); if ((object)MethodThisParameter != null) GetOrCreateSlot(MethodThisParameter); + + if (TryGetInstanceExtensionParameter(out ParameterSymbol extensionParameter)) + GetOrCreateSlot(extensionParameter); + var result = base.Scan(ref badRegion); return result; } diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/DefiniteAssignment.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/DefiniteAssignment.cs index 568b2c4d01aa6..3c29f693a0a7b 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/DefiniteAssignment.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/DefiniteAssignment.cs @@ -368,6 +368,12 @@ protected override ImmutableArray Scan(ref bool badRegion) } } + ParameterSymbol extensionParameter = null; + if (TryGetInstanceExtensionParameter(out extensionParameter)) + { + EnterParameter(extensionParameter); + } + ImmutableArray pendingReturns = base.Scan(ref badRegion); // check that each out parameter is definitely assigned at the end of the method. If @@ -378,6 +384,7 @@ protected override ImmutableArray Scan(ref bool badRegion) { LeaveParameters(methodParameters, null, location); if ((object)methodThisParameter != null) LeaveParameter(methodThisParameter, null, location); + if ((object)extensionParameter != null) LeaveParameter(extensionParameter, null, location); var savedState = this.State; foreach (PendingBranch returnBranch in pendingReturns) @@ -385,6 +392,7 @@ protected override ImmutableArray Scan(ref bool badRegion) this.State = returnBranch.State; LeaveParameters(methodParameters, returnBranch.Branch.Syntax, null); if ((object)methodThisParameter != null) LeaveParameter(methodThisParameter, returnBranch.Branch.Syntax, null); + if ((object)extensionParameter != null) LeaveParameter(extensionParameter, returnBranch.Branch.Syntax, null); Join(ref savedState, ref this.State); } @@ -394,6 +402,21 @@ protected override ImmutableArray Scan(ref bool badRegion) return pendingReturns; } + protected bool TryGetInstanceExtensionParameter(out ParameterSymbol extensionParameter) + { + if (_symbol is not null + && _symbol.GetIsNewExtensionMember() + && !_symbol.IsStatic + && _symbol.ContainingType.ExtensionParameter is { } foundExtensionParameter) + { + extensionParameter = foundExtensionParameter; + return true; + } + + extensionParameter = null; + return false; + } + protected override ImmutableArray RemoveReturns() { var result = base.RemoveReturns(); @@ -666,14 +689,6 @@ public static void Analyze( } #nullable disable - private sealed class SameDiagnosticComparer : EqualityComparer - { - public static readonly SameDiagnosticComparer Instance = new SameDiagnosticComparer(); - public override bool Equals(Diagnostic x, Diagnostic y) => x.Equals(y); - public override int GetHashCode(Diagnostic obj) => - Hash.Combine(Hash.CombineValues(obj.Arguments), Hash.Combine(obj.Location.GetHashCode(), obj.Code)); - } - /// /// Analyze the body, reporting all necessary diagnostics. /// @@ -1832,6 +1847,18 @@ protected override LocalState TopState() } } } + + if (TryGetInstanceExtensionParameter(out ParameterSymbol extensionParameter)) + { + if (extensionParameter.RefKind != RefKind.Out) + { + int slot = GetOrCreateSlot(extensionParameter); + if (slot > 0) + { + SetSlotAssigned(slot, ref topState); + } + } + } } Symbol containing = current.ContainingSymbol; @@ -2181,7 +2208,7 @@ private void VisitStatementsWithLocalFunctions(BoundBlock block) if (stmt is BoundLocalFunctionStatement localFunctionStatement) { // Mark attribute arguments as used. - VisitAttributes(localFunctionStatement.Symbol.BindMethodAttributes()); + VisitAttributes(((LocalFunctionSymbol)localFunctionStatement.Symbol).BindMethodAttributes()); VisitAlways(stmt); } @@ -2329,7 +2356,7 @@ private void ReportIfUnused(LocalSymbol symbol, bool assigned) } } - private void ReportUnusedVariables(ImmutableArray locals) + private void ReportUnusedVariables(ImmutableArray locals) { foreach (var symbol in locals) { @@ -2337,7 +2364,7 @@ private void ReportUnusedVariables(ImmutableArray locals) } } - private void ReportIfUnused(LocalFunctionSymbol symbol) + private void ReportIfUnused(MethodSymbol symbol) { if (!_usedLocalFunctions.Contains(symbol)) { @@ -2425,7 +2452,7 @@ public override BoundNode VisitLambda(BoundLambda node) this.CurrentSymbol = node.Symbol; // Mark attribute arguments as used. - VisitAttributes(node.Symbol.BindMethodAttributes()); + VisitAttributes(((LambdaSymbol)node.Symbol).BindMethodAttributes()); var oldPending = SavePending(); // we do not support branches into a lambda diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs index f8d3ae04207f2..7943c8c6579d8 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs @@ -173,7 +173,7 @@ private static BoundBlock AppendImplicitReturn(BoundBlock body, MethodSymbol met builder.AddRange(statements, n - 1); builder.Add(AppendImplicitReturn((BoundBlock)statements[n - 1], method)); - return body.Update(body.Locals, ImmutableArray.Empty, body.HasUnsafeModifier, body.Instrumentation, builder.ToImmutableAndFree()); + return body.Update(body.Locals, ImmutableArray.Empty, body.HasUnsafeModifier, body.Instrumentation, builder.ToImmutableAndFree()); } else { diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.DebugVerifier.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.DebugVerifier.cs index 88858dcaa497f..9ecb458367894 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.DebugVerifier.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.DebugVerifier.cs @@ -231,7 +231,7 @@ private void VerifyExpression(BoundExpression expression, bool overrideSkippedEx private void VisitForEachEnumeratorInfo(ForEachEnumeratorInfo enumeratorInfo) { Visit(enumeratorInfo.DisposeAwaitableInfo); - if (enumeratorInfo.GetEnumeratorInfo.Method.IsExtensionMethod) + if (enumeratorInfo.GetEnumeratorInfo.Method.IsExtensionMethod) // Tracked by https://github.com/dotnet/roslyn/issues/76130: Test this code path with new extensions { foreach (var arg in enumeratorInfo.GetEnumeratorInfo.Arguments) { diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs index f1cca38ea7cb3..1be6cbe67c6bb 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs @@ -180,6 +180,12 @@ internal string GetDebuggerDisplay() /// private readonly bool _useConstructorExitWarnings; + /// + /// Non-null if we are performing the 'null-resilience' analysis of a getter which uses the 'field' keyword. + /// In this case, the inferred nullable annotation of the backing field must not be used, as we are currently in the process of inferring it. + /// + private readonly (SynthesizedBackingFieldSymbol field, NullableAnnotation assumedAnnotation)? _getterNullResilienceData; + /// /// If true, the parameter types and nullability from _delegateInvokeMethod is used for /// initial parameter state. If false, the signature of CurrentSymbol is used instead. @@ -448,6 +454,7 @@ private NullableWalker( CSharpCompilation compilation, Symbol? symbol, bool useConstructorExitWarnings, + (SynthesizedBackingFieldSymbol field, NullableAnnotation assumedAnnotation)? getterNullResilienceData, bool useDelegateInvokeParameterTypes, bool useDelegateInvokeReturnType, MethodSymbol? delegateInvokeMethodOpt, @@ -470,6 +477,7 @@ private NullableWalker( _binder = binder; _conversions = (Conversions)conversions.WithNullability(true); _useConstructorExitWarnings = useConstructorExitWarnings; + _getterNullResilienceData = getterNullResilienceData; _useDelegateInvokeParameterTypes = useDelegateInvokeParameterTypes; _useDelegateInvokeReturnType = useDelegateInvokeReturnType; _delegateInvokeMethod = delegateInvokeMethodOpt; @@ -592,6 +600,7 @@ protected override ImmutableArray Scan(ref bool badRegion) { EnterParameter(methodThisParameter, methodThisParameter.TypeWithAnnotations); } + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : should register the extension parameter makeNotNullMembersMaybeNull(); // We need to create a snapshot even of the first node, because we want to have the state of the initial parameters. @@ -724,7 +733,7 @@ void checkMemberStateOnConstructorExit(MethodSymbol constructor, Symbol member, switch (member) { case FieldSymbol f: - symbolType = f.TypeWithAnnotations; + symbolType = GetTypeOrReturnTypeWithAnnotations(f); field = f; symbol = (Symbol?)(f.AssociatedSymbol as PropertySymbol) ?? f; break; @@ -836,7 +845,7 @@ void makeNotNullMembersMaybeNull() var memberSlot = GetSlotForMemberPostCondition(memberToInitialize); if (memberSlot > 0) { - var type = memberToInitialize.GetTypeOrReturnType(); + var type = GetTypeOrReturnTypeWithAnnotations(memberToInitialize); if (!type.NullableAnnotation.IsOblivious()) { SetState(ref this.State, memberSlot, type.Type.IsPossiblyNullableReferenceTypeTypeParameter() ? NullableFlowState.MaybeDefault : NullableFlowState.MaybeNull); @@ -1172,6 +1181,10 @@ void makeMemberMaybeNull(MethodSymbol method, string memberName) } } + /// + /// Gets a slot for a static member, or a member of 'this', which is being referenced by a postcondition. + /// Used for "declaration-site" analysis of MemberNotNullAttributes. + /// private int GetSlotForMemberPostCondition(Symbol member) { if (member.Kind != SymbolKind.Field && @@ -1181,22 +1194,20 @@ private int GetSlotForMemberPostCondition(Symbol member) return -1; } - int containingSlot = GetReceiverSlotForMemberPostConditions(_symbol as MethodSymbol); - - if (containingSlot < 0) - { - return -1; - } - + int containingSlot; if (member.IsStatic) { - // Trying to access a static member from a non-static context containingSlot = 0; } - else if (containingSlot == 0) + else { - // Trying to access an instance member from a static context - return -1; + containingSlot = GetReceiverSlotForMemberPostConditions(_symbol as MethodSymbol); + if (containingSlot <= 0) + { + // Either trying to access an instance member from a static context, + // or an invalid slot (-1) was returned + return -1; + } } return GetOrCreateSlot(member, containingSlot); @@ -1448,6 +1459,7 @@ private static void Analyze( conversions, diagnostics, useConstructorExitWarnings, + getterNullResilienceData: null, useDelegateInvokeParameterTypes: false, useDelegateInvokeReturnType: false, delegateInvokeMethodOpt: null, @@ -1584,6 +1596,7 @@ private static (SnapshotManager?, ImmutableDictionary @@ -2771,7 +2793,7 @@ private void InheritDefaultState(TypeSymbol targetType, int targetSlot) Debug.Assert(targetSlot > 0); #if DEBUG - var actualType = _variables[targetSlot].Symbol.GetTypeOrReturnType().Type; + var actualType = GetTypeOrReturnType(_variables[targetSlot].Symbol); Debug.Assert(actualType is { }); if (!actualType.ContainsErrorType() && @@ -2791,13 +2813,46 @@ private void InheritDefaultState(TypeSymbol targetType, int targetSlot) { var symbol = AsMemberOfType(targetType, variable.Symbol); SetStateAndTrackForFinally(ref this.State, slot, GetDefaultState(symbol)); - InheritDefaultState(symbol.GetTypeOrReturnType().Type, slot); + InheritDefaultState(GetTypeOrReturnType(symbol), slot); } members.Free(); } + private static TypeSymbol GetTypeOrReturnType(Symbol symbol) => symbol.GetTypeOrReturnType().Type; + + /// Gets the TypeWithAnnotations of a symbol, possibly using the inferred nullable annotation for backing fields. + private TypeWithAnnotations GetTypeOrReturnTypeWithAnnotations(Symbol symbol) + { + var typeWithAnnotations = symbol.GetTypeOrReturnType(); + if (symbol is SynthesizedBackingFieldSymbol { InfersNullableAnnotation: true } backingField) + { + NullableAnnotation nullableAnnotation; + if (_getterNullResilienceData is var (analyzedField, assumedNullableAnnotation)) + { + // If we find a usage of a different backing field, than the one we are currently doing a null resilience analysis on, + // we should not proceed, in order to avoid cycles across inference of multiple fields. + if ((object)analyzedField != backingField) + throw ExceptionUtilities.UnexpectedValue(backingField); + + // Currently in the process of inferring the nullable annotation for 'backingField'. + // Therefore don't try to access the inferred nullable annotation, use a temporary assumedNullableAnnotation instead. + nullableAnnotation = assumedNullableAnnotation; + } + else + { + nullableAnnotation = backingField.GetInferredNullableAnnotation(); + } + + typeWithAnnotations = TypeWithAnnotations.Create(typeWithAnnotations.Type, nullableAnnotation); + } + + return typeWithAnnotations; + } + private NullableFlowState GetDefaultState(Symbol symbol) - => ApplyUnconditionalAnnotations(symbol.GetTypeOrReturnType().ToTypeWithState(), GetRValueAnnotations(symbol)).State; + { + return ApplyUnconditionalAnnotations(GetTypeOrReturnTypeWithAnnotations(symbol).ToTypeWithState(), GetRValueAnnotations(symbol)).State; + } private void InheritNullableStateOfTrackableType(int targetSlot, int valueSlot, int skipSlot) { @@ -3161,7 +3216,7 @@ private void VisitStatementsWithLocalFunctions(BoundBlock block) // In the first pass of the nullable walker, existence of usages here means that a call site has been visited. // In subsequent nullable walker passes, the starting state is preserved from previous passes. // In any case, existence of usages means that we have a good starting state. - if (localFuncs[i] is { } localFunc && HasLocalFuncUsagesCreated(localFunc.Symbol)) + if (localFuncs[i] is { } localFunc && HasLocalFuncUsagesCreated((LocalFunctionSymbol)localFunc.Symbol)) { localFuncs[i] = null; unvisitedLocalFuncs--; @@ -3209,7 +3264,7 @@ private void VisitStatementsWithLocalFunctions(BoundBlock block) public override BoundNode? VisitLocalFunctionStatement(BoundLocalFunctionStatement node) { - var localFunc = node.Symbol; + var localFunc = (LocalFunctionSymbol)node.Symbol; // Usages state is created when we visit the function's call site or its body. // In the first pass of the nullable walker, existence of usages here means that a call site has been visited. @@ -3926,10 +3981,11 @@ private void VisitObjectCreationExpressionBase(BoundObjectCreationExpressionBase Debug.Assert(isTargetTyped == argumentsCompletion is not null); var type = node.Type; - (int slot, NullableFlowState resultState, Func? initialStateInferenceCompletion) = inferInitialObjectState(node, type, constructor, arguments, argumentResults, isTargetTyped); + var initializerOpt = node.InitializerExpressionOpt; + (int slot, NullableFlowState resultState, Func? initialStateInferenceCompletion) = + inferInitialObjectState(node, type, constructor, arguments, argumentResults, isTargetTyped, hasObjectInitializer: initializerOpt is { }); Action? initializerCompletion = null; - var initializerOpt = node.InitializerExpressionOpt; if (initializerOpt != null) { initializerCompletion = VisitObjectCreationInitializer(slot, type, initializerOpt, delayCompletionForType: isTargetTyped); @@ -4012,20 +4068,20 @@ void setAnalyzedNullabilityAsContinuation( (int slot, NullableFlowState resultState, Func? completion) inferInitialObjectState( BoundExpression node, TypeSymbol type, MethodSymbol? constructor, ImmutableArray arguments, ImmutableArray argumentResults, - bool isTargetTyped) + bool isTargetTyped, + bool hasObjectInitializer) { if (isTargetTyped) { - return (-1, NullableFlowState.NotNull, inferInitialObjectStateAsContinuation(node, arguments, argumentResults)); + return (-1, NullableFlowState.NotNull, inferInitialObjectStateAsContinuation(node, arguments, argumentResults, hasObjectInitializer)); } Debug.Assert(node.Kind is BoundKind.ObjectCreationExpression or BoundKind.DynamicObjectCreationExpression or BoundKind.NewT or BoundKind.NoPiaObjectCreationExpression); - var argumentTypes = argumentResults.SelectAsArray(ar => ar.RValueType); - int slot = -1; var resultState = NullableFlowState.NotNull; - if (type is object) + if (type is object && + (hasObjectInitializer || type.IsStructType())) { slot = GetOrCreatePlaceholderSlot(node); if (slot > 0) @@ -4038,6 +4094,7 @@ void setAnalyzedNullabilityAsContinuation( if (containingType?.IsTupleType == true && !isDefaultValueTypeConstructor) { // new System.ValueTuple(e1, ..., eN) + var argumentTypes = argumentResults.SelectAsArray(ar => ar.RValueType); TrackNullableStateOfTupleElements(slot, containingType, arguments, argumentTypes, ((BoundObjectCreationExpression)node).ArgsToParamsOpt, useRestField: true); } else @@ -4082,11 +4139,12 @@ void setAnalyzedNullabilityAsContinuation( Func inferInitialObjectStateAsContinuation( BoundExpression node, ImmutableArray arguments, - ImmutableArray argumentResults) + ImmutableArray argumentResults, + bool hasObjectInitializer) { return (TypeSymbol type, MethodSymbol? constructor) => { - var (slot, resultState, completion) = inferInitialObjectState(node, type, constructor, arguments, argumentResults, isTargetTyped: false); + var (slot, resultState, completion) = inferInitialObjectState(node, type, constructor, arguments, argumentResults, isTargetTyped: false, hasObjectInitializer); Debug.Assert(completion is null); Debug.Assert(resultState == NullableFlowState.NotNull); return slot; @@ -4254,7 +4312,7 @@ void setAnalyzedNullabilityAsContinuation( if (symbol != null) { - Debug.Assert(TypeSymbol.Equals(objectInitializer.Type, symbol.GetTypeOrReturnType().Type, TypeCompareKind.IgnoreNullableModifiersForReferenceTypes)); + Debug.Assert(TypeSymbol.Equals(objectInitializer.Type, GetTypeOrReturnType(symbol), TypeCompareKind.IgnoreNullableModifiersForReferenceTypes)); symbol = AsMemberOfType(containingType, symbol); } @@ -4271,7 +4329,7 @@ int getOrCreateSlot(int containingSlot, Symbol symbol) int slot = getOrCreateSlot(containingSlot, symbol); Debug.Assert(!delayCompletionForType || slot == -1); - Action? nestedCompletion = VisitObjectCreationInitializer(slot, symbol.GetTypeOrReturnType().Type, initializer, delayCompletionForType); + Action? nestedCompletion = VisitObjectCreationInitializer(slot, GetTypeOrReturnType(symbol), initializer, delayCompletionForType); return completeNestedInitializerAnalysis(symbol, initializer, slot, nestedCompletion, delayCompletionForType); } @@ -4304,7 +4362,7 @@ int getOrCreateSlot(int containingSlot, Symbol symbol) { int slot = getOrCreateSlot(containingSlot, symbol); completeNestedInitializerAnalysis(symbol, initializer, slot, nestedCompletion: null, delayCompletionForType: false); - nestedCompletion?.Invoke(slot, symbol.GetTypeOrReturnType().Type); + nestedCompletion?.Invoke(slot, GetTypeOrReturnType(symbol)); }; } @@ -4317,9 +4375,9 @@ int getOrCreateSlot(int containingSlot, Symbol symbol) TakeIncrementalSnapshot(node.Right); } - Debug.Assert(symbol.GetTypeOrReturnType().HasType); + Debug.Assert(GetTypeOrReturnTypeWithAnnotations(symbol).HasType); - var type = ApplyLValueAnnotations(symbol.GetTypeOrReturnType(), GetObjectInitializerMemberLValueAnnotations(symbol)); + var type = ApplyLValueAnnotations(GetTypeOrReturnTypeWithAnnotations(symbol), GetObjectInitializerMemberLValueAnnotations(symbol)); (TypeWithState resultType, conversionCompletion) = conversionCompletion is not null ? @@ -4410,7 +4468,7 @@ conversionCompletion is not null ? Debug.Assert(reinferredMethod is object); if (node.ImplicitReceiverOpt != null) { - Debug.Assert(node.ImplicitReceiverOpt.Kind == BoundKind.ObjectOrCollectionValuePlaceholder); + //Debug.Assert(node.ImplicitReceiverOpt.Kind == BoundKind.ObjectOrCollectionValuePlaceholder); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : the receiver may be converted now SetAnalyzedNullability(node.ImplicitReceiverOpt, new VisitResult(node.ImplicitReceiverOpt.Type, NullableAnnotation.NotAnnotated, NullableFlowState.NotNull)); } SetUnknownResultNullability(node); @@ -4459,6 +4517,7 @@ static MethodSymbol addMethodAsMemberOfContainingType(BoundCollectionElementInit } else { + // Tracked by https://github.com/dotnet/roslyn/issues/76130: Do we need to do anything special for new extensions here? method = (MethodSymbol)AsMemberOfType(containingType, method); } @@ -4766,6 +4825,7 @@ internal static TypeWithAnnotations BestTypeForLambdaReturns( var walker = new NullableWalker(binder.Compilation, symbol: null, useConstructorExitWarnings: false, + getterNullResilienceData: null, useDelegateInvokeParameterTypes: false, useDelegateInvokeReturnType: false, delegateInvokeMethodOpt: null, @@ -5332,7 +5392,7 @@ private void AfterLeftChildHasBeenVisited( operandComparedToNonNull = SkipReferenceConversions(operandComparedToNonNull); SplitAndLearnFromNonNullTest(operandComparedToNonNull, whenTrue: false); return; - }; + } } } @@ -5545,7 +5605,7 @@ private void MarkDependentSlotsNotNull(int slot, TypeSymbol expressionType, ref if (childSlot > 0) { SetState(ref state, childSlot, NullableFlowState.NotNull); - MarkDependentSlotsNotNull(childSlot, member.GetTypeOrReturnType().Type, ref state, depth - 1); + MarkDependentSlotsNotNull(childSlot, GetTypeOrReturnType(member), ref state, depth - 1); } } } @@ -6270,6 +6330,7 @@ private static BoundExpression CreatePlaceholderIfNecessary(BoundExpression expr // Only instance receivers go through VisitRvalue; arguments go through VisitArgumentEvaluate. if (node.ReceiverOpt is not null) { + // Tracked by https://github.com/dotnet/roslyn/issues/76130: Do we need to do anything special for new extensions here? VisitRvalueEpilogue(receiver); // VisitRvalue does this after visiting each node receiverType = ResultType; CheckCallReceiver(receiver, receiverType, node.Method); @@ -6335,6 +6396,7 @@ TypeWithState visitAndCheckReceiver(BoundCall node) void reinferMethodAndVisitArguments(BoundCall node, TypeWithState receiverType, VisitResult? firstArgumentResult = null) { + // Tracked by https://github.com/dotnet/roslyn/issues/76130: Do we need to do anything special for new extensions here? var method = node.Method; ImmutableArray refKindsOpt = node.ArgumentRefKindsOpt; if (!receiverType.HasNullType) @@ -6648,6 +6710,12 @@ private FlowAnalysisAnnotations GetRValueAnnotations(Symbol? symbol) private FlowAnalysisAnnotations GetParameterAnnotations(ParameterSymbol parameter) { + if (parameter.ContainingSymbol is TypeSymbol { IsExtension: true }) + { + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : revisit when doing nullability analysis + return FlowAnalysisAnnotations.None; + } + // Annotations are ignored when binding an attribute to avoid cycles. (Members used // in attributes are error scenarios, so missing warnings should not be important.) if (IsAnalyzingAttribute) @@ -6656,7 +6724,7 @@ private FlowAnalysisAnnotations GetParameterAnnotations(ParameterSymbol paramete var annotations = parameter.FlowAnalysisAnnotations; // Conditional annotations are ignored on parameters of non-boolean members. - if (parameter.ContainingSymbol.GetTypeOrReturnType().Type.SpecialType != SpecialType.System_Boolean) + if (GetTypeOrReturnType(parameter.ContainingSymbol).SpecialType != SpecialType.System_Boolean) { // NotNull = NotNullWhenTrue + NotNullWhenFalse bool hasNotNullWhenTrue = (annotations & FlowAnalysisAnnotations.NotNull) == FlowAnalysisAnnotations.NotNullWhenTrue; @@ -6766,7 +6834,7 @@ private static bool HasImplicitTypeArguments(SyntaxNode syntax) return nameSyntax.Kind() != SyntaxKind.GenericName; } - protected override void VisitArguments(ImmutableArray arguments, ImmutableArray refKindsOpt, MethodSymbol method) + protected override void VisitArguments(ImmutableArray arguments, ImmutableArray refKindsOpt, MethodSymbol method, ImmutableArray argsToParamsOpt, bool expanded) { // Callers should be using VisitArguments overload below. throw ExceptionUtilities.Unreachable(); @@ -7144,6 +7212,10 @@ bool tryShortCircuitTargetTypedExpression(BoundExpression argument, BoundExpress } } + /// + /// Applies the member postconditions of to members of or to the appropriate static members. + /// Used for the "use-site" analysis of MemberNotNullAttributes. + /// private void ApplyMemberPostConditions(BoundExpression? receiverOpt, MethodSymbol? method) { if (method is null) @@ -7163,9 +7235,11 @@ private void ApplyMemberPostConditions(BoundExpression? receiverOpt, MethodSymbo ApplyMemberPostConditions(receiverSlot, method); } - // For an instance method, or a non-static local function in an instance method, returns the slot for the `this` parameter - // For a static method, or a static local function, or a local function in a static method, returns 0 - // Otherwise, returns -1 + /// + /// Returns -1 when a null method is passed. In this case there are definitely no member postconditions to apply. + /// Returns the slot for the `this` parameter for an instance method, or a non-static local function in an instance method. + /// Otherwise, returns 0, because postconditions applying to static members of the containing type could be present. + /// private int GetReceiverSlotForMemberPostConditions(MethodSymbol? method) { if (method is null) @@ -7193,7 +7267,7 @@ private int GetReceiverSlotForMemberPostConditions(MethodSymbol? method) return GetOrCreateSlot(thisParameter); } - return -1; + return 0; } private void ApplyMemberPostConditions(int receiverSlot, MethodSymbol method) @@ -7919,7 +7993,7 @@ private MethodSymbol InferMethodTypeArguments( parameterRefKinds, arguments, ref discardedUseSiteInfo, - new MethodInferenceExtensions(this)); + new MethodInferenceExtensions(this)); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : we may need to override ordinals here if (!result.Success) { @@ -8298,7 +8372,9 @@ private static Symbol AsMemberOfType(TypeSymbol? type, Symbol symbol) } } } - Debug.Assert(false); // If this assert fails, add an appropriate test. + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : The assert below fails for an instance call on a generic extension. + //Debug.Assert(false); // If this assert fails, add an appropriate test. return symbol; bool tryAsMemberOfSingleType(NamedTypeSymbol singleType, [NotNullWhen(true)] out Symbol? result) @@ -8574,7 +8650,7 @@ private void TrackNullableStateOfNullableValue(int containingSlot, TypeSymbol co int targetSlot = GetNullableOfTValueSlot(containingType, containingSlot, out Symbol? symbol); if (targetSlot > 0) { - TrackNullableStateForAssignment(value, symbol!.GetTypeOrReturnType(), targetSlot, valueType, valueSlot); + TrackNullableStateForAssignment(value, GetTypeOrReturnTypeWithAnnotations(symbol!), targetSlot, valueType, valueSlot); } } @@ -8728,7 +8804,7 @@ void reportBadDelegateParameter(BindingDiagnosticBag bag, MethodSymbol sourceInv private void ReportNullabilityMismatchWithTargetDelegate(Location location, NamedTypeSymbol delegateType, BoundLambda lambda) { MethodSymbol? targetInvokeMethod = delegateType.DelegateInvokeMethod; - LambdaSymbol sourceMethod = lambda.Symbol; + LambdaSymbol sourceMethod = (LambdaSymbol)lambda.Symbol; UnboundLambda unboundLambda = lambda.UnboundLambda; if (targetInvokeMethod is null || @@ -8908,10 +8984,12 @@ private TypeWithState VisitConversion( { VisitLocalFunctionUse(localFunc); } + // Tracked by https://github.com/dotnet/roslyn/issues/76130: Do we need to do anything special for new extensions here? method = CheckMethodGroupReceiverNullability(group, parameters, method, conversion.IsExtensionMethod); } if (reportRemainingWarnings && invokeSignature != null) { + // Tracked by https://github.com/dotnet/roslyn/issues/76130: Do we need to do anything special for new extensions here? ReportNullabilityMismatchWithTargetDelegate(getDiagnosticLocation(), targetType, invokeSignature, method, conversion.IsExtensionMethod); } } @@ -9773,7 +9851,7 @@ void setAnalyzedNullabilityAsContinuation(BoundDelegateCreationExpression node, if (!lambda.IsSuppressed) { - ReportNullabilityMismatchWithTargetDelegate(lambda.Symbol.DiagnosticLocation, delegateType, lambda); + ReportNullabilityMismatchWithTargetDelegate(((LambdaSymbol)lambda.Symbol).DiagnosticLocation, delegateType, lambda); } return null; @@ -9868,6 +9946,7 @@ private MethodSymbol CheckMethodGroupReceiverNullability(BoundMethodGroup group, var receiverOpt = group.ReceiverOpt; if (TryGetMethodGroupReceiverNullability(receiverOpt, out TypeWithState receiverType)) { + // Tracked by https://github.com/dotnet/roslyn/issues/76130: Do we need to do anything special for new extensions here? var syntax = group.Syntax; if (!invokedAsExtensionMethod) { @@ -9999,9 +10078,23 @@ private void VisitThisOrBaseReference(BoundExpression node) // we may enter a conditional state for error scenarios on the LHS. Unsplit(); - FlowAnalysisAnnotations leftAnnotations = GetLValueAnnotations(left); - TypeWithAnnotations declaredType = LvalueResultType; - TypeWithAnnotations leftLValueType = ApplyLValueAnnotations(declaredType, leftAnnotations); + // When a getter-only prop is assigned in a constructor, it is bound as + // an assignment of the property even though it is really an assignment of the backing field. + // When such a property also uses the field keyword, we want the field's annotations+attributes + // to decide the validity of the assignment and the ones on the property itself to be ignored. + TypeWithAnnotations leftLValueType; + FlowAnalysisAnnotations leftAnnotations; + if (left is BoundPropertyAccess { PropertySymbol: SourcePropertySymbolBase { SetMethod: null, UsesFieldKeyword: true } property }) + { + var field = property.BackingField; + leftAnnotations = field.FlowAnalysisAnnotations; + leftLValueType = ApplyLValueAnnotations(GetTypeOrReturnTypeWithAnnotations(field), leftAnnotations); + } + else + { + leftAnnotations = GetLValueAnnotations(left); + leftLValueType = ApplyLValueAnnotations(LvalueResultType, leftAnnotations); + } if (left.Kind == BoundKind.EventAccess && ((BoundEventAccess)left).EventSymbol.IsWindowsRuntimeEvent) { @@ -10225,6 +10318,7 @@ private void VisitDeconstructMethodArguments(ArrayBuilder originalUserDefinedConversionsOpt, TypeSymbol type, bool hasErrors = false) + public BoundConversion(SyntaxNode syntax, BoundExpression operand, Conversion conversion, bool isBaseConversion, bool @checked, bool explicitCastInCode, ConstantValue? constantValueOpt, ConversionGroup? conversionGroupOpt, TypeSymbol type, bool hasErrors = false) : base(BoundKind.Conversion, syntax, type, hasErrors || operand.HasErrors()) { @@ -2963,7 +2963,6 @@ public BoundConversion(SyntaxNode syntax, BoundExpression operand, Conversion co this.ExplicitCastInCode = explicitCastInCode; this.ConstantValueOpt = constantValueOpt; this.ConversionGroupOpt = conversionGroupOpt; - this.OriginalUserDefinedConversionsOpt = originalUserDefinedConversionsOpt; } public new TypeSymbol Type => base.Type!; @@ -2974,16 +2973,15 @@ public BoundConversion(SyntaxNode syntax, BoundExpression operand, Conversion co public bool ExplicitCastInCode { get; } public override ConstantValue? ConstantValueOpt { get; } public ConversionGroup? ConversionGroupOpt { get; } - public ImmutableArray OriginalUserDefinedConversionsOpt { get; } [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitConversion(this); - public BoundConversion Update(BoundExpression operand, Conversion conversion, bool isBaseConversion, bool @checked, bool explicitCastInCode, ConstantValue? constantValueOpt, ConversionGroup? conversionGroupOpt, ImmutableArray originalUserDefinedConversionsOpt, TypeSymbol type) + public BoundConversion Update(BoundExpression operand, Conversion conversion, bool isBaseConversion, bool @checked, bool explicitCastInCode, ConstantValue? constantValueOpt, ConversionGroup? conversionGroupOpt, TypeSymbol type) { - if (operand != this.Operand || conversion != this.Conversion || isBaseConversion != this.IsBaseConversion || @checked != this.Checked || explicitCastInCode != this.ExplicitCastInCode || constantValueOpt != this.ConstantValueOpt || conversionGroupOpt != this.ConversionGroupOpt || originalUserDefinedConversionsOpt != this.OriginalUserDefinedConversionsOpt || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) + if (operand != this.Operand || conversion != this.Conversion || isBaseConversion != this.IsBaseConversion || @checked != this.Checked || explicitCastInCode != this.ExplicitCastInCode || constantValueOpt != this.ConstantValueOpt || conversionGroupOpt != this.ConversionGroupOpt || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) { - var result = new BoundConversion(this.Syntax, operand, conversion, isBaseConversion, @checked, explicitCastInCode, constantValueOpt, conversionGroupOpt, originalUserDefinedConversionsOpt, type, this.HasErrors); + var result = new BoundConversion(this.Syntax, operand, conversion, isBaseConversion, @checked, explicitCastInCode, constantValueOpt, conversionGroupOpt, type, this.HasErrors); result.CopyAttributes(this); return result; } @@ -3302,7 +3300,7 @@ public BoundStepThroughSequencePoint Update(TextSpan span) internal sealed partial class BoundBlock : BoundStatementList { - public BoundBlock(SyntaxNode syntax, ImmutableArray locals, ImmutableArray localFunctions, bool hasUnsafeModifier, BoundBlockInstrumentation? instrumentation, ImmutableArray statements, bool hasErrors = false) + public BoundBlock(SyntaxNode syntax, ImmutableArray locals, ImmutableArray localFunctions, bool hasUnsafeModifier, BoundBlockInstrumentation? instrumentation, ImmutableArray statements, bool hasErrors = false) : base(BoundKind.Block, syntax, statements, hasErrors || instrumentation.HasErrors() || statements.HasErrors()) { @@ -3317,14 +3315,14 @@ public BoundBlock(SyntaxNode syntax, ImmutableArray locals, Immutab } public ImmutableArray Locals { get; } - public ImmutableArray LocalFunctions { get; } + public ImmutableArray LocalFunctions { get; } public bool HasUnsafeModifier { get; } public BoundBlockInstrumentation? Instrumentation { get; } [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitBlock(this); - public BoundBlock Update(ImmutableArray locals, ImmutableArray localFunctions, bool hasUnsafeModifier, BoundBlockInstrumentation? instrumentation, ImmutableArray statements) + public BoundBlock Update(ImmutableArray locals, ImmutableArray localFunctions, bool hasUnsafeModifier, BoundBlockInstrumentation? instrumentation, ImmutableArray statements) { if (locals != this.Locals || localFunctions != this.LocalFunctions || hasUnsafeModifier != this.HasUnsafeModifier || instrumentation != this.Instrumentation || statements != this.Statements) { @@ -3504,7 +3502,7 @@ public BoundUsingLocalDeclarations Update(MethodArgumentInfo? patternDisposeInfo internal sealed partial class BoundLocalFunctionStatement : BoundStatement { - public BoundLocalFunctionStatement(SyntaxNode syntax, LocalFunctionSymbol symbol, BoundBlock? blockBody, BoundBlock? expressionBody, bool hasErrors = false) + public BoundLocalFunctionStatement(SyntaxNode syntax, MethodSymbol symbol, BoundBlock? blockBody, BoundBlock? expressionBody, bool hasErrors = false) : base(BoundKind.LocalFunctionStatement, syntax, hasErrors || blockBody.HasErrors() || expressionBody.HasErrors()) { @@ -3515,14 +3513,14 @@ public BoundLocalFunctionStatement(SyntaxNode syntax, LocalFunctionSymbol symbol this.ExpressionBody = expressionBody; } - public LocalFunctionSymbol Symbol { get; } + public MethodSymbol Symbol { get; } public BoundBlock? BlockBody { get; } public BoundBlock? ExpressionBody { get; } [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitLocalFunctionStatement(this); - public BoundLocalFunctionStatement Update(LocalFunctionSymbol symbol, BoundBlock? blockBody, BoundBlock? expressionBody) + public BoundLocalFunctionStatement Update(MethodSymbol symbol, BoundBlock? blockBody, BoundBlock? expressionBody) { if (!Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(symbol, this.Symbol) || blockBody != this.BlockBody || expressionBody != this.ExpressionBody) { @@ -3694,7 +3692,7 @@ public BoundExpressionStatement Update(BoundExpression expression) internal sealed partial class BoundBreakStatement : BoundStatement { - public BoundBreakStatement(SyntaxNode syntax, GeneratedLabelSymbol label, bool hasErrors) + public BoundBreakStatement(SyntaxNode syntax, LabelSymbol label, bool hasErrors) : base(BoundKind.BreakStatement, syntax, hasErrors) { @@ -3703,7 +3701,7 @@ public BoundBreakStatement(SyntaxNode syntax, GeneratedLabelSymbol label, bool h this.Label = label; } - public BoundBreakStatement(SyntaxNode syntax, GeneratedLabelSymbol label) + public BoundBreakStatement(SyntaxNode syntax, LabelSymbol label) : base(BoundKind.BreakStatement, syntax) { @@ -3712,12 +3710,12 @@ public BoundBreakStatement(SyntaxNode syntax, GeneratedLabelSymbol label) this.Label = label; } - public GeneratedLabelSymbol Label { get; } + public LabelSymbol Label { get; } [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitBreakStatement(this); - public BoundBreakStatement Update(GeneratedLabelSymbol label) + public BoundBreakStatement Update(LabelSymbol label) { if (!Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(label, this.Label)) { @@ -3731,7 +3729,7 @@ public BoundBreakStatement Update(GeneratedLabelSymbol label) internal sealed partial class BoundContinueStatement : BoundStatement { - public BoundContinueStatement(SyntaxNode syntax, GeneratedLabelSymbol label, bool hasErrors) + public BoundContinueStatement(SyntaxNode syntax, LabelSymbol label, bool hasErrors) : base(BoundKind.ContinueStatement, syntax, hasErrors) { @@ -3740,7 +3738,7 @@ public BoundContinueStatement(SyntaxNode syntax, GeneratedLabelSymbol label, boo this.Label = label; } - public BoundContinueStatement(SyntaxNode syntax, GeneratedLabelSymbol label) + public BoundContinueStatement(SyntaxNode syntax, LabelSymbol label) : base(BoundKind.ContinueStatement, syntax) { @@ -3749,12 +3747,12 @@ public BoundContinueStatement(SyntaxNode syntax, GeneratedLabelSymbol label) this.Label = label; } - public GeneratedLabelSymbol Label { get; } + public LabelSymbol Label { get; } [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitContinueStatement(this); - public BoundContinueStatement Update(GeneratedLabelSymbol label) + public BoundContinueStatement Update(LabelSymbol label) { if (!Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(label, this.Label)) { @@ -3768,7 +3766,7 @@ public BoundContinueStatement Update(GeneratedLabelSymbol label) internal sealed partial class BoundSwitchStatement : BoundStatement { - public BoundSwitchStatement(SyntaxNode syntax, BoundExpression expression, ImmutableArray innerLocals, ImmutableArray innerLocalFunctions, ImmutableArray switchSections, BoundDecisionDag reachabilityDecisionDag, BoundSwitchLabel? defaultLabel, GeneratedLabelSymbol breakLabel, bool hasErrors = false) + public BoundSwitchStatement(SyntaxNode syntax, BoundExpression expression, ImmutableArray innerLocals, ImmutableArray innerLocalFunctions, ImmutableArray switchSections, BoundDecisionDag reachabilityDecisionDag, BoundSwitchLabel? defaultLabel, LabelSymbol breakLabel, bool hasErrors = false) : base(BoundKind.SwitchStatement, syntax, hasErrors || expression.HasErrors() || switchSections.HasErrors() || reachabilityDecisionDag.HasErrors() || defaultLabel.HasErrors()) { @@ -3790,16 +3788,16 @@ public BoundSwitchStatement(SyntaxNode syntax, BoundExpression expression, Immut public BoundExpression Expression { get; } public ImmutableArray InnerLocals { get; } - public ImmutableArray InnerLocalFunctions { get; } + public ImmutableArray InnerLocalFunctions { get; } public ImmutableArray SwitchSections { get; } public BoundDecisionDag ReachabilityDecisionDag { get; } public BoundSwitchLabel? DefaultLabel { get; } - public GeneratedLabelSymbol BreakLabel { get; } + public LabelSymbol BreakLabel { get; } [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitSwitchStatement(this); - public BoundSwitchStatement Update(BoundExpression expression, ImmutableArray innerLocals, ImmutableArray innerLocalFunctions, ImmutableArray switchSections, BoundDecisionDag reachabilityDecisionDag, BoundSwitchLabel? defaultLabel, GeneratedLabelSymbol breakLabel) + public BoundSwitchStatement Update(BoundExpression expression, ImmutableArray innerLocals, ImmutableArray innerLocalFunctions, ImmutableArray switchSections, BoundDecisionDag reachabilityDecisionDag, BoundSwitchLabel? defaultLabel, LabelSymbol breakLabel) { if (expression != this.Expression || innerLocals != this.InnerLocals || innerLocalFunctions != this.InnerLocalFunctions || switchSections != this.SwitchSections || reachabilityDecisionDag != this.ReachabilityDecisionDag || defaultLabel != this.DefaultLabel || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(breakLabel, this.BreakLabel)) { @@ -3882,7 +3880,7 @@ public BoundIfStatement Update(BoundExpression condition, BoundStatement consequ internal abstract partial class BoundLoopStatement : BoundStatement { - protected BoundLoopStatement(BoundKind kind, SyntaxNode syntax, GeneratedLabelSymbol breakLabel, GeneratedLabelSymbol continueLabel, bool hasErrors) + protected BoundLoopStatement(BoundKind kind, SyntaxNode syntax, LabelSymbol breakLabel, LabelSymbol continueLabel, bool hasErrors) : base(kind, syntax, hasErrors) { @@ -3893,7 +3891,7 @@ protected BoundLoopStatement(BoundKind kind, SyntaxNode syntax, GeneratedLabelSy this.ContinueLabel = continueLabel; } - protected BoundLoopStatement(BoundKind kind, SyntaxNode syntax, GeneratedLabelSymbol breakLabel, GeneratedLabelSymbol continueLabel) + protected BoundLoopStatement(BoundKind kind, SyntaxNode syntax, LabelSymbol breakLabel, LabelSymbol continueLabel) : base(kind, syntax) { @@ -3904,13 +3902,13 @@ protected BoundLoopStatement(BoundKind kind, SyntaxNode syntax, GeneratedLabelSy this.ContinueLabel = continueLabel; } - public GeneratedLabelSymbol BreakLabel { get; } - public GeneratedLabelSymbol ContinueLabel { get; } + public LabelSymbol BreakLabel { get; } + public LabelSymbol ContinueLabel { get; } } internal abstract partial class BoundConditionalLoopStatement : BoundLoopStatement { - protected BoundConditionalLoopStatement(BoundKind kind, SyntaxNode syntax, ImmutableArray locals, BoundExpression condition, BoundStatement body, GeneratedLabelSymbol breakLabel, GeneratedLabelSymbol continueLabel, bool hasErrors = false) + protected BoundConditionalLoopStatement(BoundKind kind, SyntaxNode syntax, ImmutableArray locals, BoundExpression condition, BoundStatement body, LabelSymbol breakLabel, LabelSymbol continueLabel, bool hasErrors = false) : base(kind, syntax, breakLabel, continueLabel, hasErrors) { @@ -3932,7 +3930,7 @@ protected BoundConditionalLoopStatement(BoundKind kind, SyntaxNode syntax, Immut internal sealed partial class BoundDoStatement : BoundConditionalLoopStatement { - public BoundDoStatement(SyntaxNode syntax, ImmutableArray locals, BoundExpression condition, BoundStatement body, GeneratedLabelSymbol breakLabel, GeneratedLabelSymbol continueLabel, bool hasErrors = false) + public BoundDoStatement(SyntaxNode syntax, ImmutableArray locals, BoundExpression condition, BoundStatement body, LabelSymbol breakLabel, LabelSymbol continueLabel, bool hasErrors = false) : base(BoundKind.DoStatement, syntax, locals, condition, body, breakLabel, continueLabel, hasErrors || condition.HasErrors() || body.HasErrors()) { @@ -3948,7 +3946,7 @@ public BoundDoStatement(SyntaxNode syntax, ImmutableArray locals, B [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitDoStatement(this); - public BoundDoStatement Update(ImmutableArray locals, BoundExpression condition, BoundStatement body, GeneratedLabelSymbol breakLabel, GeneratedLabelSymbol continueLabel) + public BoundDoStatement Update(ImmutableArray locals, BoundExpression condition, BoundStatement body, LabelSymbol breakLabel, LabelSymbol continueLabel) { if (locals != this.Locals || condition != this.Condition || body != this.Body || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(breakLabel, this.BreakLabel) || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(continueLabel, this.ContinueLabel)) { @@ -3962,7 +3960,7 @@ public BoundDoStatement Update(ImmutableArray locals, BoundExpressi internal sealed partial class BoundWhileStatement : BoundConditionalLoopStatement { - public BoundWhileStatement(SyntaxNode syntax, ImmutableArray locals, BoundExpression condition, BoundStatement body, GeneratedLabelSymbol breakLabel, GeneratedLabelSymbol continueLabel, bool hasErrors = false) + public BoundWhileStatement(SyntaxNode syntax, ImmutableArray locals, BoundExpression condition, BoundStatement body, LabelSymbol breakLabel, LabelSymbol continueLabel, bool hasErrors = false) : base(BoundKind.WhileStatement, syntax, locals, condition, body, breakLabel, continueLabel, hasErrors || condition.HasErrors() || body.HasErrors()) { @@ -3978,7 +3976,7 @@ public BoundWhileStatement(SyntaxNode syntax, ImmutableArray locals [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitWhileStatement(this); - public BoundWhileStatement Update(ImmutableArray locals, BoundExpression condition, BoundStatement body, GeneratedLabelSymbol breakLabel, GeneratedLabelSymbol continueLabel) + public BoundWhileStatement Update(ImmutableArray locals, BoundExpression condition, BoundStatement body, LabelSymbol breakLabel, LabelSymbol continueLabel) { if (locals != this.Locals || condition != this.Condition || body != this.Body || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(breakLabel, this.BreakLabel) || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(continueLabel, this.ContinueLabel)) { @@ -3992,7 +3990,7 @@ public BoundWhileStatement Update(ImmutableArray locals, BoundExpre internal sealed partial class BoundForStatement : BoundLoopStatement { - public BoundForStatement(SyntaxNode syntax, ImmutableArray outerLocals, BoundStatement? initializer, ImmutableArray innerLocals, BoundExpression? condition, BoundStatement? increment, BoundStatement body, GeneratedLabelSymbol breakLabel, GeneratedLabelSymbol continueLabel, bool hasErrors = false) + public BoundForStatement(SyntaxNode syntax, ImmutableArray outerLocals, BoundStatement? initializer, ImmutableArray innerLocals, BoundExpression? condition, BoundStatement? increment, BoundStatement body, LabelSymbol breakLabel, LabelSymbol continueLabel, bool hasErrors = false) : base(BoundKind.ForStatement, syntax, breakLabel, continueLabel, hasErrors || initializer.HasErrors() || condition.HasErrors() || increment.HasErrors() || body.HasErrors()) { @@ -4020,7 +4018,7 @@ public BoundForStatement(SyntaxNode syntax, ImmutableArray outerLoc [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitForStatement(this); - public BoundForStatement Update(ImmutableArray outerLocals, BoundStatement? initializer, ImmutableArray innerLocals, BoundExpression? condition, BoundStatement? increment, BoundStatement body, GeneratedLabelSymbol breakLabel, GeneratedLabelSymbol continueLabel) + public BoundForStatement Update(ImmutableArray outerLocals, BoundStatement? initializer, ImmutableArray innerLocals, BoundExpression? condition, BoundStatement? increment, BoundStatement body, LabelSymbol breakLabel, LabelSymbol continueLabel) { if (outerLocals != this.OuterLocals || initializer != this.Initializer || innerLocals != this.InnerLocals || condition != this.Condition || increment != this.Increment || body != this.Body || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(breakLabel, this.BreakLabel) || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(continueLabel, this.ContinueLabel)) { @@ -4034,7 +4032,7 @@ public BoundForStatement Update(ImmutableArray outerLocals, BoundSt internal sealed partial class BoundForEachStatement : BoundLoopStatement { - public BoundForEachStatement(SyntaxNode syntax, ForEachEnumeratorInfo? enumeratorInfoOpt, BoundValuePlaceholder? elementPlaceholder, BoundExpression? elementConversion, BoundTypeExpression iterationVariableType, ImmutableArray iterationVariables, BoundExpression? iterationErrorExpressionOpt, BoundExpression expression, BoundForEachDeconstructStep? deconstructionOpt, BoundAwaitableInfo? awaitOpt, BoundStatement body, GeneratedLabelSymbol breakLabel, GeneratedLabelSymbol continueLabel, bool hasErrors = false) + public BoundForEachStatement(SyntaxNode syntax, ForEachEnumeratorInfo? enumeratorInfoOpt, BoundValuePlaceholder? elementPlaceholder, BoundExpression? elementConversion, BoundTypeExpression iterationVariableType, ImmutableArray iterationVariables, BoundExpression? iterationErrorExpressionOpt, BoundExpression expression, BoundForEachDeconstructStep? deconstructionOpt, BoundAwaitableInfo? awaitOpt, BoundStatement body, LabelSymbol breakLabel, LabelSymbol continueLabel, bool hasErrors = false) : base(BoundKind.ForEachStatement, syntax, breakLabel, continueLabel, hasErrors || elementPlaceholder.HasErrors() || elementConversion.HasErrors() || iterationVariableType.HasErrors() || iterationErrorExpressionOpt.HasErrors() || expression.HasErrors() || deconstructionOpt.HasErrors() || awaitOpt.HasErrors() || body.HasErrors()) { @@ -4071,7 +4069,7 @@ public BoundForEachStatement(SyntaxNode syntax, ForEachEnumeratorInfo? enumerato [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitForEachStatement(this); - public BoundForEachStatement Update(ForEachEnumeratorInfo? enumeratorInfoOpt, BoundValuePlaceholder? elementPlaceholder, BoundExpression? elementConversion, BoundTypeExpression iterationVariableType, ImmutableArray iterationVariables, BoundExpression? iterationErrorExpressionOpt, BoundExpression expression, BoundForEachDeconstructStep? deconstructionOpt, BoundAwaitableInfo? awaitOpt, BoundStatement body, GeneratedLabelSymbol breakLabel, GeneratedLabelSymbol continueLabel) + public BoundForEachStatement Update(ForEachEnumeratorInfo? enumeratorInfoOpt, BoundValuePlaceholder? elementPlaceholder, BoundExpression? elementConversion, BoundTypeExpression iterationVariableType, ImmutableArray iterationVariables, BoundExpression? iterationErrorExpressionOpt, BoundExpression expression, BoundForEachDeconstructStep? deconstructionOpt, BoundAwaitableInfo? awaitOpt, BoundStatement body, LabelSymbol breakLabel, LabelSymbol continueLabel) { if (enumeratorInfoOpt != this.EnumeratorInfoOpt || elementPlaceholder != this.ElementPlaceholder || elementConversion != this.ElementConversion || iterationVariableType != this.IterationVariableType || iterationVariables != this.IterationVariables || iterationErrorExpressionOpt != this.IterationErrorExpressionOpt || expression != this.Expression || deconstructionOpt != this.DeconstructionOpt || awaitOpt != this.AwaitOpt || body != this.Body || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(breakLabel, this.BreakLabel) || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(continueLabel, this.ContinueLabel)) { @@ -7590,7 +7588,7 @@ public BoundDynamicIndexerAccess Update(BoundExpression receiver, ImmutableArray internal sealed partial class BoundLambda : BoundExpression { - public BoundLambda(SyntaxNode syntax, UnboundLambda unboundLambda, LambdaSymbol symbol, BoundBlock body, ReadOnlyBindingDiagnostic diagnostics, Binder binder, TypeSymbol? type, bool hasErrors = false) + public BoundLambda(SyntaxNode syntax, UnboundLambda unboundLambda, MethodSymbol symbol, BoundBlock body, ReadOnlyBindingDiagnostic diagnostics, Binder binder, TypeSymbol? type, bool hasErrors = false) : base(BoundKind.Lambda, syntax, type, hasErrors || unboundLambda.HasErrors() || body.HasErrors()) { @@ -7607,7 +7605,7 @@ public BoundLambda(SyntaxNode syntax, UnboundLambda unboundLambda, LambdaSymbol } public UnboundLambda UnboundLambda { get; } - public LambdaSymbol Symbol { get; } + public MethodSymbol Symbol { get; } public new TypeSymbol? Type => base.Type; public BoundBlock Body { get; } public ReadOnlyBindingDiagnostic Diagnostics { get; } @@ -7616,7 +7614,7 @@ public BoundLambda(SyntaxNode syntax, UnboundLambda unboundLambda, LambdaSymbol [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitLambda(this); - public BoundLambda Update(UnboundLambda unboundLambda, LambdaSymbol symbol, BoundBlock body, ReadOnlyBindingDiagnostic diagnostics, Binder binder, TypeSymbol? type) + public BoundLambda Update(UnboundLambda unboundLambda, MethodSymbol symbol, BoundBlock body, ReadOnlyBindingDiagnostic diagnostics, Binder binder, TypeSymbol? type) { if (unboundLambda != this.UnboundLambda || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(symbol, this.Symbol) || body != this.Body || diagnostics != this.Diagnostics || binder != this.Binder || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) { @@ -10835,18 +10833,24 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor { public override BoundNode? VisitFieldEqualsValue(BoundFieldEqualsValue node) { + FieldSymbol field = this.VisitFieldSymbol(node.Field); + ImmutableArray locals = this.VisitLocals(node.Locals); BoundExpression value = (BoundExpression)this.Visit(node.Value); - return node.Update(node.Field, node.Locals, value); + return node.Update(field, locals, value); } public override BoundNode? VisitPropertyEqualsValue(BoundPropertyEqualsValue node) { + PropertySymbol property = this.VisitPropertySymbol(node.Property); + ImmutableArray locals = this.VisitLocals(node.Locals); BoundExpression value = (BoundExpression)this.Visit(node.Value); - return node.Update(node.Property, node.Locals, value); + return node.Update(property, locals, value); } public override BoundNode? VisitParameterEqualsValue(BoundParameterEqualsValue node) { + ParameterSymbol parameter = this.VisitParameterSymbol(node.Parameter); + ImmutableArray locals = this.VisitLocals(node.Locals); BoundExpression value = (BoundExpression)this.Visit(node.Value); - return node.Update(node.Parameter, node.Locals, value); + return node.Update(parameter, locals, value); } public override BoundNode? VisitGlobalStatementInitializer(BoundGlobalStatementInitializer node) { @@ -10866,8 +10870,9 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitDeconstructValuePlaceholder(BoundDeconstructValuePlaceholder node) { + Symbol? variableSymbol = this.VisitSymbol(node.VariableSymbol); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.VariableSymbol, node.IsDiscardExpression, type); + return node.Update(variableSymbol, node.IsDiscardExpression, type); } public override BoundNode? VisitTupleOperandPlaceholder(BoundTupleOperandPlaceholder node) { @@ -10932,9 +10937,10 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitBadExpression(BoundBadExpression node) { + ImmutableArray symbols = this.VisitSymbols(node.Symbols); ImmutableArray childBoundNodes = this.VisitList(node.ChildBoundNodes); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.ResultKind, node.Symbols, childBoundNodes, type); + return node.Update(node.ResultKind, symbols, childBoundNodes, type); } public override BoundNode? VisitBadStatement(BoundBadStatement node) { @@ -10948,10 +10954,11 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitTypeExpression(BoundTypeExpression node) { + AliasSymbol? aliasOpt = this.VisitAliasSymbol(node.AliasOpt); BoundTypeExpression? boundContainingTypeOpt = (BoundTypeExpression?)this.Visit(node.BoundContainingTypeOpt); ImmutableArray boundDimensionsOpt = this.VisitList(node.BoundDimensionsOpt); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.AliasOpt, boundContainingTypeOpt, boundDimensionsOpt, node.TypeWithAnnotations, type); + return node.Update(aliasOpt, boundContainingTypeOpt, boundDimensionsOpt, node.TypeWithAnnotations, type); } public override BoundNode? VisitTypeOrValueExpression(BoundTypeOrValueExpression node) { @@ -10960,18 +10967,24 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitNamespaceExpression(BoundNamespaceExpression node) { + NamespaceSymbol namespaceSymbol = this.VisitNamespaceSymbol(node.NamespaceSymbol); + AliasSymbol? aliasOpt = this.VisitAliasSymbol(node.AliasOpt); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.NamespaceSymbol, node.AliasOpt); + return node.Update(namespaceSymbol, aliasOpt); } public override BoundNode? VisitUnaryOperator(BoundUnaryOperator node) { + MethodSymbol? methodOpt = this.VisitMethodSymbol(node.MethodOpt); + ImmutableArray originalUserDefinedOperatorsOpt = this.VisitSymbols(node.OriginalUserDefinedOperatorsOpt); BoundExpression operand = (BoundExpression)this.Visit(node.Operand); TypeSymbol? constrainedToTypeOpt = this.VisitType(node.ConstrainedToTypeOpt); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.OperatorKind, operand, node.ConstantValueOpt, node.MethodOpt, constrainedToTypeOpt, node.ResultKind, node.OriginalUserDefinedOperatorsOpt, type); + return node.Update(node.OperatorKind, operand, node.ConstantValueOpt, methodOpt, constrainedToTypeOpt, node.ResultKind, originalUserDefinedOperatorsOpt, type); } public override BoundNode? VisitIncrementOperator(BoundIncrementOperator node) { + MethodSymbol? methodOpt = this.VisitMethodSymbol(node.MethodOpt); + ImmutableArray originalUserDefinedOperatorsOpt = this.VisitSymbols(node.OriginalUserDefinedOperatorsOpt); BoundExpression operand = (BoundExpression)this.Visit(node.Operand); BoundValuePlaceholder? operandPlaceholder = node.OperandPlaceholder; BoundExpression? operandConversion = node.OperandConversion; @@ -10979,7 +10992,7 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor BoundExpression? resultConversion = node.ResultConversion; TypeSymbol? constrainedToTypeOpt = this.VisitType(node.ConstrainedToTypeOpt); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.OperatorKind, operand, node.MethodOpt, constrainedToTypeOpt, operandPlaceholder, operandConversion, resultPlaceholder, resultConversion, node.ResultKind, node.OriginalUserDefinedOperatorsOpt, type); + return node.Update(node.OperatorKind, operand, methodOpt, constrainedToTypeOpt, operandPlaceholder, operandConversion, resultPlaceholder, resultConversion, node.ResultKind, originalUserDefinedOperatorsOpt, type); } public override BoundNode? VisitAddressOfOperator(BoundAddressOfOperator node) { @@ -10995,9 +11008,10 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitFunctionPointerLoad(BoundFunctionPointerLoad node) { + MethodSymbol targetMethod = this.VisitMethodSymbol(node.TargetMethod); TypeSymbol? constrainedToTypeOpt = this.VisitType(node.ConstrainedToTypeOpt); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.TargetMethod, constrainedToTypeOpt, type); + return node.Update(targetMethod, constrainedToTypeOpt, type); } public override BoundNode? VisitPointerIndirectionOperator(BoundPointerIndirectionOperator node) { @@ -11021,9 +11035,10 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitRefTypeOperator(BoundRefTypeOperator node) { + MethodSymbol? getTypeFromHandle = this.VisitMethodSymbol(node.GetTypeFromHandle); BoundExpression operand = (BoundExpression)this.Visit(node.Operand); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(operand, node.GetTypeFromHandle, type); + return node.Update(operand, getTypeFromHandle, type); } public override BoundNode? VisitMakeRefOperator(BoundMakeRefOperator node) { @@ -11039,16 +11054,18 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitFromEndIndexExpression(BoundFromEndIndexExpression node) { + MethodSymbol? methodOpt = this.VisitMethodSymbol(node.MethodOpt); BoundExpression operand = (BoundExpression)this.Visit(node.Operand); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(operand, node.MethodOpt, type); + return node.Update(operand, methodOpt, type); } public override BoundNode? VisitRangeExpression(BoundRangeExpression node) { + MethodSymbol? methodOpt = this.VisitMethodSymbol(node.MethodOpt); BoundExpression? leftOperandOpt = (BoundExpression?)this.Visit(node.LeftOperandOpt); BoundExpression? rightOperandOpt = (BoundExpression?)this.Visit(node.RightOperandOpt); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(leftOperandOpt, rightOperandOpt, node.MethodOpt, type); + return node.Update(leftOperandOpt, rightOperandOpt, methodOpt, type); } public override BoundNode? VisitBinaryOperator(BoundBinaryOperator node) { @@ -11066,14 +11083,19 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitUserDefinedConditionalLogicalOperator(BoundUserDefinedConditionalLogicalOperator node) { + MethodSymbol logicalOperator = this.VisitMethodSymbol(node.LogicalOperator); + MethodSymbol trueOperator = this.VisitMethodSymbol(node.TrueOperator); + MethodSymbol falseOperator = this.VisitMethodSymbol(node.FalseOperator); + ImmutableArray originalUserDefinedOperatorsOpt = this.VisitSymbols(node.OriginalUserDefinedOperatorsOpt); BoundExpression left = (BoundExpression)this.Visit(node.Left); BoundExpression right = (BoundExpression)this.Visit(node.Right); TypeSymbol? constrainedToTypeOpt = this.VisitType(node.ConstrainedToTypeOpt); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.OperatorKind, node.LogicalOperator, node.TrueOperator, node.FalseOperator, constrainedToTypeOpt, node.ResultKind, node.OriginalUserDefinedOperatorsOpt, left, right, type); + return node.Update(node.OperatorKind, logicalOperator, trueOperator, falseOperator, constrainedToTypeOpt, node.ResultKind, originalUserDefinedOperatorsOpt, left, right, type); } public override BoundNode? VisitCompoundAssignmentOperator(BoundCompoundAssignmentOperator node) { + ImmutableArray originalUserDefinedOperatorsOpt = this.VisitSymbols(node.OriginalUserDefinedOperatorsOpt); BoundExpression left = (BoundExpression)this.Visit(node.Left); BoundExpression right = (BoundExpression)this.Visit(node.Right); BoundValuePlaceholder? leftPlaceholder = node.LeftPlaceholder; @@ -11081,7 +11103,7 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor BoundValuePlaceholder? finalPlaceholder = node.FinalPlaceholder; BoundExpression? finalConversion = node.FinalConversion; TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.Operator, left, right, leftPlaceholder, leftConversion, finalPlaceholder, finalConversion, node.ResultKind, node.OriginalUserDefinedOperatorsOpt, type); + return node.Update(node.Operator, left, right, leftPlaceholder, leftConversion, finalPlaceholder, finalConversion, node.ResultKind, originalUserDefinedOperatorsOpt, type); } public override BoundNode? VisitAssignmentOperator(BoundAssignmentOperator node) { @@ -11151,9 +11173,11 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitAwaitableInfo(BoundAwaitableInfo node) { + PropertySymbol? isCompleted = this.VisitPropertySymbol(node.IsCompleted); + MethodSymbol? getResult = this.VisitMethodSymbol(node.GetResult); BoundAwaitableValuePlaceholder? awaitableInstancePlaceholder = (BoundAwaitableValuePlaceholder?)this.Visit(node.AwaitableInstancePlaceholder); BoundExpression? getAwaiter = (BoundExpression?)this.Visit(node.GetAwaiter); - return node.Update(awaitableInstancePlaceholder, node.IsDynamic, getAwaiter, node.IsCompleted, node.GetResult); + return node.Update(awaitableInstancePlaceholder, node.IsDynamic, getAwaiter, isCompleted, getResult); } public override BoundNode? VisitAwaitExpression(BoundAwaitExpression node) { @@ -11164,9 +11188,10 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitTypeOfOperator(BoundTypeOfOperator node) { + MethodSymbol? getTypeFromHandle = this.VisitMethodSymbol(node.GetTypeFromHandle); BoundTypeExpression sourceType = (BoundTypeExpression)this.Visit(node.SourceType); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(sourceType, node.GetTypeFromHandle, type); + return node.Update(sourceType, getTypeFromHandle, type); } public override BoundNode? VisitBlockInstrumentation(BoundBlockInstrumentation node) { @@ -11176,18 +11201,23 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitMethodDefIndex(BoundMethodDefIndex node) { + MethodSymbol method = this.VisitMethodSymbol(node.Method); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.Method, type); + return node.Update(method, type); } public override BoundNode? VisitLocalId(BoundLocalId node) { + LocalSymbol local = this.VisitLocalSymbol(node.Local); + FieldSymbol? hoistedField = this.VisitFieldSymbol(node.HoistedField); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.Local, node.HoistedField, type); + return node.Update(local, hoistedField, type); } public override BoundNode? VisitParameterId(BoundParameterId node) { + ParameterSymbol parameter = this.VisitParameterSymbol(node.Parameter); + FieldSymbol? hoistedField = this.VisitFieldSymbol(node.HoistedField); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.Parameter, node.HoistedField, type); + return node.Update(parameter, hoistedField, type); } public override BoundNode? VisitStateMachineInstanceId(BoundStateMachineInstanceId node) { @@ -11231,13 +11261,17 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitMethodInfo(BoundMethodInfo node) { + MethodSymbol method = this.VisitMethodSymbol(node.Method); + MethodSymbol? getMethodFromHandle = this.VisitMethodSymbol(node.GetMethodFromHandle); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.Method, node.GetMethodFromHandle, type); + return node.Update(method, getMethodFromHandle, type); } public override BoundNode? VisitFieldInfo(BoundFieldInfo node) { + FieldSymbol field = this.VisitFieldSymbol(node.Field); + MethodSymbol? getFieldFromHandle = this.VisitMethodSymbol(node.GetFieldFromHandle); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.Field, node.GetFieldFromHandle, type); + return node.Update(field, getFieldFromHandle, type); } public override BoundNode? VisitDefaultLiteral(BoundDefaultLiteral node) { @@ -11276,13 +11310,14 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor { BoundExpression operand = (BoundExpression)this.Visit(node.Operand); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(operand, node.Conversion, node.IsBaseConversion, node.Checked, node.ExplicitCastInCode, node.ConstantValueOpt, node.ConversionGroupOpt, node.OriginalUserDefinedConversionsOpt, type); + return node.Update(operand, node.Conversion, node.IsBaseConversion, node.Checked, node.ExplicitCastInCode, node.ConstantValueOpt, node.ConversionGroupOpt, type); } public override BoundNode? VisitReadOnlySpanFromArray(BoundReadOnlySpanFromArray node) { + MethodSymbol conversionMethod = this.VisitMethodSymbol(node.ConversionMethod); BoundExpression operand = (BoundExpression)this.Visit(node.Operand); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(operand, node.ConversionMethod, type); + return node.Update(operand, conversionMethod, type); } public override BoundNode? VisitArgList(BoundArgList node) { @@ -11297,12 +11332,13 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitFixedLocalCollectionInitializer(BoundFixedLocalCollectionInitializer node) { + MethodSymbol? getPinnableOpt = this.VisitMethodSymbol(node.GetPinnableOpt); BoundValuePlaceholder? elementPointerPlaceholder = node.ElementPointerPlaceholder; BoundExpression? elementPointerConversion = node.ElementPointerConversion; BoundExpression expression = (BoundExpression)this.Visit(node.Expression); TypeSymbol? elementPointerType = this.VisitType(node.ElementPointerType); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(elementPointerType, elementPointerPlaceholder, elementPointerConversion, expression, node.GetPinnableOpt, type); + return node.Update(elementPointerType, elementPointerPlaceholder, elementPointerConversion, expression, getPinnableOpt, type); } public override BoundNode? VisitSequencePoint(BoundSequencePoint node) { @@ -11319,26 +11355,31 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor public override BoundNode? VisitStepThroughSequencePoint(BoundStepThroughSequencePoint node) => node; public override BoundNode? VisitBlock(BoundBlock node) { + ImmutableArray locals = this.VisitLocals(node.Locals); + ImmutableArray localFunctions = this.VisitDeclaredLocalFunctions(node.LocalFunctions); BoundBlockInstrumentation? instrumentation = (BoundBlockInstrumentation?)this.Visit(node.Instrumentation); ImmutableArray statements = this.VisitList(node.Statements); - return node.Update(node.Locals, node.LocalFunctions, node.HasUnsafeModifier, instrumentation, statements); + return node.Update(locals, localFunctions, node.HasUnsafeModifier, instrumentation, statements); } public override BoundNode? VisitScope(BoundScope node) { + ImmutableArray locals = this.VisitLocals(node.Locals); ImmutableArray statements = this.VisitList(node.Statements); - return node.Update(node.Locals, statements); + return node.Update(locals, statements); } public override BoundNode? VisitStateMachineScope(BoundStateMachineScope node) { + ImmutableArray fields = this.VisitSymbols(node.Fields); BoundStatement statement = (BoundStatement)this.Visit(node.Statement); - return node.Update(node.Fields, statement); + return node.Update(fields, statement); } public override BoundNode? VisitLocalDeclaration(BoundLocalDeclaration node) { + LocalSymbol localSymbol = this.VisitLocalSymbol(node.LocalSymbol); BoundTypeExpression? declaredTypeOpt = (BoundTypeExpression?)this.Visit(node.DeclaredTypeOpt); BoundExpression? initializerOpt = (BoundExpression?)this.Visit(node.InitializerOpt); ImmutableArray argumentsOpt = this.VisitList(node.ArgumentsOpt); - return node.Update(node.LocalSymbol, declaredTypeOpt, initializerOpt, argumentsOpt, node.InferredType); + return node.Update(localSymbol, declaredTypeOpt, initializerOpt, argumentsOpt, node.InferredType); } public override BoundNode? VisitMultipleLocalDeclarations(BoundMultipleLocalDeclarations node) { @@ -11353,9 +11394,10 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitLocalFunctionStatement(BoundLocalFunctionStatement node) { + MethodSymbol symbol = this.VisitMethodSymbol(node.Symbol); BoundBlock? blockBody = (BoundBlock?)this.Visit(node.BlockBody); BoundBlock? expressionBody = (BoundBlock?)this.Visit(node.ExpressionBody); - return node.Update(node.Symbol, blockBody, expressionBody); + return node.Update(symbol, blockBody, expressionBody); } public override BoundNode? VisitNoOpStatement(BoundNoOpStatement node) => node; public override BoundNode? VisitReturnStatement(BoundReturnStatement node) @@ -11379,20 +11421,32 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor BoundExpression expression = (BoundExpression)this.Visit(node.Expression); return node.Update(expression); } - public override BoundNode? VisitBreakStatement(BoundBreakStatement node) => node; - public override BoundNode? VisitContinueStatement(BoundContinueStatement node) => node; + public override BoundNode? VisitBreakStatement(BoundBreakStatement node) + { + LabelSymbol label = this.VisitLabelSymbol(node.Label); + return node.Update(label); + } + public override BoundNode? VisitContinueStatement(BoundContinueStatement node) + { + LabelSymbol label = this.VisitLabelSymbol(node.Label); + return node.Update(label); + } public override BoundNode? VisitSwitchStatement(BoundSwitchStatement node) { + ImmutableArray innerLocals = this.VisitLocals(node.InnerLocals); + ImmutableArray innerLocalFunctions = this.VisitDeclaredLocalFunctions(node.InnerLocalFunctions); + LabelSymbol breakLabel = this.VisitLabelSymbol(node.BreakLabel); BoundExpression expression = (BoundExpression)this.Visit(node.Expression); ImmutableArray switchSections = this.VisitList(node.SwitchSections); BoundDecisionDag reachabilityDecisionDag = node.ReachabilityDecisionDag; BoundSwitchLabel? defaultLabel = (BoundSwitchLabel?)this.Visit(node.DefaultLabel); - return node.Update(expression, node.InnerLocals, node.InnerLocalFunctions, switchSections, reachabilityDecisionDag, defaultLabel, node.BreakLabel); + return node.Update(expression, innerLocals, innerLocalFunctions, switchSections, reachabilityDecisionDag, defaultLabel, breakLabel); } public override BoundNode? VisitSwitchDispatch(BoundSwitchDispatch node) { + LabelSymbol defaultLabel = this.VisitLabelSymbol(node.DefaultLabel); BoundExpression expression = (BoundExpression)this.Visit(node.Expression); - return node.Update(expression, node.Cases, node.DefaultLabel, node.LengthBasedStringSwitchDataOpt); + return node.Update(expression, node.Cases, defaultLabel, node.LengthBasedStringSwitchDataOpt); } public override BoundNode? VisitIfStatement(BoundIfStatement node) { @@ -11403,26 +11457,39 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitDoStatement(BoundDoStatement node) { + ImmutableArray locals = this.VisitLocals(node.Locals); + LabelSymbol breakLabel = this.VisitLabelSymbol(node.BreakLabel); + LabelSymbol continueLabel = this.VisitLabelSymbol(node.ContinueLabel); BoundExpression condition = (BoundExpression)this.Visit(node.Condition); BoundStatement body = (BoundStatement)this.Visit(node.Body); - return node.Update(node.Locals, condition, body, node.BreakLabel, node.ContinueLabel); + return node.Update(locals, condition, body, breakLabel, continueLabel); } public override BoundNode? VisitWhileStatement(BoundWhileStatement node) { + ImmutableArray locals = this.VisitLocals(node.Locals); + LabelSymbol breakLabel = this.VisitLabelSymbol(node.BreakLabel); + LabelSymbol continueLabel = this.VisitLabelSymbol(node.ContinueLabel); BoundExpression condition = (BoundExpression)this.Visit(node.Condition); BoundStatement body = (BoundStatement)this.Visit(node.Body); - return node.Update(node.Locals, condition, body, node.BreakLabel, node.ContinueLabel); + return node.Update(locals, condition, body, breakLabel, continueLabel); } public override BoundNode? VisitForStatement(BoundForStatement node) { + ImmutableArray outerLocals = this.VisitLocals(node.OuterLocals); + ImmutableArray innerLocals = this.VisitLocals(node.InnerLocals); + LabelSymbol breakLabel = this.VisitLabelSymbol(node.BreakLabel); + LabelSymbol continueLabel = this.VisitLabelSymbol(node.ContinueLabel); BoundStatement? initializer = (BoundStatement?)this.Visit(node.Initializer); BoundExpression? condition = (BoundExpression?)this.Visit(node.Condition); BoundStatement? increment = (BoundStatement?)this.Visit(node.Increment); BoundStatement body = (BoundStatement)this.Visit(node.Body); - return node.Update(node.OuterLocals, initializer, node.InnerLocals, condition, increment, body, node.BreakLabel, node.ContinueLabel); + return node.Update(outerLocals, initializer, innerLocals, condition, increment, body, breakLabel, continueLabel); } public override BoundNode? VisitForEachStatement(BoundForEachStatement node) { + ImmutableArray iterationVariables = this.VisitLocals(node.IterationVariables); + LabelSymbol breakLabel = this.VisitLabelSymbol(node.BreakLabel); + LabelSymbol continueLabel = this.VisitLabelSymbol(node.ContinueLabel); BoundValuePlaceholder? elementPlaceholder = node.ElementPlaceholder; BoundExpression? elementConversion = node.ElementConversion; BoundTypeExpression iterationVariableType = (BoundTypeExpression)this.Visit(node.IterationVariableType); @@ -11431,7 +11498,7 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor BoundForEachDeconstructStep? deconstructionOpt = (BoundForEachDeconstructStep?)this.Visit(node.DeconstructionOpt); BoundAwaitableInfo? awaitOpt = (BoundAwaitableInfo?)this.Visit(node.AwaitOpt); BoundStatement body = (BoundStatement)this.Visit(node.Body); - return node.Update(node.EnumeratorInfoOpt, elementPlaceholder, elementConversion, iterationVariableType, node.IterationVariables, iterationErrorExpressionOpt, expression, deconstructionOpt, awaitOpt, body, node.BreakLabel, node.ContinueLabel); + return node.Update(node.EnumeratorInfoOpt, elementPlaceholder, elementConversion, iterationVariableType, iterationVariables, iterationErrorExpressionOpt, expression, deconstructionOpt, awaitOpt, body, breakLabel, continueLabel); } public override BoundNode? VisitForEachDeconstructStep(BoundForEachDeconstructStep node) { @@ -11441,17 +11508,19 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitUsingStatement(BoundUsingStatement node) { + ImmutableArray locals = this.VisitLocals(node.Locals); BoundMultipleLocalDeclarations? declarationsOpt = (BoundMultipleLocalDeclarations?)this.Visit(node.DeclarationsOpt); BoundExpression? expressionOpt = (BoundExpression?)this.Visit(node.ExpressionOpt); BoundStatement body = (BoundStatement)this.Visit(node.Body); BoundAwaitableInfo? awaitOpt = (BoundAwaitableInfo?)this.Visit(node.AwaitOpt); - return node.Update(node.Locals, declarationsOpt, expressionOpt, body, awaitOpt, node.PatternDisposeInfoOpt); + return node.Update(locals, declarationsOpt, expressionOpt, body, awaitOpt, node.PatternDisposeInfoOpt); } public override BoundNode? VisitFixedStatement(BoundFixedStatement node) { + ImmutableArray locals = this.VisitLocals(node.Locals); BoundMultipleLocalDeclarations declarations = (BoundMultipleLocalDeclarations)this.Visit(node.Declarations); BoundStatement body = (BoundStatement)this.Visit(node.Body); - return node.Update(node.Locals, declarations, body); + return node.Update(locals, declarations, body); } public override BoundNode? VisitLockStatement(BoundLockStatement node) { @@ -11461,19 +11530,21 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitTryStatement(BoundTryStatement node) { + LabelSymbol? finallyLabelOpt = this.VisitLabelSymbol(node.FinallyLabelOpt); BoundBlock tryBlock = (BoundBlock)this.Visit(node.TryBlock); ImmutableArray catchBlocks = this.VisitList(node.CatchBlocks); BoundBlock? finallyBlockOpt = (BoundBlock?)this.Visit(node.FinallyBlockOpt); - return node.Update(tryBlock, catchBlocks, finallyBlockOpt, node.FinallyLabelOpt, node.PreferFaultHandler); + return node.Update(tryBlock, catchBlocks, finallyBlockOpt, finallyLabelOpt, node.PreferFaultHandler); } public override BoundNode? VisitCatchBlock(BoundCatchBlock node) { + ImmutableArray locals = this.VisitLocals(node.Locals); BoundExpression? exceptionSourceOpt = (BoundExpression?)this.Visit(node.ExceptionSourceOpt); BoundStatementList? exceptionFilterPrologueOpt = (BoundStatementList?)this.Visit(node.ExceptionFilterPrologueOpt); BoundExpression? exceptionFilterOpt = (BoundExpression?)this.Visit(node.ExceptionFilterOpt); BoundBlock body = (BoundBlock)this.Visit(node.Body); TypeSymbol? exceptionTypeOpt = this.VisitType(node.ExceptionTypeOpt); - return node.Update(node.Locals, exceptionSourceOpt, exceptionTypeOpt, exceptionFilterPrologueOpt, exceptionFilterOpt, body, node.IsSynthesizedAsyncCatchAll); + return node.Update(locals, exceptionSourceOpt, exceptionTypeOpt, exceptionFilterPrologueOpt, exceptionFilterOpt, body, node.IsSynthesizedAsyncCatchAll); } public override BoundNode? VisitLiteral(BoundLiteral node) { @@ -11507,41 +11578,52 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitLocal(BoundLocal node) { + LocalSymbol localSymbol = this.VisitLocalSymbol(node.LocalSymbol); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.LocalSymbol, node.DeclarationKind, node.ConstantValueOpt, node.IsNullableUnknown, type); + return node.Update(localSymbol, node.DeclarationKind, node.ConstantValueOpt, node.IsNullableUnknown, type); } public override BoundNode? VisitPseudoVariable(BoundPseudoVariable node) { + LocalSymbol localSymbol = this.VisitLocalSymbol(node.LocalSymbol); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.LocalSymbol, node.EmitExpressions, type); + return node.Update(localSymbol, node.EmitExpressions, type); } public override BoundNode? VisitRangeVariable(BoundRangeVariable node) { + RangeVariableSymbol rangeVariableSymbol = this.VisitRangeVariableSymbol(node.RangeVariableSymbol); BoundExpression value = (BoundExpression)this.Visit(node.Value); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.RangeVariableSymbol, value, type); + return node.Update(rangeVariableSymbol, value, type); } public override BoundNode? VisitParameter(BoundParameter node) { + ParameterSymbol parameterSymbol = this.VisitParameterSymbol(node.ParameterSymbol); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.ParameterSymbol, type); + return node.Update(parameterSymbol, type); + } + public override BoundNode? VisitLabelStatement(BoundLabelStatement node) + { + LabelSymbol label = this.VisitLabelSymbol(node.Label); + return node.Update(label); } - public override BoundNode? VisitLabelStatement(BoundLabelStatement node) => node; public override BoundNode? VisitGotoStatement(BoundGotoStatement node) { + LabelSymbol label = this.VisitLabelSymbol(node.Label); BoundExpression? caseExpressionOpt = (BoundExpression?)this.Visit(node.CaseExpressionOpt); BoundLabel? labelExpressionOpt = (BoundLabel?)this.Visit(node.LabelExpressionOpt); - return node.Update(node.Label, caseExpressionOpt, labelExpressionOpt); + return node.Update(label, caseExpressionOpt, labelExpressionOpt); } public override BoundNode? VisitLabeledStatement(BoundLabeledStatement node) { + LabelSymbol label = this.VisitLabelSymbol(node.Label); BoundStatement body = (BoundStatement)this.Visit(node.Body); - return node.Update(node.Label, body); + return node.Update(label, body); } public override BoundNode? VisitLabel(BoundLabel node) { + LabelSymbol label = this.VisitLabelSymbol(node.Label); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.Label, type); + return node.Update(label, type); } public override BoundNode? VisitStatementList(BoundStatementList node) { @@ -11550,32 +11632,37 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitConditionalGoto(BoundConditionalGoto node) { + LabelSymbol label = this.VisitLabelSymbol(node.Label); BoundExpression condition = (BoundExpression)this.Visit(node.Condition); - return node.Update(condition, node.JumpIfTrue, node.Label); + return node.Update(condition, node.JumpIfTrue, label); } public override BoundNode? VisitSwitchExpressionArm(BoundSwitchExpressionArm node) { + ImmutableArray locals = this.VisitLocals(node.Locals); + LabelSymbol label = this.VisitLabelSymbol(node.Label); BoundPattern pattern = (BoundPattern)this.Visit(node.Pattern); BoundExpression? whenClause = (BoundExpression?)this.Visit(node.WhenClause); BoundExpression value = (BoundExpression)this.Visit(node.Value); - return node.Update(node.Locals, pattern, whenClause, value, node.Label); + return node.Update(locals, pattern, whenClause, value, label); } public override BoundNode? VisitUnconvertedSwitchExpression(BoundUnconvertedSwitchExpression node) { + LabelSymbol? defaultLabel = this.VisitLabelSymbol(node.DefaultLabel); BoundExpression expression = (BoundExpression)this.Visit(node.Expression); ImmutableArray switchArms = this.VisitList(node.SwitchArms); BoundDecisionDag reachabilityDecisionDag = node.ReachabilityDecisionDag; TypeSymbol? type = this.VisitType(node.Type); - return node.Update(expression, switchArms, reachabilityDecisionDag, node.DefaultLabel, node.ReportedNotExhaustive, type); + return node.Update(expression, switchArms, reachabilityDecisionDag, defaultLabel, node.ReportedNotExhaustive, type); } public override BoundNode? VisitConvertedSwitchExpression(BoundConvertedSwitchExpression node) { + LabelSymbol? defaultLabel = this.VisitLabelSymbol(node.DefaultLabel); BoundExpression expression = (BoundExpression)this.Visit(node.Expression); ImmutableArray switchArms = this.VisitList(node.SwitchArms); BoundDecisionDag reachabilityDecisionDag = node.ReachabilityDecisionDag; TypeSymbol? naturalTypeOpt = this.VisitType(node.NaturalTypeOpt); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(naturalTypeOpt, node.WasTargetTyped, expression, switchArms, reachabilityDecisionDag, node.DefaultLabel, node.ReportedNotExhaustive, type); + return node.Update(naturalTypeOpt, node.WasTargetTyped, expression, switchArms, reachabilityDecisionDag, defaultLabel, node.ReportedNotExhaustive, type); } public override BoundNode? VisitDecisionDag(BoundDecisionDag node) { @@ -11602,7 +11689,11 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor BoundDecisionDagNode? whenFalse = (BoundDecisionDagNode?)this.Visit(node.WhenFalse); return node.Update(node.Bindings, whenExpression, whenTrue, whenFalse); } - public override BoundNode? VisitLeafDecisionDagNode(BoundLeafDecisionDagNode node) => node; + public override BoundNode? VisitLeafDecisionDagNode(BoundLeafDecisionDagNode node) + { + LabelSymbol label = this.VisitLabelSymbol(node.Label); + return node.Update(label); + } public override BoundNode? VisitDagTemp(BoundDagTemp node) { BoundDagEvaluation? source = (BoundDagEvaluation?)this.Visit(node.Source); @@ -11637,8 +11728,9 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitDagDeconstructEvaluation(BoundDagDeconstructEvaluation node) { + MethodSymbol deconstructMethod = this.VisitMethodSymbol(node.DeconstructMethod); BoundDagTemp input = (BoundDagTemp)this.Visit(node.Input); - return node.Update(node.DeconstructMethod, input); + return node.Update(deconstructMethod, input); } public override BoundNode? VisitDagTypeEvaluation(BoundDagTypeEvaluation node) { @@ -11648,18 +11740,21 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitDagFieldEvaluation(BoundDagFieldEvaluation node) { + FieldSymbol field = this.VisitFieldSymbol(node.Field); BoundDagTemp input = (BoundDagTemp)this.Visit(node.Input); - return node.Update(node.Field, input); + return node.Update(field, input); } public override BoundNode? VisitDagPropertyEvaluation(BoundDagPropertyEvaluation node) { + PropertySymbol property = this.VisitPropertySymbol(node.Property); BoundDagTemp input = (BoundDagTemp)this.Visit(node.Input); - return node.Update(node.Property, node.IsLengthOrCount, input); + return node.Update(property, node.IsLengthOrCount, input); } public override BoundNode? VisitDagIndexEvaluation(BoundDagIndexEvaluation node) { + PropertySymbol property = this.VisitPropertySymbol(node.Property); BoundDagTemp input = (BoundDagTemp)this.Visit(node.Input); - return node.Update(node.Property, node.Index, input); + return node.Update(property, node.Index, input); } public override BoundNode? VisitDagIndexerEvaluation(BoundDagIndexerEvaluation node) { @@ -11689,15 +11784,17 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitSwitchSection(BoundSwitchSection node) { + ImmutableArray locals = this.VisitLocals(node.Locals); ImmutableArray switchLabels = this.VisitList(node.SwitchLabels); ImmutableArray statements = this.VisitList(node.Statements); - return node.Update(node.Locals, switchLabels, statements); + return node.Update(locals, switchLabels, statements); } public override BoundNode? VisitSwitchLabel(BoundSwitchLabel node) { + LabelSymbol label = this.VisitLabelSymbol(node.Label); BoundPattern pattern = (BoundPattern)this.Visit(node.Pattern); BoundExpression? whenClause = (BoundExpression?)this.Visit(node.WhenClause); - return node.Update(node.Label, pattern, whenClause); + return node.Update(label, pattern, whenClause); } public override BoundNode? VisitSequencePointExpression(BoundSequencePointExpression node) { @@ -11707,17 +11804,19 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitSequence(BoundSequence node) { + ImmutableArray locals = this.VisitLocals(node.Locals); ImmutableArray sideEffects = this.VisitList(node.SideEffects); BoundExpression value = (BoundExpression)this.Visit(node.Value); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.Locals, sideEffects, value, type); + return node.Update(locals, sideEffects, value, type); } public override BoundNode? VisitSpillSequence(BoundSpillSequence node) { + ImmutableArray locals = this.VisitLocals(node.Locals); ImmutableArray sideEffects = this.VisitList(node.SideEffects); BoundExpression value = (BoundExpression)this.Visit(node.Value); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.Locals, sideEffects, value, type); + return node.Update(locals, sideEffects, value, type); } public override BoundNode? VisitDynamicMemberAccess(BoundDynamicMemberAccess node) { @@ -11727,10 +11826,11 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitDynamicInvocation(BoundDynamicInvocation node) { + ImmutableArray applicableMethods = this.VisitSymbols(node.ApplicableMethods); BoundExpression expression = (BoundExpression)this.Visit(node.Expression); ImmutableArray arguments = this.VisitList(node.Arguments); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, node.ApplicableMethods, expression, arguments, type); + return node.Update(node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, applicableMethods, expression, arguments, type); } public override BoundNode? VisitConditionalAccess(BoundConditionalAccess node) { @@ -11741,11 +11841,12 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitLoweredConditionalAccess(BoundLoweredConditionalAccess node) { + MethodSymbol? hasValueMethodOpt = this.VisitMethodSymbol(node.HasValueMethodOpt); BoundExpression receiver = (BoundExpression)this.Visit(node.Receiver); BoundExpression whenNotNull = (BoundExpression)this.Visit(node.WhenNotNull); BoundExpression? whenNullOpt = (BoundExpression?)this.Visit(node.WhenNullOpt); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(receiver, node.HasValueMethodOpt, whenNotNull, whenNullOpt, node.Id, node.ForceCopyOfNullableValueType, type); + return node.Update(receiver, hasValueMethodOpt, whenNotNull, whenNullOpt, node.Id, node.ForceCopyOfNullableValueType, type); } public override BoundNode? VisitConditionalReceiver(BoundConditionalReceiver node) { @@ -11761,36 +11862,44 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitMethodGroup(BoundMethodGroup node) { + ImmutableArray methods = this.VisitSymbols(node.Methods); + Symbol? lookupSymbolOpt = this.VisitSymbol(node.LookupSymbolOpt); + FunctionTypeSymbol? functionType = this.VisitFunctionTypeSymbol(node.FunctionType); BoundExpression? receiverOpt = (BoundExpression?)this.Visit(node.ReceiverOpt); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.TypeArgumentsOpt, node.Name, node.Methods, node.LookupSymbolOpt, node.LookupError, node.Flags, node.FunctionType, receiverOpt, node.ResultKind); + return node.Update(node.TypeArgumentsOpt, node.Name, methods, lookupSymbolOpt, node.LookupError, node.Flags, functionType, receiverOpt, node.ResultKind); } public override BoundNode? VisitPropertyGroup(BoundPropertyGroup node) { + ImmutableArray properties = this.VisitSymbols(node.Properties); BoundExpression? receiverOpt = (BoundExpression?)this.Visit(node.ReceiverOpt); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.Properties, receiverOpt, node.ResultKind); + return node.Update(properties, receiverOpt, node.ResultKind); } public override BoundNode? VisitCall(BoundCall node) { + MethodSymbol method = this.VisitMethodSymbol(node.Method); + ImmutableArray originalMethodsOpt = this.VisitSymbols(node.OriginalMethodsOpt); BoundExpression? receiverOpt = (BoundExpression?)this.Visit(node.ReceiverOpt); ImmutableArray arguments = this.VisitList(node.Arguments); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(receiverOpt, node.InitialBindingReceiverIsSubjectToCloning, node.Method, arguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, node.IsDelegateCall, node.Expanded, node.InvokedAsExtensionMethod, node.ArgsToParamsOpt, node.DefaultArguments, node.ResultKind, node.OriginalMethodsOpt, type); + return node.Update(receiverOpt, node.InitialBindingReceiverIsSubjectToCloning, method, arguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, node.IsDelegateCall, node.Expanded, node.InvokedAsExtensionMethod, node.ArgsToParamsOpt, node.DefaultArguments, node.ResultKind, originalMethodsOpt, type); } public override BoundNode? VisitEventAssignmentOperator(BoundEventAssignmentOperator node) { + EventSymbol @event = this.VisitEventSymbol(node.Event); BoundExpression? receiverOpt = (BoundExpression?)this.Visit(node.ReceiverOpt); BoundExpression argument = (BoundExpression)this.Visit(node.Argument); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.Event, node.IsAddition, node.IsDynamic, receiverOpt, argument, type); + return node.Update(@event, node.IsAddition, node.IsDynamic, receiverOpt, argument, type); } public override BoundNode? VisitAttribute(BoundAttribute node) { + MethodSymbol? constructor = this.VisitMethodSymbol(node.Constructor); ImmutableArray constructorArguments = this.VisitList(node.ConstructorArguments); ImmutableArray namedArguments = this.VisitList(node.NamedArguments); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.Constructor, constructorArguments, node.ConstructorArgumentNamesOpt, node.ConstructorArgumentsToParamsOpt, node.ConstructorExpanded, node.ConstructorDefaultArguments, namedArguments, node.ResultKind, type); + return node.Update(constructor, constructorArguments, node.ConstructorArgumentNamesOpt, node.ConstructorArgumentsToParamsOpt, node.ConstructorExpanded, node.ConstructorDefaultArguments, namedArguments, node.ResultKind, type); } public override BoundNode? VisitUnconvertedObjectCreationExpression(BoundUnconvertedObjectCreationExpression node) { @@ -11800,10 +11909,12 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitObjectCreationExpression(BoundObjectCreationExpression node) { + MethodSymbol constructor = this.VisitMethodSymbol(node.Constructor); + ImmutableArray constructorsGroup = this.VisitSymbols(node.ConstructorsGroup); ImmutableArray arguments = this.VisitList(node.Arguments); BoundObjectInitializerExpressionBase? initializerExpressionOpt = (BoundObjectInitializerExpressionBase?)this.Visit(node.InitializerExpressionOpt); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.Constructor, node.ConstructorsGroup, arguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, node.Expanded, node.ArgsToParamsOpt, node.DefaultArguments, node.ConstantValueOpt, initializerExpressionOpt, node.WasTargetTyped, type); + return node.Update(constructor, constructorsGroup, arguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, node.Expanded, node.ArgsToParamsOpt, node.DefaultArguments, node.ConstantValueOpt, initializerExpressionOpt, node.WasTargetTyped, type); } public override BoundNode? VisitUnconvertedCollectionExpression(BoundUnconvertedCollectionExpression node) { @@ -11813,6 +11924,7 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitCollectionExpression(BoundCollectionExpression node) { + MethodSymbol? collectionBuilderMethod = this.VisitMethodSymbol(node.CollectionBuilderMethod); BoundObjectOrCollectionValuePlaceholder? placeholder = node.Placeholder; BoundExpression? collectionCreation = node.CollectionCreation; BoundValuePlaceholder? collectionBuilderInvocationPlaceholder = node.CollectionBuilderInvocationPlaceholder; @@ -11820,7 +11932,7 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor BoundUnconvertedCollectionExpression unconvertedCollectionExpression = node.UnconvertedCollectionExpression; ImmutableArray elements = this.VisitList(node.Elements); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.CollectionTypeKind, placeholder, collectionCreation, node.CollectionBuilderMethod, collectionBuilderInvocationPlaceholder, collectionBuilderInvocationConversion, node.WasTargetTyped, unconvertedCollectionExpression, elements, type); + return node.Update(node.CollectionTypeKind, placeholder, collectionCreation, collectionBuilderMethod, collectionBuilderInvocationPlaceholder, collectionBuilderInvocationConversion, node.WasTargetTyped, unconvertedCollectionExpression, elements, type); } public override BoundNode? VisitCollectionExpressionSpreadExpressionPlaceholder(BoundCollectionExpressionSpreadExpressionPlaceholder node) { @@ -11852,10 +11964,11 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitDynamicObjectCreationExpression(BoundDynamicObjectCreationExpression node) { + ImmutableArray applicableMethods = this.VisitSymbols(node.ApplicableMethods); ImmutableArray arguments = this.VisitList(node.Arguments); BoundObjectInitializerExpressionBase? initializerExpressionOpt = (BoundObjectInitializerExpressionBase?)this.Visit(node.InitializerExpressionOpt); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.Name, arguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, initializerExpressionOpt, node.ApplicableMethods, node.WasTargetTyped, type); + return node.Update(node.Name, arguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, initializerExpressionOpt, applicableMethods, node.WasTargetTyped, type); } public override BoundNode? VisitNoPiaObjectCreationExpression(BoundNoPiaObjectCreationExpression node) { @@ -11872,10 +11985,11 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitObjectInitializerMember(BoundObjectInitializerMember node) { + Symbol? memberSymbol = this.VisitSymbol(node.MemberSymbol); ImmutableArray arguments = this.VisitList(node.Arguments); TypeSymbol? receiverType = this.VisitType(node.ReceiverType); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.MemberSymbol, arguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, node.Expanded, node.ArgsToParamsOpt, node.DefaultArguments, node.ResultKind, node.AccessorKind, receiverType, type); + return node.Update(memberSymbol, arguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, node.Expanded, node.ArgsToParamsOpt, node.DefaultArguments, node.ResultKind, node.AccessorKind, receiverType, type); } public override BoundNode? VisitDynamicObjectInitializerMember(BoundDynamicObjectInitializerMember node) { @@ -11892,17 +12006,19 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitCollectionElementInitializer(BoundCollectionElementInitializer node) { + MethodSymbol addMethod = this.VisitMethodSymbol(node.AddMethod); ImmutableArray arguments = this.VisitList(node.Arguments); BoundExpression? implicitReceiverOpt = (BoundExpression?)this.Visit(node.ImplicitReceiverOpt); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.AddMethod, arguments, implicitReceiverOpt, node.Expanded, node.ArgsToParamsOpt, node.DefaultArguments, node.InvokedAsExtensionMethod, node.ResultKind, type); + return node.Update(addMethod, arguments, implicitReceiverOpt, node.Expanded, node.ArgsToParamsOpt, node.DefaultArguments, node.InvokedAsExtensionMethod, node.ResultKind, type); } public override BoundNode? VisitDynamicCollectionElementInitializer(BoundDynamicCollectionElementInitializer node) { + ImmutableArray applicableMethods = this.VisitSymbols(node.ApplicableMethods); BoundExpression expression = (BoundExpression)this.Visit(node.Expression); ImmutableArray arguments = this.VisitList(node.Arguments); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.ApplicableMethods, expression, arguments, type); + return node.Update(applicableMethods, expression, arguments, type); } public override BoundNode? VisitImplicitReceiver(BoundImplicitReceiver node) { @@ -11911,15 +12027,17 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitAnonymousObjectCreationExpression(BoundAnonymousObjectCreationExpression node) { + MethodSymbol constructor = this.VisitMethodSymbol(node.Constructor); ImmutableArray arguments = this.VisitList(node.Arguments); ImmutableArray declarations = this.VisitList(node.Declarations); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.Constructor, arguments, declarations, type); + return node.Update(constructor, arguments, declarations, type); } public override BoundNode? VisitAnonymousPropertyDeclaration(BoundAnonymousPropertyDeclaration node) { + PropertySymbol property = this.VisitPropertySymbol(node.Property); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.Property, type); + return node.Update(property, type); } public override BoundNode? VisitNewT(BoundNewT node) { @@ -11929,9 +12047,10 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitDelegateCreationExpression(BoundDelegateCreationExpression node) { + MethodSymbol? methodOpt = this.VisitMethodSymbol(node.MethodOpt); BoundExpression argument = (BoundExpression)this.Visit(node.Argument); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(argument, node.MethodOpt, node.IsExtensionMethod, node.WasTargetTyped, type); + return node.Update(argument, methodOpt, node.IsExtensionMethod, node.WasTargetTyped, type); } public override BoundNode? VisitArrayCreation(BoundArrayCreation node) { @@ -11964,33 +12083,39 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitFieldAccess(BoundFieldAccess node) { + FieldSymbol fieldSymbol = this.VisitFieldSymbol(node.FieldSymbol); BoundExpression? receiverOpt = (BoundExpression?)this.Visit(node.ReceiverOpt); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(receiverOpt, node.FieldSymbol, node.ConstantValueOpt, node.ResultKind, node.IsByValue, node.IsDeclaration, type); + return node.Update(receiverOpt, fieldSymbol, node.ConstantValueOpt, node.ResultKind, node.IsByValue, node.IsDeclaration, type); } public override BoundNode? VisitHoistedFieldAccess(BoundHoistedFieldAccess node) { + FieldSymbol fieldSymbol = this.VisitFieldSymbol(node.FieldSymbol); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.FieldSymbol, type); + return node.Update(fieldSymbol, type); } public override BoundNode? VisitPropertyAccess(BoundPropertyAccess node) { + PropertySymbol propertySymbol = this.VisitPropertySymbol(node.PropertySymbol); BoundExpression? receiverOpt = (BoundExpression?)this.Visit(node.ReceiverOpt); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(receiverOpt, node.InitialBindingReceiverIsSubjectToCloning, node.PropertySymbol, node.AutoPropertyAccessorKind, node.ResultKind, type); + return node.Update(receiverOpt, node.InitialBindingReceiverIsSubjectToCloning, propertySymbol, node.AutoPropertyAccessorKind, node.ResultKind, type); } public override BoundNode? VisitEventAccess(BoundEventAccess node) { + EventSymbol eventSymbol = this.VisitEventSymbol(node.EventSymbol); BoundExpression? receiverOpt = (BoundExpression?)this.Visit(node.ReceiverOpt); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(receiverOpt, node.EventSymbol, node.IsUsableAsField, node.ResultKind, type); + return node.Update(receiverOpt, eventSymbol, node.IsUsableAsField, node.ResultKind, type); } public override BoundNode? VisitIndexerAccess(BoundIndexerAccess node) { + PropertySymbol indexer = this.VisitPropertySymbol(node.Indexer); + ImmutableArray originalIndexersOpt = this.VisitSymbols(node.OriginalIndexersOpt); BoundExpression? receiverOpt = (BoundExpression?)this.Visit(node.ReceiverOpt); ImmutableArray arguments = this.VisitList(node.Arguments); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(receiverOpt, node.InitialBindingReceiverIsSubjectToCloning, node.Indexer, arguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, node.Expanded, node.AccessorKind, node.ArgsToParamsOpt, node.DefaultArguments, node.OriginalIndexersOpt, type); + return node.Update(receiverOpt, node.InitialBindingReceiverIsSubjectToCloning, indexer, arguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, node.Expanded, node.AccessorKind, node.ArgsToParamsOpt, node.DefaultArguments, originalIndexersOpt, type); } public override BoundNode? VisitImplicitIndexerAccess(BoundImplicitIndexerAccess node) { @@ -12012,31 +12137,35 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitDynamicIndexerAccess(BoundDynamicIndexerAccess node) { + ImmutableArray applicableIndexers = this.VisitSymbols(node.ApplicableIndexers); BoundExpression receiver = (BoundExpression)this.Visit(node.Receiver); ImmutableArray arguments = this.VisitList(node.Arguments); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(receiver, arguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, node.ApplicableIndexers, type); + return node.Update(receiver, arguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, applicableIndexers, type); } public override BoundNode? VisitLambda(BoundLambda node) { + MethodSymbol symbol = this.VisitMethodSymbol(node.Symbol); UnboundLambda unboundLambda = node.UnboundLambda; BoundBlock body = (BoundBlock)this.Visit(node.Body); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(unboundLambda, node.Symbol, body, node.Diagnostics, node.Binder, type); + return node.Update(unboundLambda, symbol, body, node.Diagnostics, node.Binder, type); } public override BoundNode? VisitUnboundLambda(UnboundLambda node) { + FunctionTypeSymbol? functionType = this.VisitFunctionTypeSymbol(node.FunctionType); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.Data, node.FunctionType, node.WithDependencies); + return node.Update(node.Data, functionType, node.WithDependencies); } public override BoundNode? VisitQueryClause(BoundQueryClause node) { + RangeVariableSymbol? definedSymbol = this.VisitRangeVariableSymbol(node.DefinedSymbol); BoundExpression value = (BoundExpression)this.Visit(node.Value); BoundExpression? operation = node.Operation; BoundExpression? cast = node.Cast; BoundExpression? unoptimizedForm = node.UnoptimizedForm; TypeSymbol? type = this.VisitType(node.Type); - return node.Update(value, node.DefinedSymbol, operation, cast, node.Binder, unoptimizedForm, type); + return node.Update(value, definedSymbol, operation, cast, node.Binder, unoptimizedForm, type); } public override BoundNode? VisitTypeOrInstanceInitializers(BoundTypeOrInstanceInitializers node) { @@ -12081,11 +12210,13 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitIsPatternExpression(BoundIsPatternExpression node) { + LabelSymbol whenTrueLabel = this.VisitLabelSymbol(node.WhenTrueLabel); + LabelSymbol whenFalseLabel = this.VisitLabelSymbol(node.WhenFalseLabel); BoundExpression expression = (BoundExpression)this.Visit(node.Expression); BoundPattern pattern = (BoundPattern)this.Visit(node.Pattern); BoundDecisionDag reachabilityDecisionDag = node.ReachabilityDecisionDag; TypeSymbol? type = this.VisitType(node.Type); - return node.Update(expression, pattern, node.IsNegated, reachabilityDecisionDag, node.WhenTrueLabel, node.WhenFalseLabel, type); + return node.Update(expression, pattern, node.IsNegated, reachabilityDecisionDag, whenTrueLabel, whenFalseLabel, type); } public override BoundNode? VisitConstantPattern(BoundConstantPattern node) { @@ -12102,24 +12233,28 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitDeclarationPattern(BoundDeclarationPattern node) { + Symbol? variable = this.VisitSymbol(node.Variable); BoundTypeExpression declaredType = (BoundTypeExpression)this.Visit(node.DeclaredType); BoundExpression? variableAccess = (BoundExpression?)this.Visit(node.VariableAccess); TypeSymbol? inputType = this.VisitType(node.InputType); TypeSymbol? narrowedType = this.VisitType(node.NarrowedType); - return node.Update(declaredType, node.IsVar, node.Variable, variableAccess, inputType, narrowedType); + return node.Update(declaredType, node.IsVar, variable, variableAccess, inputType, narrowedType); } public override BoundNode? VisitRecursivePattern(BoundRecursivePattern node) { + MethodSymbol? deconstructMethod = this.VisitMethodSymbol(node.DeconstructMethod); + Symbol? variable = this.VisitSymbol(node.Variable); BoundTypeExpression? declaredType = (BoundTypeExpression?)this.Visit(node.DeclaredType); ImmutableArray deconstruction = this.VisitList(node.Deconstruction); ImmutableArray properties = this.VisitList(node.Properties); BoundExpression? variableAccess = (BoundExpression?)this.Visit(node.VariableAccess); TypeSymbol? inputType = this.VisitType(node.InputType); TypeSymbol? narrowedType = this.VisitType(node.NarrowedType); - return node.Update(declaredType, node.DeconstructMethod, deconstruction, properties, node.IsExplicitNotNullTest, node.Variable, variableAccess, inputType, narrowedType); + return node.Update(declaredType, deconstructMethod, deconstruction, properties, node.IsExplicitNotNullTest, variable, variableAccess, inputType, narrowedType); } public override BoundNode? VisitListPattern(BoundListPattern node) { + Symbol? variable = this.VisitSymbol(node.Variable); ImmutableArray subpatterns = this.VisitList(node.Subpatterns); BoundExpression? lengthAccess = node.LengthAccess; BoundExpression? indexerAccess = node.IndexerAccess; @@ -12128,7 +12263,7 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor BoundExpression? variableAccess = (BoundExpression?)this.Visit(node.VariableAccess); TypeSymbol? inputType = this.VisitType(node.InputType); TypeSymbol? narrowedType = this.VisitType(node.NarrowedType); - return node.Update(subpatterns, node.HasSlice, lengthAccess, indexerAccess, receiverPlaceholder, argumentPlaceholder, node.Variable, variableAccess, inputType, narrowedType); + return node.Update(subpatterns, node.HasSlice, lengthAccess, indexerAccess, receiverPlaceholder, argumentPlaceholder, variable, variableAccess, inputType, narrowedType); } public override BoundNode? VisitSlicePattern(BoundSlicePattern node) { @@ -12142,15 +12277,18 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitITuplePattern(BoundITuplePattern node) { + MethodSymbol getLengthMethod = this.VisitMethodSymbol(node.GetLengthMethod); + MethodSymbol getItemMethod = this.VisitMethodSymbol(node.GetItemMethod); ImmutableArray subpatterns = this.VisitList(node.Subpatterns); TypeSymbol? inputType = this.VisitType(node.InputType); TypeSymbol? narrowedType = this.VisitType(node.NarrowedType); - return node.Update(node.GetLengthMethod, node.GetItemMethod, subpatterns, inputType, narrowedType); + return node.Update(getLengthMethod, getItemMethod, subpatterns, inputType, narrowedType); } public override BoundNode? VisitPositionalSubpattern(BoundPositionalSubpattern node) { + Symbol? symbol = this.VisitSymbol(node.Symbol); BoundPattern pattern = (BoundPattern)this.Visit(node.Pattern); - return node.Update(node.Symbol, pattern); + return node.Update(symbol, pattern); } public override BoundNode? VisitPropertySubpattern(BoundPropertySubpattern node) { @@ -12160,9 +12298,10 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitPropertySubpatternMember(BoundPropertySubpatternMember node) { + Symbol? symbol = this.VisitSymbol(node.Symbol); BoundPropertySubpatternMember? receiver = (BoundPropertySubpatternMember?)this.Visit(node.Receiver); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(receiver, node.Symbol, type); + return node.Update(receiver, symbol, type); } public override BoundNode? VisitTypePattern(BoundTypePattern node) { @@ -12206,20 +12345,23 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitOutVariablePendingInference(OutVariablePendingInference node) { + Symbol variableSymbol = this.VisitSymbol(node.VariableSymbol); BoundExpression? receiverOpt = (BoundExpression?)this.Visit(node.ReceiverOpt); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.VariableSymbol, receiverOpt); + return node.Update(variableSymbol, receiverOpt); } public override BoundNode? VisitDeconstructionVariablePendingInference(DeconstructionVariablePendingInference node) { + Symbol variableSymbol = this.VisitSymbol(node.VariableSymbol); BoundExpression? receiverOpt = (BoundExpression?)this.Visit(node.ReceiverOpt); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.VariableSymbol, receiverOpt); + return node.Update(variableSymbol, receiverOpt); } public override BoundNode? VisitOutDeconstructVarPendingInference(OutDeconstructVarPendingInference node) { + Symbol? variableSymbol = this.VisitSymbol(node.VariableSymbol); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.VariableSymbol, node.IsDiscardExpression); + return node.Update(variableSymbol, node.IsDiscardExpression); } public override BoundNode? VisitNonConstructorMethodBody(BoundNonConstructorMethodBody node) { @@ -12229,10 +12371,11 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitConstructorMethodBody(BoundConstructorMethodBody node) { + ImmutableArray locals = this.VisitLocals(node.Locals); BoundStatement? initializer = (BoundStatement?)this.Visit(node.Initializer); BoundBlock? blockBody = (BoundBlock?)this.Visit(node.BlockBody); BoundBlock? expressionBody = (BoundBlock?)this.Visit(node.ExpressionBody); - return node.Update(node.Locals, initializer, blockBody, expressionBody); + return node.Update(locals, initializer, blockBody, expressionBody); } public override BoundNode? VisitExpressionWithNullability(BoundExpressionWithNullability node) { @@ -12242,10 +12385,11 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor } public override BoundNode? VisitWithExpression(BoundWithExpression node) { + MethodSymbol? cloneMethod = this.VisitMethodSymbol(node.CloneMethod); BoundExpression receiver = (BoundExpression)this.Visit(node.Receiver); BoundObjectInitializerExpressionBase initializerExpression = (BoundObjectInitializerExpressionBase)this.Visit(node.InitializerExpression); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(receiver, node.CloneMethod, initializerExpression, type); + return node.Update(receiver, cloneMethod, initializerExpression, type); } } @@ -13301,18 +13445,17 @@ public NullabilityRewriter(ImmutableDictionary originalUserDefinedConversionsOpt = GetUpdatedArray(node, node.OriginalUserDefinedConversionsOpt); BoundExpression operand = (BoundExpression)this.Visit(node.Operand); BoundConversion updatedNode; if (_updatedNullabilities.TryGetValue(node, out (NullabilityInfo Info, TypeSymbol? Type) infoAndType)) { - updatedNode = node.Update(operand, node.Conversion, node.IsBaseConversion, node.Checked, node.ExplicitCastInCode, node.ConstantValueOpt, node.ConversionGroupOpt, node.OriginalUserDefinedConversionsOpt, infoAndType.Type!); + updatedNode = node.Update(operand, node.Conversion, node.IsBaseConversion, node.Checked, node.ExplicitCastInCode, node.ConstantValueOpt, node.ConversionGroupOpt, infoAndType.Type!); updatedNode.TopLevelNullability = infoAndType.Info; } else { - updatedNode = node.Update(operand, node.Conversion, node.IsBaseConversion, node.Checked, node.ExplicitCastInCode, node.ConstantValueOpt, node.ConversionGroupOpt, node.OriginalUserDefinedConversionsOpt, node.Type); + updatedNode = node.Update(operand, node.Conversion, node.IsBaseConversion, node.Checked, node.ExplicitCastInCode, node.ConstantValueOpt, node.ConversionGroupOpt, node.Type); } return updatedNode; } @@ -13388,7 +13531,7 @@ public NullabilityRewriter(ImmutableDictionary locals = GetUpdatedArray(node, node.Locals); - ImmutableArray localFunctions = GetUpdatedArray(node, node.LocalFunctions); + ImmutableArray localFunctions = GetUpdatedArray(node, node.LocalFunctions); BoundBlockInstrumentation? instrumentation = (BoundBlockInstrumentation?)this.Visit(node.Instrumentation); ImmutableArray statements = this.VisitList(node.Statements); return node.Update(locals, localFunctions, node.HasUnsafeModifier, instrumentation, statements); @@ -13419,7 +13562,7 @@ public NullabilityRewriter(ImmutableDictionary innerLocals = GetUpdatedArray(node, node.InnerLocals); - ImmutableArray innerLocalFunctions = GetUpdatedArray(node, node.InnerLocalFunctions); + ImmutableArray innerLocalFunctions = GetUpdatedArray(node, node.InnerLocalFunctions); BoundExpression expression = (BoundExpression)this.Visit(node.Expression); ImmutableArray switchSections = this.VisitList(node.SwitchSections); BoundDecisionDag reachabilityDecisionDag = node.ReachabilityDecisionDag; @@ -14576,7 +14719,7 @@ public NullabilityRewriter(ImmutableDictionaryGets the identifier. - public abstract SyntaxToken Identifier { get; } + public abstract SyntaxToken? Identifier { get; } /// Gets the base type list. public abstract BaseListSyntax? BaseList { get; } @@ -16524,7 +16524,7 @@ internal BaseTypeDeclarationSyntax(SyntaxKind kind) public abstract SyntaxToken? SemicolonToken { get; } } -/// Base class for type declaration syntax (class, struct, interface, record). +/// Base class for type declaration syntax (class, struct, interface, record, extension). internal abstract partial class TypeDeclarationSyntax : BaseTypeDeclarationSyntax { internal TypeDeclarationSyntax(SyntaxKind kind, DiagnosticInfo[]? diagnostics, SyntaxAnnotation[]? annotations) @@ -16537,7 +16537,7 @@ internal TypeDeclarationSyntax(SyntaxKind kind) { } - /// Gets the type keyword token ("class", "struct", "interface", "record"). + /// Gets the type keyword token ("class", "struct", "interface", "record", "extension"). public abstract SyntaxToken Keyword { get; } public abstract TypeParameterListSyntax? TypeParameterList { get; } @@ -18109,6 +18109,236 @@ internal override GreenNode SetAnnotations(SyntaxAnnotation[]? annotations) => new EnumMemberDeclarationSyntax(this.Kind, this.attributeLists, this.modifiers, this.identifier, this.equalsValue, GetDiagnostics(), annotations); } +/// Extension container syntax. +internal sealed partial class ExtensionDeclarationSyntax : TypeDeclarationSyntax +{ + internal readonly GreenNode? attributeLists; + internal readonly GreenNode? modifiers; + internal readonly SyntaxToken keyword; + internal readonly TypeParameterListSyntax? typeParameterList; + internal readonly ParameterListSyntax? parameterList; + internal readonly GreenNode? constraintClauses; + internal readonly SyntaxToken? openBraceToken; + internal readonly GreenNode? members; + internal readonly SyntaxToken? closeBraceToken; + internal readonly SyntaxToken? semicolonToken; + + internal ExtensionDeclarationSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, SyntaxToken keyword, TypeParameterListSyntax? typeParameterList, ParameterListSyntax? parameterList, GreenNode? constraintClauses, SyntaxToken? openBraceToken, GreenNode? members, SyntaxToken? closeBraceToken, SyntaxToken? semicolonToken, DiagnosticInfo[]? diagnostics, SyntaxAnnotation[]? annotations) + : base(kind, diagnostics, annotations) + { + this.SlotCount = 10; + if (attributeLists != null) + { + this.AdjustFlagsAndWidth(attributeLists); + this.attributeLists = attributeLists; + } + if (modifiers != null) + { + this.AdjustFlagsAndWidth(modifiers); + this.modifiers = modifiers; + } + this.AdjustFlagsAndWidth(keyword); + this.keyword = keyword; + if (typeParameterList != null) + { + this.AdjustFlagsAndWidth(typeParameterList); + this.typeParameterList = typeParameterList; + } + if (parameterList != null) + { + this.AdjustFlagsAndWidth(parameterList); + this.parameterList = parameterList; + } + if (constraintClauses != null) + { + this.AdjustFlagsAndWidth(constraintClauses); + this.constraintClauses = constraintClauses; + } + if (openBraceToken != null) + { + this.AdjustFlagsAndWidth(openBraceToken); + this.openBraceToken = openBraceToken; + } + if (members != null) + { + this.AdjustFlagsAndWidth(members); + this.members = members; + } + if (closeBraceToken != null) + { + this.AdjustFlagsAndWidth(closeBraceToken); + this.closeBraceToken = closeBraceToken; + } + if (semicolonToken != null) + { + this.AdjustFlagsAndWidth(semicolonToken); + this.semicolonToken = semicolonToken; + } + } + + internal ExtensionDeclarationSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, SyntaxToken keyword, TypeParameterListSyntax? typeParameterList, ParameterListSyntax? parameterList, GreenNode? constraintClauses, SyntaxToken? openBraceToken, GreenNode? members, SyntaxToken? closeBraceToken, SyntaxToken? semicolonToken, SyntaxFactoryContext context) + : base(kind) + { + this.SetFactoryContext(context); + this.SlotCount = 10; + if (attributeLists != null) + { + this.AdjustFlagsAndWidth(attributeLists); + this.attributeLists = attributeLists; + } + if (modifiers != null) + { + this.AdjustFlagsAndWidth(modifiers); + this.modifiers = modifiers; + } + this.AdjustFlagsAndWidth(keyword); + this.keyword = keyword; + if (typeParameterList != null) + { + this.AdjustFlagsAndWidth(typeParameterList); + this.typeParameterList = typeParameterList; + } + if (parameterList != null) + { + this.AdjustFlagsAndWidth(parameterList); + this.parameterList = parameterList; + } + if (constraintClauses != null) + { + this.AdjustFlagsAndWidth(constraintClauses); + this.constraintClauses = constraintClauses; + } + if (openBraceToken != null) + { + this.AdjustFlagsAndWidth(openBraceToken); + this.openBraceToken = openBraceToken; + } + if (members != null) + { + this.AdjustFlagsAndWidth(members); + this.members = members; + } + if (closeBraceToken != null) + { + this.AdjustFlagsAndWidth(closeBraceToken); + this.closeBraceToken = closeBraceToken; + } + if (semicolonToken != null) + { + this.AdjustFlagsAndWidth(semicolonToken); + this.semicolonToken = semicolonToken; + } + } + + internal ExtensionDeclarationSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, SyntaxToken keyword, TypeParameterListSyntax? typeParameterList, ParameterListSyntax? parameterList, GreenNode? constraintClauses, SyntaxToken? openBraceToken, GreenNode? members, SyntaxToken? closeBraceToken, SyntaxToken? semicolonToken) + : base(kind) + { + this.SlotCount = 10; + if (attributeLists != null) + { + this.AdjustFlagsAndWidth(attributeLists); + this.attributeLists = attributeLists; + } + if (modifiers != null) + { + this.AdjustFlagsAndWidth(modifiers); + this.modifiers = modifiers; + } + this.AdjustFlagsAndWidth(keyword); + this.keyword = keyword; + if (typeParameterList != null) + { + this.AdjustFlagsAndWidth(typeParameterList); + this.typeParameterList = typeParameterList; + } + if (parameterList != null) + { + this.AdjustFlagsAndWidth(parameterList); + this.parameterList = parameterList; + } + if (constraintClauses != null) + { + this.AdjustFlagsAndWidth(constraintClauses); + this.constraintClauses = constraintClauses; + } + if (openBraceToken != null) + { + this.AdjustFlagsAndWidth(openBraceToken); + this.openBraceToken = openBraceToken; + } + if (members != null) + { + this.AdjustFlagsAndWidth(members); + this.members = members; + } + if (closeBraceToken != null) + { + this.AdjustFlagsAndWidth(closeBraceToken); + this.closeBraceToken = closeBraceToken; + } + if (semicolonToken != null) + { + this.AdjustFlagsAndWidth(semicolonToken); + this.semicolonToken = semicolonToken; + } + } + + public override CoreSyntax.SyntaxList AttributeLists => new CoreSyntax.SyntaxList(this.attributeLists); + public override CoreSyntax.SyntaxList Modifiers => new CoreSyntax.SyntaxList(this.modifiers); + public override SyntaxToken Keyword => this.keyword; + public override TypeParameterListSyntax? TypeParameterList => this.typeParameterList; + public override ParameterListSyntax? ParameterList => this.parameterList; + public override CoreSyntax.SyntaxList ConstraintClauses => new CoreSyntax.SyntaxList(this.constraintClauses); + public override SyntaxToken? OpenBraceToken => this.openBraceToken; + public override CoreSyntax.SyntaxList Members => new CoreSyntax.SyntaxList(this.members); + public override SyntaxToken? CloseBraceToken => this.closeBraceToken; + public override SyntaxToken? SemicolonToken => this.semicolonToken; + + internal override GreenNode? GetSlot(int index) + => index switch + { + 0 => this.attributeLists, + 1 => this.modifiers, + 2 => this.keyword, + 3 => this.typeParameterList, + 4 => this.parameterList, + 5 => this.constraintClauses, + 6 => this.openBraceToken, + 7 => this.members, + 8 => this.closeBraceToken, + 9 => this.semicolonToken, + _ => null, + }; + + internal override SyntaxNode CreateRed(SyntaxNode? parent, int position) => new CSharp.Syntax.ExtensionDeclarationSyntax(this, parent, position); + + public override void Accept(CSharpSyntaxVisitor visitor) => visitor.VisitExtensionDeclaration(this); + public override TResult Accept(CSharpSyntaxVisitor visitor) => visitor.VisitExtensionDeclaration(this); + + public ExtensionDeclarationSyntax Update(CoreSyntax.SyntaxList attributeLists, CoreSyntax.SyntaxList modifiers, SyntaxToken keyword, TypeParameterListSyntax typeParameterList, ParameterListSyntax parameterList, CoreSyntax.SyntaxList constraintClauses, SyntaxToken openBraceToken, CoreSyntax.SyntaxList members, SyntaxToken closeBraceToken, SyntaxToken semicolonToken) + { + if (attributeLists != this.AttributeLists || modifiers != this.Modifiers || keyword != this.Keyword || typeParameterList != this.TypeParameterList || parameterList != this.ParameterList || constraintClauses != this.ConstraintClauses || openBraceToken != this.OpenBraceToken || members != this.Members || closeBraceToken != this.CloseBraceToken || semicolonToken != this.SemicolonToken) + { + var newNode = SyntaxFactory.ExtensionDeclaration(attributeLists, modifiers, keyword, typeParameterList, parameterList, constraintClauses, openBraceToken, members, closeBraceToken, semicolonToken); + var diags = GetDiagnostics(); + if (diags?.Length > 0) + newNode = newNode.WithDiagnosticsGreen(diags); + var annotations = GetAnnotations(); + if (annotations?.Length > 0) + newNode = newNode.WithAnnotationsGreen(annotations); + return newNode; + } + + return this; + } + + internal override GreenNode SetDiagnostics(DiagnosticInfo[]? diagnostics) + => new ExtensionDeclarationSyntax(this.Kind, this.attributeLists, this.modifiers, this.keyword, this.typeParameterList, this.parameterList, this.constraintClauses, this.openBraceToken, this.members, this.closeBraceToken, this.semicolonToken, diagnostics, GetAnnotations()); + + internal override GreenNode SetAnnotations(SyntaxAnnotation[]? annotations) + => new ExtensionDeclarationSyntax(this.Kind, this.attributeLists, this.modifiers, this.keyword, this.typeParameterList, this.parameterList, this.constraintClauses, this.openBraceToken, this.members, this.closeBraceToken, this.semicolonToken, GetDiagnostics(), annotations); +} + /// Base list syntax. internal sealed partial class BaseListSyntax : CSharpSyntaxNode { @@ -21618,10 +21848,10 @@ internal sealed partial class ParameterSyntax : BaseParameterSyntax internal readonly GreenNode? attributeLists; internal readonly GreenNode? modifiers; internal readonly TypeSyntax? type; - internal readonly SyntaxToken identifier; + internal readonly SyntaxToken? identifier; internal readonly EqualsValueClauseSyntax? @default; - internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, TypeSyntax? type, SyntaxToken identifier, EqualsValueClauseSyntax? @default, DiagnosticInfo[]? diagnostics, SyntaxAnnotation[]? annotations) + internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, TypeSyntax? type, SyntaxToken? identifier, EqualsValueClauseSyntax? @default, DiagnosticInfo[]? diagnostics, SyntaxAnnotation[]? annotations) : base(kind, diagnostics, annotations) { this.SlotCount = 5; @@ -21640,8 +21870,11 @@ internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? this.AdjustFlagsAndWidth(type); this.type = type; } - this.AdjustFlagsAndWidth(identifier); - this.identifier = identifier; + if (identifier != null) + { + this.AdjustFlagsAndWidth(identifier); + this.identifier = identifier; + } if (@default != null) { this.AdjustFlagsAndWidth(@default); @@ -21649,7 +21882,7 @@ internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? } } - internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, TypeSyntax? type, SyntaxToken identifier, EqualsValueClauseSyntax? @default, SyntaxFactoryContext context) + internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, TypeSyntax? type, SyntaxToken? identifier, EqualsValueClauseSyntax? @default, SyntaxFactoryContext context) : base(kind) { this.SetFactoryContext(context); @@ -21669,8 +21902,11 @@ internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? this.AdjustFlagsAndWidth(type); this.type = type; } - this.AdjustFlagsAndWidth(identifier); - this.identifier = identifier; + if (identifier != null) + { + this.AdjustFlagsAndWidth(identifier); + this.identifier = identifier; + } if (@default != null) { this.AdjustFlagsAndWidth(@default); @@ -21678,7 +21914,7 @@ internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? } } - internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, TypeSyntax? type, SyntaxToken identifier, EqualsValueClauseSyntax? @default) + internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, TypeSyntax? type, SyntaxToken? identifier, EqualsValueClauseSyntax? @default) : base(kind) { this.SlotCount = 5; @@ -21697,8 +21933,11 @@ internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? this.AdjustFlagsAndWidth(type); this.type = type; } - this.AdjustFlagsAndWidth(identifier); - this.identifier = identifier; + if (identifier != null) + { + this.AdjustFlagsAndWidth(identifier); + this.identifier = identifier; + } if (@default != null) { this.AdjustFlagsAndWidth(@default); @@ -21712,7 +21951,7 @@ internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? public override CoreSyntax.SyntaxList Modifiers => new CoreSyntax.SyntaxList(this.modifiers); public override TypeSyntax? Type => this.type; /// Gets the identifier. - public SyntaxToken Identifier => this.identifier; + public SyntaxToken? Identifier => this.identifier; public EqualsValueClauseSyntax? Default => this.@default; internal override GreenNode? GetSlot(int index) @@ -26654,6 +26893,7 @@ internal partial class CSharpSyntaxVisitor public virtual TResult VisitEnumDeclaration(EnumDeclarationSyntax node) => this.DefaultVisit(node); public virtual TResult VisitDelegateDeclaration(DelegateDeclarationSyntax node) => this.DefaultVisit(node); public virtual TResult VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) => this.DefaultVisit(node); + public virtual TResult VisitExtensionDeclaration(ExtensionDeclarationSyntax node) => this.DefaultVisit(node); public virtual TResult VisitBaseList(BaseListSyntax node) => this.DefaultVisit(node); public virtual TResult VisitSimpleBaseType(SimpleBaseTypeSyntax node) => this.DefaultVisit(node); public virtual TResult VisitPrimaryConstructorBaseType(PrimaryConstructorBaseTypeSyntax node) => this.DefaultVisit(node); @@ -26902,6 +27142,7 @@ internal partial class CSharpSyntaxVisitor public virtual void VisitEnumDeclaration(EnumDeclarationSyntax node) => this.DefaultVisit(node); public virtual void VisitDelegateDeclaration(DelegateDeclarationSyntax node) => this.DefaultVisit(node); public virtual void VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) => this.DefaultVisit(node); + public virtual void VisitExtensionDeclaration(ExtensionDeclarationSyntax node) => this.DefaultVisit(node); public virtual void VisitBaseList(BaseListSyntax node) => this.DefaultVisit(node); public virtual void VisitSimpleBaseType(SimpleBaseTypeSyntax node) => this.DefaultVisit(node); public virtual void VisitPrimaryConstructorBaseType(PrimaryConstructorBaseTypeSyntax node) => this.DefaultVisit(node); @@ -27490,6 +27731,9 @@ public override CSharpSyntaxNode VisitDelegateDeclaration(DelegateDeclarationSyn public override CSharpSyntaxNode VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) => node.Update(VisitList(node.AttributeLists), VisitList(node.Modifiers), (SyntaxToken)Visit(node.Identifier), (EqualsValueClauseSyntax)Visit(node.EqualsValue)); + public override CSharpSyntaxNode VisitExtensionDeclaration(ExtensionDeclarationSyntax node) + => node.Update(VisitList(node.AttributeLists), VisitList(node.Modifiers), (SyntaxToken)Visit(node.Keyword), (TypeParameterListSyntax)Visit(node.TypeParameterList), (ParameterListSyntax)Visit(node.ParameterList), VisitList(node.ConstraintClauses), (SyntaxToken)Visit(node.OpenBraceToken), VisitList(node.Members), (SyntaxToken)Visit(node.CloseBraceToken), (SyntaxToken)Visit(node.SemicolonToken)); + public override CSharpSyntaxNode VisitBaseList(BaseListSyntax node) => node.Update((SyntaxToken)Visit(node.ColonToken), VisitList(node.Types)); @@ -31416,6 +31660,43 @@ public EnumMemberDeclarationSyntax EnumMemberDeclaration(CoreSyntax.SyntaxList attributeLists, CoreSyntax.SyntaxList modifiers, SyntaxToken keyword, TypeParameterListSyntax? typeParameterList, ParameterListSyntax? parameterList, CoreSyntax.SyntaxList constraintClauses, SyntaxToken? openBraceToken, CoreSyntax.SyntaxList members, SyntaxToken? closeBraceToken, SyntaxToken? semicolonToken) + { +#if DEBUG + if (keyword == null) throw new ArgumentNullException(nameof(keyword)); + if (keyword.Kind != SyntaxKind.ExtensionKeyword) throw new ArgumentException(nameof(keyword)); + if (openBraceToken != null) + { + switch (openBraceToken.Kind) + { + case SyntaxKind.OpenBraceToken: + case SyntaxKind.None: break; + default: throw new ArgumentException(nameof(openBraceToken)); + } + } + if (closeBraceToken != null) + { + switch (closeBraceToken.Kind) + { + case SyntaxKind.CloseBraceToken: + case SyntaxKind.None: break; + default: throw new ArgumentException(nameof(closeBraceToken)); + } + } + if (semicolonToken != null) + { + switch (semicolonToken.Kind) + { + case SyntaxKind.SemicolonToken: + case SyntaxKind.None: break; + default: throw new ArgumentException(nameof(semicolonToken)); + } + } +#endif + + return new ExtensionDeclarationSyntax(SyntaxKind.ExtensionDeclaration, attributeLists.Node, modifiers.Node, keyword, typeParameterList, parameterList, constraintClauses.Node, openBraceToken, members.Node, closeBraceToken, semicolonToken, this.context); + } + public BaseListSyntax BaseList(SyntaxToken colonToken, CoreSyntax.SeparatedSyntaxList types) { #if DEBUG @@ -32059,15 +32340,18 @@ public BracketedParameterListSyntax BracketedParameterList(SyntaxToken openBrack return result; } - public ParameterSyntax Parameter(CoreSyntax.SyntaxList attributeLists, CoreSyntax.SyntaxList modifiers, TypeSyntax? type, SyntaxToken identifier, EqualsValueClauseSyntax? @default) + public ParameterSyntax Parameter(CoreSyntax.SyntaxList attributeLists, CoreSyntax.SyntaxList modifiers, TypeSyntax? type, SyntaxToken? identifier, EqualsValueClauseSyntax? @default) { #if DEBUG - if (identifier == null) throw new ArgumentNullException(nameof(identifier)); - switch (identifier.Kind) + if (identifier != null) { - case SyntaxKind.IdentifierToken: - case SyntaxKind.ArgListKeyword: break; - default: throw new ArgumentException(nameof(identifier)); + switch (identifier.Kind) + { + case SyntaxKind.IdentifierToken: + case SyntaxKind.ArgListKeyword: + case SyntaxKind.None: break; + default: throw new ArgumentException(nameof(identifier)); + } } #endif @@ -36684,6 +36968,43 @@ public static EnumMemberDeclarationSyntax EnumMemberDeclaration(CoreSyntax.Synta return new EnumMemberDeclarationSyntax(SyntaxKind.EnumMemberDeclaration, attributeLists.Node, modifiers.Node, identifier, equalsValue); } + public static ExtensionDeclarationSyntax ExtensionDeclaration(CoreSyntax.SyntaxList attributeLists, CoreSyntax.SyntaxList modifiers, SyntaxToken keyword, TypeParameterListSyntax? typeParameterList, ParameterListSyntax? parameterList, CoreSyntax.SyntaxList constraintClauses, SyntaxToken? openBraceToken, CoreSyntax.SyntaxList members, SyntaxToken? closeBraceToken, SyntaxToken? semicolonToken) + { +#if DEBUG + if (keyword == null) throw new ArgumentNullException(nameof(keyword)); + if (keyword.Kind != SyntaxKind.ExtensionKeyword) throw new ArgumentException(nameof(keyword)); + if (openBraceToken != null) + { + switch (openBraceToken.Kind) + { + case SyntaxKind.OpenBraceToken: + case SyntaxKind.None: break; + default: throw new ArgumentException(nameof(openBraceToken)); + } + } + if (closeBraceToken != null) + { + switch (closeBraceToken.Kind) + { + case SyntaxKind.CloseBraceToken: + case SyntaxKind.None: break; + default: throw new ArgumentException(nameof(closeBraceToken)); + } + } + if (semicolonToken != null) + { + switch (semicolonToken.Kind) + { + case SyntaxKind.SemicolonToken: + case SyntaxKind.None: break; + default: throw new ArgumentException(nameof(semicolonToken)); + } + } +#endif + + return new ExtensionDeclarationSyntax(SyntaxKind.ExtensionDeclaration, attributeLists.Node, modifiers.Node, keyword, typeParameterList, parameterList, constraintClauses.Node, openBraceToken, members.Node, closeBraceToken, semicolonToken); + } + public static BaseListSyntax BaseList(SyntaxToken colonToken, CoreSyntax.SeparatedSyntaxList types) { #if DEBUG @@ -37327,15 +37648,18 @@ public static BracketedParameterListSyntax BracketedParameterList(SyntaxToken op return result; } - public static ParameterSyntax Parameter(CoreSyntax.SyntaxList attributeLists, CoreSyntax.SyntaxList modifiers, TypeSyntax? type, SyntaxToken identifier, EqualsValueClauseSyntax? @default) + public static ParameterSyntax Parameter(CoreSyntax.SyntaxList attributeLists, CoreSyntax.SyntaxList modifiers, TypeSyntax? type, SyntaxToken? identifier, EqualsValueClauseSyntax? @default) { #if DEBUG - if (identifier == null) throw new ArgumentNullException(nameof(identifier)); - switch (identifier.Kind) + if (identifier != null) { - case SyntaxKind.IdentifierToken: - case SyntaxKind.ArgListKeyword: break; - default: throw new ArgumentException(nameof(identifier)); + switch (identifier.Kind) + { + case SyntaxKind.IdentifierToken: + case SyntaxKind.ArgListKeyword: + case SyntaxKind.None: break; + default: throw new ArgumentException(nameof(identifier)); + } } #endif diff --git a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs index 0b31bde257994..66df0106254e3 100644 --- a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs @@ -525,6 +525,9 @@ public partial class CSharpSyntaxVisitor /// Called when the visitor visits a EnumMemberDeclarationSyntax node. public virtual TResult? VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) => this.DefaultVisit(node); + /// Called when the visitor visits a ExtensionDeclarationSyntax node. + public virtual TResult? VisitExtensionDeclaration(ExtensionDeclarationSyntax node) => this.DefaultVisit(node); + /// Called when the visitor visits a BaseListSyntax node. public virtual TResult? VisitBaseList(BaseListSyntax node) => this.DefaultVisit(node); @@ -1260,6 +1263,9 @@ public partial class CSharpSyntaxVisitor /// Called when the visitor visits a EnumMemberDeclarationSyntax node. public virtual void VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) => this.DefaultVisit(node); + /// Called when the visitor visits a ExtensionDeclarationSyntax node. + public virtual void VisitExtensionDeclaration(ExtensionDeclarationSyntax node) => this.DefaultVisit(node); + /// Called when the visitor visits a BaseListSyntax node. public virtual void VisitBaseList(BaseListSyntax node) => this.DefaultVisit(node); @@ -1995,6 +2001,9 @@ public partial class CSharpSyntaxRewriter : CSharpSyntaxVisitor public override SyntaxNode? VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) => node.Update(VisitList(node.AttributeLists), VisitList(node.Modifiers), VisitToken(node.Identifier), (EqualsValueClauseSyntax?)Visit(node.EqualsValue)); + public override SyntaxNode? VisitExtensionDeclaration(ExtensionDeclarationSyntax node) + => node.Update(VisitList(node.AttributeLists), VisitList(node.Modifiers), VisitToken(node.Keyword), (TypeParameterListSyntax?)Visit(node.TypeParameterList), (ParameterListSyntax?)Visit(node.ParameterList), VisitList(node.ConstraintClauses), VisitToken(node.OpenBraceToken), VisitList(node.Members), VisitToken(node.CloseBraceToken), VisitToken(node.SemicolonToken)); + public override SyntaxNode? VisitBaseList(BaseListSyntax node) => node.Update(VisitToken(node.ColonToken), VisitList(node.Types)); @@ -3196,14 +3205,6 @@ public static SimpleLambdaExpressionSyntax SimpleLambdaExpression(SyntaxList(), modifiers.Node.ToGreenList(), (Syntax.InternalSyntax.ParameterSyntax)parameter.Green, (Syntax.InternalSyntax.SyntaxToken)arrowToken.Node!, block == null ? null : (Syntax.InternalSyntax.BlockSyntax)block.Green, expressionBody == null ? null : (Syntax.InternalSyntax.ExpressionSyntax)expressionBody.Green).CreateRed(); } - /// Creates a new SimpleLambdaExpressionSyntax instance. - public static SimpleLambdaExpressionSyntax SimpleLambdaExpression(SyntaxList attributeLists, SyntaxTokenList modifiers, ParameterSyntax parameter, BlockSyntax? block, ExpressionSyntax? expressionBody) - => SyntaxFactory.SimpleLambdaExpression(attributeLists, modifiers, parameter, SyntaxFactory.Token(SyntaxKind.EqualsGreaterThanToken), block, expressionBody); - - /// Creates a new SimpleLambdaExpressionSyntax instance. - public static SimpleLambdaExpressionSyntax SimpleLambdaExpression(ParameterSyntax parameter) - => SyntaxFactory.SimpleLambdaExpression(default, default(SyntaxTokenList), parameter, SyntaxFactory.Token(SyntaxKind.EqualsGreaterThanToken), default, default); - /// Creates a new RefExpressionSyntax instance. public static RefExpressionSyntax RefExpression(SyntaxToken refKeyword, ExpressionSyntax expression) { @@ -5146,6 +5147,39 @@ public static EnumMemberDeclarationSyntax EnumMemberDeclaration(SyntaxToken iden public static EnumMemberDeclarationSyntax EnumMemberDeclaration(string identifier) => SyntaxFactory.EnumMemberDeclaration(default, default(SyntaxTokenList), SyntaxFactory.Identifier(identifier), default); + /// Creates a new ExtensionDeclarationSyntax instance. + public static ExtensionDeclarationSyntax ExtensionDeclaration(SyntaxList attributeLists, SyntaxTokenList modifiers, SyntaxToken keyword, TypeParameterListSyntax? typeParameterList, ParameterListSyntax? parameterList, SyntaxList constraintClauses, SyntaxToken openBraceToken, SyntaxList members, SyntaxToken closeBraceToken, SyntaxToken semicolonToken) + { + if (keyword.Kind() != SyntaxKind.ExtensionKeyword) throw new ArgumentException(nameof(keyword)); + switch (openBraceToken.Kind()) + { + case SyntaxKind.OpenBraceToken: + case SyntaxKind.None: break; + default: throw new ArgumentException(nameof(openBraceToken)); + } + switch (closeBraceToken.Kind()) + { + case SyntaxKind.CloseBraceToken: + case SyntaxKind.None: break; + default: throw new ArgumentException(nameof(closeBraceToken)); + } + switch (semicolonToken.Kind()) + { + case SyntaxKind.SemicolonToken: + case SyntaxKind.None: break; + default: throw new ArgumentException(nameof(semicolonToken)); + } + return (ExtensionDeclarationSyntax)Syntax.InternalSyntax.SyntaxFactory.ExtensionDeclaration(attributeLists.Node.ToGreenList(), modifiers.Node.ToGreenList(), (Syntax.InternalSyntax.SyntaxToken)keyword.Node!, typeParameterList == null ? null : (Syntax.InternalSyntax.TypeParameterListSyntax)typeParameterList.Green, parameterList == null ? null : (Syntax.InternalSyntax.ParameterListSyntax)parameterList.Green, constraintClauses.Node.ToGreenList(), (Syntax.InternalSyntax.SyntaxToken?)openBraceToken.Node, members.Node.ToGreenList(), (Syntax.InternalSyntax.SyntaxToken?)closeBraceToken.Node, (Syntax.InternalSyntax.SyntaxToken?)semicolonToken.Node).CreateRed(); + } + + /// Creates a new ExtensionDeclarationSyntax instance. + public static ExtensionDeclarationSyntax ExtensionDeclaration(SyntaxList attributeLists, SyntaxTokenList modifiers, TypeParameterListSyntax? typeParameterList, ParameterListSyntax? parameterList, SyntaxList constraintClauses, SyntaxList members) + => SyntaxFactory.ExtensionDeclaration(attributeLists, modifiers, SyntaxFactory.Token(SyntaxKind.ExtensionKeyword), typeParameterList, parameterList, constraintClauses, default, members, default, default); + + /// Creates a new ExtensionDeclarationSyntax instance. + public static ExtensionDeclarationSyntax ExtensionDeclaration() + => SyntaxFactory.ExtensionDeclaration(default, default(SyntaxTokenList), SyntaxFactory.Token(SyntaxKind.ExtensionKeyword), default, default, default, default, default, default, default); + /// Creates a new BaseListSyntax instance. public static BaseListSyntax BaseList(SyntaxToken colonToken, SeparatedSyntaxList types) { @@ -5718,16 +5752,13 @@ public static ParameterSyntax Parameter(SyntaxList attribut switch (identifier.Kind()) { case SyntaxKind.IdentifierToken: - case SyntaxKind.ArgListKeyword: break; + case SyntaxKind.ArgListKeyword: + case SyntaxKind.None: break; default: throw new ArgumentException(nameof(identifier)); } - return (ParameterSyntax)Syntax.InternalSyntax.SyntaxFactory.Parameter(attributeLists.Node.ToGreenList(), modifiers.Node.ToGreenList(), type == null ? null : (Syntax.InternalSyntax.TypeSyntax)type.Green, (Syntax.InternalSyntax.SyntaxToken)identifier.Node!, @default == null ? null : (Syntax.InternalSyntax.EqualsValueClauseSyntax)@default.Green).CreateRed(); + return (ParameterSyntax)Syntax.InternalSyntax.SyntaxFactory.Parameter(attributeLists.Node.ToGreenList(), modifiers.Node.ToGreenList(), type == null ? null : (Syntax.InternalSyntax.TypeSyntax)type.Green, (Syntax.InternalSyntax.SyntaxToken?)identifier.Node, @default == null ? null : (Syntax.InternalSyntax.EqualsValueClauseSyntax)@default.Green).CreateRed(); } - /// Creates a new ParameterSyntax instance. - public static ParameterSyntax Parameter(SyntaxToken identifier) - => SyntaxFactory.Parameter(default, default(SyntaxTokenList), default, identifier, default); - /// Creates a new FunctionPointerParameterSyntax instance. public static FunctionPointerParameterSyntax FunctionPointerParameter(SyntaxList attributeLists, SyntaxTokenList modifiers, TypeSyntax type) { diff --git a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Syntax.Generated.cs b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Syntax.Generated.cs index 0c97b7c25c0a7..aa66360fb08d8 100644 --- a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Syntax.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Syntax.Generated.cs @@ -10261,7 +10261,7 @@ internal BaseTypeDeclarationSyntax(InternalSyntax.CSharpSyntaxNode green, Syntax public new BaseTypeDeclarationSyntax AddModifiers(params SyntaxToken[] items) => (BaseTypeDeclarationSyntax)AddModifiersCore(items); } -/// Base class for type declaration syntax (class, struct, interface, record). +/// Base class for type declaration syntax (class, struct, interface, record, extension). public abstract partial class TypeDeclarationSyntax : BaseTypeDeclarationSyntax { internal TypeDeclarationSyntax(InternalSyntax.CSharpSyntaxNode green, SyntaxNode? parent, int position) @@ -10269,7 +10269,7 @@ internal TypeDeclarationSyntax(InternalSyntax.CSharpSyntaxNode green, SyntaxNode { } - /// Gets the type keyword token ("class", "struct", "interface", "record"). + /// Gets the type keyword token ("class", "struct", "interface", "record", "extension"). public abstract SyntaxToken Keyword { get; } public TypeDeclarationSyntax WithKeyword(SyntaxToken keyword) => WithKeywordCore(keyword); internal abstract TypeDeclarationSyntax WithKeywordCore(SyntaxToken keyword); @@ -11312,6 +11312,154 @@ public EnumMemberDeclarationSyntax Update(SyntaxList attrib public new EnumMemberDeclarationSyntax AddModifiers(params SyntaxToken[] items) => WithModifiers(this.Modifiers.AddRange(items)); } +/// Extension container syntax. +/// +/// This node is associated with the following syntax kinds: +/// +/// +/// +/// +public sealed partial class ExtensionDeclarationSyntax : TypeDeclarationSyntax +{ + private SyntaxNode? attributeLists; + private TypeParameterListSyntax? typeParameterList; + private ParameterListSyntax? parameterList; + private SyntaxNode? constraintClauses; + private SyntaxNode? members; + + internal ExtensionDeclarationSyntax(InternalSyntax.CSharpSyntaxNode green, SyntaxNode? parent, int position) + : base(green, parent, position) + { + } + + public override SyntaxList AttributeLists => new SyntaxList(GetRed(ref this.attributeLists, 0)); + + public override SyntaxTokenList Modifiers + { + get + { + var slot = this.Green.GetSlot(1); + return slot != null ? new SyntaxTokenList(this, slot, GetChildPosition(1), GetChildIndex(1)) : default; + } + } + + public override SyntaxToken Keyword => new SyntaxToken(this, ((InternalSyntax.ExtensionDeclarationSyntax)this.Green).keyword, GetChildPosition(2), GetChildIndex(2)); + + public override TypeParameterListSyntax? TypeParameterList => GetRed(ref this.typeParameterList, 3); + + public override ParameterListSyntax? ParameterList => GetRed(ref this.parameterList, 4); + + public override SyntaxList ConstraintClauses => new SyntaxList(GetRed(ref this.constraintClauses, 5)); + + public override SyntaxToken OpenBraceToken + { + get + { + var slot = ((Syntax.InternalSyntax.ExtensionDeclarationSyntax)this.Green).openBraceToken; + return slot != null ? new SyntaxToken(this, slot, GetChildPosition(6), GetChildIndex(6)) : default; + } + } + + public override SyntaxList Members => new SyntaxList(GetRed(ref this.members, 7)); + + public override SyntaxToken CloseBraceToken + { + get + { + var slot = ((Syntax.InternalSyntax.ExtensionDeclarationSyntax)this.Green).closeBraceToken; + return slot != null ? new SyntaxToken(this, slot, GetChildPosition(8), GetChildIndex(8)) : default; + } + } + + public override SyntaxToken SemicolonToken + { + get + { + var slot = ((Syntax.InternalSyntax.ExtensionDeclarationSyntax)this.Green).semicolonToken; + return slot != null ? new SyntaxToken(this, slot, GetChildPosition(9), GetChildIndex(9)) : default; + } + } + + internal override SyntaxNode? GetNodeSlot(int index) + => index switch + { + 0 => GetRedAtZero(ref this.attributeLists)!, + 3 => GetRed(ref this.typeParameterList, 3), + 4 => GetRed(ref this.parameterList, 4), + 5 => GetRed(ref this.constraintClauses, 5)!, + 7 => GetRed(ref this.members, 7)!, + _ => null, + }; + + internal override SyntaxNode? GetCachedSlot(int index) + => index switch + { + 0 => this.attributeLists, + 3 => this.typeParameterList, + 4 => this.parameterList, + 5 => this.constraintClauses, + 7 => this.members, + _ => null, + }; + + public override void Accept(CSharpSyntaxVisitor visitor) => visitor.VisitExtensionDeclaration(this); + public override TResult? Accept(CSharpSyntaxVisitor visitor) where TResult : default => visitor.VisitExtensionDeclaration(this); + + public ExtensionDeclarationSyntax Update(SyntaxList attributeLists, SyntaxTokenList modifiers, SyntaxToken keyword, TypeParameterListSyntax? typeParameterList, ParameterListSyntax? parameterList, SyntaxList constraintClauses, SyntaxToken openBraceToken, SyntaxList members, SyntaxToken closeBraceToken, SyntaxToken semicolonToken) + { + if (attributeLists != this.AttributeLists || modifiers != this.Modifiers || keyword != this.Keyword || typeParameterList != this.TypeParameterList || parameterList != this.ParameterList || constraintClauses != this.ConstraintClauses || openBraceToken != this.OpenBraceToken || members != this.Members || closeBraceToken != this.CloseBraceToken || semicolonToken != this.SemicolonToken) + { + var newNode = SyntaxFactory.ExtensionDeclaration(attributeLists, modifiers, keyword, typeParameterList, parameterList, constraintClauses, openBraceToken, members, closeBraceToken, semicolonToken); + var annotations = GetAnnotations(); + return annotations?.Length > 0 ? newNode.WithAnnotations(annotations) : newNode; + } + + return this; + } + + internal override MemberDeclarationSyntax WithAttributeListsCore(SyntaxList attributeLists) => WithAttributeLists(attributeLists); + public new ExtensionDeclarationSyntax WithAttributeLists(SyntaxList attributeLists) => Update(attributeLists, this.Modifiers, this.Keyword, this.TypeParameterList, this.ParameterList, this.ConstraintClauses, this.OpenBraceToken, this.Members, this.CloseBraceToken, this.SemicolonToken); + internal override MemberDeclarationSyntax WithModifiersCore(SyntaxTokenList modifiers) => WithModifiers(modifiers); + public new ExtensionDeclarationSyntax WithModifiers(SyntaxTokenList modifiers) => Update(this.AttributeLists, modifiers, this.Keyword, this.TypeParameterList, this.ParameterList, this.ConstraintClauses, this.OpenBraceToken, this.Members, this.CloseBraceToken, this.SemicolonToken); + internal override TypeDeclarationSyntax WithKeywordCore(SyntaxToken keyword) => WithKeyword(keyword); + public new ExtensionDeclarationSyntax WithKeyword(SyntaxToken keyword) => Update(this.AttributeLists, this.Modifiers, keyword, this.TypeParameterList, this.ParameterList, this.ConstraintClauses, this.OpenBraceToken, this.Members, this.CloseBraceToken, this.SemicolonToken); + internal override TypeDeclarationSyntax WithTypeParameterListCore(TypeParameterListSyntax? typeParameterList) => WithTypeParameterList(typeParameterList); + public new ExtensionDeclarationSyntax WithTypeParameterList(TypeParameterListSyntax? typeParameterList) => Update(this.AttributeLists, this.Modifiers, this.Keyword, typeParameterList, this.ParameterList, this.ConstraintClauses, this.OpenBraceToken, this.Members, this.CloseBraceToken, this.SemicolonToken); + internal override TypeDeclarationSyntax WithParameterListCore(ParameterListSyntax? parameterList) => WithParameterList(parameterList); + public new ExtensionDeclarationSyntax WithParameterList(ParameterListSyntax? parameterList) => Update(this.AttributeLists, this.Modifiers, this.Keyword, this.TypeParameterList, parameterList, this.ConstraintClauses, this.OpenBraceToken, this.Members, this.CloseBraceToken, this.SemicolonToken); + internal override TypeDeclarationSyntax WithConstraintClausesCore(SyntaxList constraintClauses) => WithConstraintClauses(constraintClauses); + public new ExtensionDeclarationSyntax WithConstraintClauses(SyntaxList constraintClauses) => Update(this.AttributeLists, this.Modifiers, this.Keyword, this.TypeParameterList, this.ParameterList, constraintClauses, this.OpenBraceToken, this.Members, this.CloseBraceToken, this.SemicolonToken); + internal override BaseTypeDeclarationSyntax WithOpenBraceTokenCore(SyntaxToken openBraceToken) => WithOpenBraceToken(openBraceToken); + public new ExtensionDeclarationSyntax WithOpenBraceToken(SyntaxToken openBraceToken) => Update(this.AttributeLists, this.Modifiers, this.Keyword, this.TypeParameterList, this.ParameterList, this.ConstraintClauses, openBraceToken, this.Members, this.CloseBraceToken, this.SemicolonToken); + internal override TypeDeclarationSyntax WithMembersCore(SyntaxList members) => WithMembers(members); + public new ExtensionDeclarationSyntax WithMembers(SyntaxList members) => Update(this.AttributeLists, this.Modifiers, this.Keyword, this.TypeParameterList, this.ParameterList, this.ConstraintClauses, this.OpenBraceToken, members, this.CloseBraceToken, this.SemicolonToken); + internal override BaseTypeDeclarationSyntax WithCloseBraceTokenCore(SyntaxToken closeBraceToken) => WithCloseBraceToken(closeBraceToken); + public new ExtensionDeclarationSyntax WithCloseBraceToken(SyntaxToken closeBraceToken) => Update(this.AttributeLists, this.Modifiers, this.Keyword, this.TypeParameterList, this.ParameterList, this.ConstraintClauses, this.OpenBraceToken, this.Members, closeBraceToken, this.SemicolonToken); + internal override BaseTypeDeclarationSyntax WithSemicolonTokenCore(SyntaxToken semicolonToken) => WithSemicolonToken(semicolonToken); + public new ExtensionDeclarationSyntax WithSemicolonToken(SyntaxToken semicolonToken) => Update(this.AttributeLists, this.Modifiers, this.Keyword, this.TypeParameterList, this.ParameterList, this.ConstraintClauses, this.OpenBraceToken, this.Members, this.CloseBraceToken, semicolonToken); + + internal override MemberDeclarationSyntax AddAttributeListsCore(params AttributeListSyntax[] items) => AddAttributeLists(items); + public new ExtensionDeclarationSyntax AddAttributeLists(params AttributeListSyntax[] items) => WithAttributeLists(this.AttributeLists.AddRange(items)); + internal override MemberDeclarationSyntax AddModifiersCore(params SyntaxToken[] items) => AddModifiers(items); + public new ExtensionDeclarationSyntax AddModifiers(params SyntaxToken[] items) => WithModifiers(this.Modifiers.AddRange(items)); + internal override TypeDeclarationSyntax AddTypeParameterListParametersCore(params TypeParameterSyntax[] items) => AddTypeParameterListParameters(items); + public new ExtensionDeclarationSyntax AddTypeParameterListParameters(params TypeParameterSyntax[] items) + { + var typeParameterList = this.TypeParameterList ?? SyntaxFactory.TypeParameterList(); + return WithTypeParameterList(typeParameterList.WithParameters(typeParameterList.Parameters.AddRange(items))); + } + internal override TypeDeclarationSyntax AddParameterListParametersCore(params ParameterSyntax[] items) => AddParameterListParameters(items); + public new ExtensionDeclarationSyntax AddParameterListParameters(params ParameterSyntax[] items) + { + var parameterList = this.ParameterList ?? SyntaxFactory.ParameterList(); + return WithParameterList(parameterList.WithParameters(parameterList.Parameters.AddRange(items))); + } + internal override TypeDeclarationSyntax AddConstraintClausesCore(params TypeParameterConstraintClauseSyntax[] items) => AddConstraintClauses(items); + public new ExtensionDeclarationSyntax AddConstraintClauses(params TypeParameterConstraintClauseSyntax[] items) => WithConstraintClauses(this.ConstraintClauses.AddRange(items)); + internal override TypeDeclarationSyntax AddMembersCore(params MemberDeclarationSyntax[] items) => AddMembers(items); + public new ExtensionDeclarationSyntax AddMembers(params MemberDeclarationSyntax[] items) => WithMembers(this.Members.AddRange(items)); +} + /// Base list syntax. /// /// This node is associated with the following syntax kinds: @@ -13636,7 +13784,14 @@ public override SyntaxTokenList Modifiers public override TypeSyntax? Type => GetRed(ref this.type, 2); /// Gets the identifier. - public SyntaxToken Identifier => new SyntaxToken(this, ((InternalSyntax.ParameterSyntax)this.Green).identifier, GetChildPosition(3), GetChildIndex(3)); + public SyntaxToken Identifier + { + get + { + var slot = ((Syntax.InternalSyntax.ParameterSyntax)this.Green).identifier; + return slot != null ? new SyntaxToken(this, slot, GetChildPosition(3), GetChildIndex(3)) : default; + } + } public EqualsValueClauseSyntax? Default => GetRed(ref this.@default, 4); diff --git a/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs b/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs index 266ea28e686ca..35a3f0182d26b 100644 --- a/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs @@ -338,7 +338,7 @@ public static bool IsWarning(ErrorCode code) case ErrorCode.WRN_CollectionExpressionRefStructMayAllocate: case ErrorCode.WRN_CollectionExpressionRefStructSpreadMayAllocate: case ErrorCode.WRN_ConvertingLock: - case ErrorCode.WRN_PartialPropertySignatureDifference: + case ErrorCode.WRN_PartialMemberSignatureDifference: case ErrorCode.WRN_FieldIsAmbiguous: case ErrorCode.WRN_UninitializedNonNullableBackingField: case ErrorCode.WRN_UnassignedInternalRefField: diff --git a/src/Compilers/CSharp/Portable/LanguageVersion.cs b/src/Compilers/CSharp/Portable/LanguageVersion.cs index 4d429582030ef..ec5d56afa9904 100644 --- a/src/Compilers/CSharp/Portable/LanguageVersion.cs +++ b/src/Compilers/CSharp/Portable/LanguageVersion.cs @@ -572,5 +572,10 @@ internal static bool AllowImprovedOverloadCandidates(this LanguageVersion self) { return self >= MessageID.IDS_FeatureImprovedOverloadCandidates.RequiredVersion(); } + + internal static bool AllowNewExtensions(this LanguageVersion self) + { + return self >= MessageID.IDS_FeatureExtensions.RequiredVersion(); + } } } diff --git a/src/Compilers/CSharp/Portable/Lowering/BoundTreeToDifferentEnclosingContextRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/BoundTreeToDifferentEnclosingContextRewriter.cs new file mode 100644 index 0000000000000..ae54fba8eca00 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Lowering/BoundTreeToDifferentEnclosingContextRewriter.cs @@ -0,0 +1,180 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp +{ + /// + /// a bound node rewriter that rewrites types properly (which in some cases the automatically-generated + /// base class does not). This is used in the lambda rewriter, the iterator rewriter, and the async rewriter. + /// + internal abstract class BoundTreeToDifferentEnclosingContextRewriter : BoundTreeRewriterWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator + { + // A mapping from every local variable to its replacement local variable. Local variables are replaced when + // their types change due to being inside of a generic method. Otherwise we reuse the original local (even + // though its containing method is not correct because the code is moved into another method) + private readonly Dictionary localMap = new Dictionary(); + + // A mapping for types in the original method to types in its replacement. This is mainly necessary + // when the original method was generic, as type parameters in the original method are mapping into + // type parameters of the resulting class. + protected abstract TypeMap TypeMap { get; } + + protected abstract MethodSymbol CurrentMethod { get; } + + public override BoundNode DefaultVisit(BoundNode node) + { + Debug.Fail($"Override the visitor for {node.Kind}"); + return base.DefaultVisit(node); + } + + protected void RewriteLocals(ImmutableArray locals, ArrayBuilder newLocals) + { + foreach (var local in locals) + { + if (TryRewriteLocal(local, out LocalSymbol? newLocal)) + { + newLocals.Add(newLocal); + } + } + } + + protected virtual bool TryRewriteLocal(LocalSymbol local, [NotNullWhen(true)] out LocalSymbol? newLocal) + { + if (localMap.TryGetValue(local, out newLocal)) + { + return true; + } + + var newType = VisitType(local.Type); + if (TypeSymbol.Equals(newType, local.Type, TypeCompareKind.ConsiderEverything2)) + { + newLocal = local; + } + else + { + newLocal = new TypeSubstitutedLocalSymbol(local, TypeWithAnnotations.Create(newType), CurrentMethod); + localMap.Add(local, newLocal); + } + + return true; + } + + protected sealed override ImmutableArray VisitLocals(ImmutableArray locals) + { + if (locals.IsEmpty) return locals; + var newLocals = ArrayBuilder.GetInstance(); + RewriteLocals(locals, newLocals); + return newLocals.ToImmutableAndFree(); + } + + public sealed override LocalSymbol VisitLocalSymbol(LocalSymbol local) + { + if (!TryRewriteLocal(local, out var newLocal)) + { + throw ExceptionUtilities.UnexpectedValue(local); + } + + return newLocal; + } + + protected bool TryGetRewrittenLocal(LocalSymbol local, [NotNullWhen(true)] out LocalSymbol? localToUse) + { + return localMap.TryGetValue(local, out localToUse); + } + + public override BoundNode VisitBlock(BoundBlock node) + => VisitBlock(node, removeInstrumentation: false); + + protected BoundBlock VisitBlock(BoundBlock node, bool removeInstrumentation) + { + // Note: Instrumentation variable is intentionally not rewritten. It should never be lifted. + + var newLocals = this.VisitLocals(node.Locals); + var newLocalFunctions = this.VisitDeclaredLocalFunctions(node.LocalFunctions); + var newStatements = VisitList(node.Statements); + var newInstrumentation = removeInstrumentation ? null : (BoundBlockInstrumentation?)Visit(node.Instrumentation); + return node.Update(newLocals, newLocalFunctions, node.HasUnsafeModifier, newInstrumentation, newStatements); + } + + [return: NotNullIfNotNull(nameof(type))] + public sealed override TypeSymbol? VisitType(TypeSymbol? type) + { + return TypeMap.SubstituteType(type).Type; + } + + protected override BoundBinaryOperator.UncommonData? VisitBinaryOperatorData(BoundBinaryOperator node) + { + // Local rewriter should have already rewritten interpolated strings into their final form of calls and gotos + Debug.Assert(node.InterpolatedStringHandlerData is null); + + return BoundBinaryOperator.UncommonData.CreateIfNeeded(node.ConstantValueOpt, VisitMethodSymbol(node.Method), VisitType(node.ConstrainedToType), node.OriginalUserDefinedOperatorsOpt); + } + + public override BoundNode? VisitConversion(BoundConversion node) + { + var conversion = node.Conversion; + + if (conversion.Method is not null) + { + conversion = conversion.SetConversionMethod(VisitMethodSymbol(conversion.Method)); + } + + return node.Update( + (BoundExpression)Visit(node.Operand), + conversion, + node.IsBaseConversion, + node.Checked, + node.ExplicitCastInCode, + node.ConstantValueOpt, + node.ConversionGroupOpt, + VisitType(node.Type)); + } + + [return: NotNullIfNotNull(nameof(method))] + public override MethodSymbol? VisitMethodSymbol(MethodSymbol? method) + { + if (method is null) + { + return null; + } + + if (method.ContainingType.IsAnonymousType) + { + // Method of an anonymous type + var newType = (NamedTypeSymbol)TypeMap.SubstituteType(method.ContainingType).AsTypeSymbolOnly(); + if (ReferenceEquals(newType, method.ContainingType)) + { + // Anonymous type symbol was not rewritten + return method; + } + + // get a new method by name + foreach (var member in newType.GetMembers(method.Name)) + { + if (member.Kind == SymbolKind.Method) + { + return (MethodSymbol)member; + } + } + + throw ExceptionUtilities.Unreachable(); + } + else + { + // Method of a regular type + return ((MethodSymbol)method.OriginalDefinition) + .AsMember((NamedTypeSymbol)TypeMap.SubstituteType(method.ContainingType).AsTypeSymbolOnly()) + .ConstructIfGeneric(TypeMap.SubstituteTypes(method.TypeArgumentsWithAnnotations)); + } + } + } +} diff --git a/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/ClosureConversion.cs b/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/ClosureConversion.cs index 01e209bb2bb5b..a9460f35b945a 100644 --- a/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/ClosureConversion.cs +++ b/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/ClosureConversion.cs @@ -768,7 +768,7 @@ private void InitVariableProxy(SyntaxNode syntax, Symbol symbol, LocalSymbol fra } LocalSymbol localToUse; - if (!localMap.TryGetValue(local, out localToUse)) + if (!TryGetRewrittenLocal(local, out localToUse)) { localToUse = local; } @@ -1198,17 +1198,15 @@ private BoundBlock RewriteBlock(BoundBlock node, ArrayBuilder p public override BoundNode VisitScope(BoundScope node) { Debug.Assert(!node.Locals.IsEmpty); - var newLocals = ArrayBuilder.GetInstance(); - RewriteLocals(node.Locals, newLocals); + var newLocals = VisitLocals(node.Locals); var statements = VisitList(node.Statements); - if (newLocals.Count == 0) + if (newLocals.Length == 0) { - newLocals.Free(); return new BoundStatementList(node.Syntax, statements); } - return node.Update(newLocals.ToImmutableAndFree(), statements); + return node.Update(newLocals, statements); } public override BoundNode VisitCatchBlock(BoundCatchBlock node) diff --git a/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/SynthesizedClosureEnvironment.cs b/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/SynthesizedClosureEnvironment.cs index 49797ec0c86cd..b7754a5982068 100644 --- a/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/SynthesizedClosureEnvironment.cs +++ b/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/SynthesizedClosureEnvironment.cs @@ -50,7 +50,7 @@ internal SynthesizedClosureEnvironment( DebugId methodId, DebugId closureId, RuntimeRudeEdit? rudeEdit) - : base(MakeName(scopeSyntaxOpt, methodId, closureId), containingMethod) + : base(MakeName(scopeSyntaxOpt, methodId, closureId), containingMethod is null ? [] : TypeMap.ConcatMethodTypeParameters(containingMethod, stopAt: null)) { TypeKind = isStruct ? TypeKind.Struct : TypeKind.Class; TopLevelMethod = topLevelMethod; diff --git a/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/SynthesizedClosureMethod.cs b/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/SynthesizedClosureMethod.cs index 259353e7ca066..000a43b663390 100644 --- a/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/SynthesizedClosureMethod.cs +++ b/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/SynthesizedClosureMethod.cs @@ -57,22 +57,18 @@ originalMethod is LocalFunctionSymbol case ClosureKind.Singleton: // all type parameters on method (except the top level method's) case ClosureKind.General: // only lambda's type parameters on method (rest on class) RoslynDebug.Assert(!(lambdaFrame is null)); - typeMap = lambdaFrame.TypeMap.WithConcatAlphaRename( - originalMethod, + typeMap = lambdaFrame.TypeMap.WithAlphaRename( + TypeMap.ConcatMethodTypeParameters(originalMethod, stopAt: lambdaFrame.OriginalContainingMethodOpt), this, - out typeParameters, - out _, - lambdaFrame.OriginalContainingMethodOpt); + out typeParameters); break; case ClosureKind.ThisOnly: // all type parameters on method case ClosureKind.Static: RoslynDebug.Assert(lambdaFrame is null); - typeMap = TypeMap.Empty.WithConcatAlphaRename( - originalMethod, + typeMap = TypeMap.Empty.WithAlphaRename( + TypeMap.ConcatMethodTypeParameters(originalMethod, stopAt: null), this, - out typeParameters, - out _, - stopAt: null); + out typeParameters); break; default: throw ExceptionUtilities.UnexpectedValue(closureKind); diff --git a/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs b/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs index d743981c20bcc..947a42ec2fe1f 100644 --- a/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs +++ b/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs @@ -155,7 +155,7 @@ public override BoundNode VisitLocalFunctionStatement(BoundLocalFunctionStatemen var outerLocalFunction = _staticLocalOrAnonymousFunction; if (node.Symbol.IsStatic) { - _staticLocalOrAnonymousFunction = node.Symbol; + _staticLocalOrAnonymousFunction = (SourceMethodSymbol)node.Symbol; } var result = base.VisitLocalFunctionStatement(node); _staticLocalOrAnonymousFunction = outerLocalFunction; @@ -441,7 +441,14 @@ public override BoundNode VisitObjectInitializerMember(BoundObjectInitializerMem if (node.MemberSymbol is PropertySymbol property) { - CheckRefReturningPropertyAccess(node, property); + if (_inExpressionLambda && property.GetIsNewExtensionMember()) + { + Error(ErrorCode.ERR_ExpressionTreeContainsExtensionPropertyAccess, node); + } + else + { + CheckRefReturningPropertyAccess(node, property); + } } return base.VisitObjectInitializerMember(node); @@ -508,7 +515,7 @@ private void CheckDiscard(BoundDiscardExpression argument) public override BoundNode VisitCollectionElementInitializer(BoundCollectionElementInitializer node) { - if (_inExpressionLambda && node.AddMethod.IsStatic) + if (_inExpressionLambda && (node.AddMethod.IsStatic || node.AddMethod.GetIsNewExtensionMember())) { Error(ErrorCode.ERR_ExtensionCollectionElementInitializerInExpressionTree, node); } @@ -549,9 +556,16 @@ public override BoundNode VisitPropertyAccess(BoundPropertyAccess node) CheckRefReturningPropertyAccess(node, property); CheckReceiverIfField(node.ReceiverOpt); - if (_inExpressionLambda && (property.IsAbstract || property.IsVirtual) && property.IsStatic) + if (_inExpressionLambda) { - Error(ErrorCode.ERR_ExpressionTreeContainsAbstractStaticMemberAccess, node); + if ((property.IsAbstract || property.IsVirtual) && property.IsStatic) + { + Error(ErrorCode.ERR_ExpressionTreeContainsAbstractStaticMemberAccess, node); + } + else if (property.GetIsNewExtensionMember()) + { + Error(ErrorCode.ERR_ExpressionTreeContainsExtensionPropertyAccess, node); + } } return base.VisitPropertyAccess(node); @@ -639,7 +653,7 @@ public override BoundNode VisitLambda(BoundLambda node) var outerLocalFunction = _staticLocalOrAnonymousFunction; if (node.Symbol.IsStatic) { - _staticLocalOrAnonymousFunction = node.Symbol; + _staticLocalOrAnonymousFunction = (SourceMethodSymbol)node.Symbol; } var result = base.VisitLambda(node); _staticLocalOrAnonymousFunction = outerLocalFunction; diff --git a/src/Compilers/CSharp/Portable/Lowering/ExtensionMethodBodyRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/ExtensionMethodBodyRewriter.cs new file mode 100644 index 0000000000000..c6b67cd5d3a42 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Lowering/ExtensionMethodBodyRewriter.cs @@ -0,0 +1,198 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Roslyn.Utilities; +using ReferenceEqualityComparer = Roslyn.Utilities.ReferenceEqualityComparer; + +namespace Microsoft.CodeAnalysis.CSharp +{ + /// + /// Rewrites method body lowered in context of an extension method to a body + /// that corresponds to its implementation form. + /// + internal sealed class ExtensionMethodBodyRewriter : BoundTreeToDifferentEnclosingContextRewriter + { + private readonly SourceExtensionImplementationMethodSymbol _implementationMethod; + + /// + /// Maps parameters and local functions from original enclosing context to corresponding rewritten symbols for rewritten context. + /// + private ImmutableDictionary _symbolMap; + + private RewrittenMethodSymbol _rewrittenContainingMethod; + + public ExtensionMethodBodyRewriter(MethodSymbol sourceMethod, SourceExtensionImplementationMethodSymbol implementationMethod) + { + Debug.Assert(sourceMethod is not null); + Debug.Assert(implementationMethod is not null); + Debug.Assert(sourceMethod == (object)implementationMethod.UnderlyingMethod); + + _implementationMethod = implementationMethod; + _symbolMap = ImmutableDictionary.Empty.WithComparers(ReferenceEqualityComparer.Instance, ReferenceEqualityComparer.Instance); + + bool haveExtraParameter = sourceMethod.ParameterCount != implementationMethod.ParameterCount; + if (haveExtraParameter) + { + Debug.Assert(implementationMethod.ParameterCount - 1 == sourceMethod.ParameterCount); + var receiverParameter = (WrappedParameterSymbol)implementationMethod.Parameters[0]; + _symbolMap = _symbolMap.Add(receiverParameter.UnderlyingParameter, receiverParameter); + } + EnterMethod(sourceMethod, implementationMethod, implementationMethod.Parameters.AsSpan()[(haveExtraParameter ? 1 : 0)..]); + Debug.Assert(_rewrittenContainingMethod is not null); + } + + private (RewrittenMethodSymbol, ImmutableDictionary) EnterMethod(MethodSymbol symbol, RewrittenMethodSymbol rewritten, ReadOnlySpan rewrittenParameters) + { + ImmutableDictionary saveSymbolMap = _symbolMap; + RewrittenMethodSymbol savedContainer = _rewrittenContainingMethod; + + Debug.Assert(symbol.Parameters.Length == rewrittenParameters.Length); + + if (!rewrittenParameters.IsEmpty) + { + var builder = _symbolMap.ToBuilder(); + foreach (var parameter in symbol.Parameters) + { + builder.Add(parameter, rewrittenParameters[parameter.Ordinal]); + } + _symbolMap = builder.ToImmutable(); + } + + _rewrittenContainingMethod = rewritten; + + return (savedContainer, saveSymbolMap); + } + + private (RewrittenMethodSymbol, ImmutableDictionary) EnterMethod(MethodSymbol symbol, RewrittenLambdaOrLocalFunctionSymbol rewritten) + { + return EnterMethod(symbol, rewritten, rewritten.Parameters.AsSpan()); + } + + protected override MethodSymbol CurrentMethod => _rewrittenContainingMethod; + + protected override TypeMap TypeMap => _rewrittenContainingMethod.TypeMap; + + public override BoundNode? VisitThisReference(BoundThisReference node) + { + throw ExceptionUtilities.Unreachable(); + } + + public override ParameterSymbol VisitParameterSymbol(ParameterSymbol symbol) + { + return (ParameterSymbol)_symbolMap[symbol]; + } + + public override BoundNode? VisitLambda(BoundLambda node) + { + var rewritten = new RewrittenLambdaOrLocalFunctionSymbol(node.Symbol, _rewrittenContainingMethod); + + var savedState = EnterMethod(node.Symbol, rewritten); + BoundBlock body = (BoundBlock)this.Visit(node.Body); + (_rewrittenContainingMethod, _symbolMap) = savedState; + + TypeSymbol? type = this.VisitType(node.Type); + return node.Update(node.UnboundLambda, rewritten, body, node.Diagnostics, node.Binder, type); + } + + public override BoundNode? VisitLocalFunctionStatement(BoundLocalFunctionStatement node) + { + MethodSymbol symbol = this.VisitMethodSymbol(node.Symbol); + var savedState = EnterMethod(node.Symbol, (RewrittenLambdaOrLocalFunctionSymbol)symbol); + + BoundBlock? blockBody = (BoundBlock?)this.Visit(node.BlockBody); + BoundBlock? expressionBody = (BoundBlock?)this.Visit(node.ExpressionBody); + + (_rewrittenContainingMethod, _symbolMap) = savedState; + + return node.Update(symbol, blockBody, expressionBody); + } + + public override BoundNode VisitBlock(BoundBlock node) + { + ImmutableDictionary saveSymbolMap = _symbolMap; + + if (!node.LocalFunctions.IsEmpty) + { + var builder = _symbolMap.ToBuilder(); + + foreach (var localFunction in node.LocalFunctions) + { + builder.Add(localFunction, new RewrittenLambdaOrLocalFunctionSymbol(localFunction, _rewrittenContainingMethod)); + } + + _symbolMap = builder.ToImmutable(); + } + + var result = base.VisitBlock(node); + + _symbolMap = saveSymbolMap; + return result; + } + + protected override ImmutableArray VisitDeclaredLocalFunctions(ImmutableArray localFunctions) + { + return localFunctions.SelectAsArray(static (l, map) => (MethodSymbol)map[l], _symbolMap); + } + + [return: NotNullIfNotNull(nameof(symbol))] + public override MethodSymbol? VisitMethodSymbol(MethodSymbol? symbol) + { + switch (symbol?.MethodKind) + { + case MethodKind.LambdaMethod: + throw ExceptionUtilities.Unreachable(); + + case MethodKind.LocalFunction: + if (symbol.IsDefinition) + { + return (MethodSymbol)_symbolMap[symbol]; + } + + return ((MethodSymbol)_symbolMap[symbol.OriginalDefinition]).ConstructIfGeneric(TypeMap.SubstituteTypes(symbol.TypeArgumentsWithAnnotations)); + + default: + return base.VisitMethodSymbol(symbol); + } + } + + [return: NotNullIfNotNull(nameof(symbol))] + public override FieldSymbol? VisitFieldSymbol(FieldSymbol? symbol) + { + if (symbol is null) + { + return null; + } + + return symbol.OriginalDefinition + .AsMember((NamedTypeSymbol)TypeMap.SubstituteType(symbol.ContainingType).AsTypeSymbolOnly()); + } + + public override BoundNode? VisitCall(BoundCall node) + { + return ExtensionMethodReferenceRewriter.VisitCall(this, node); + } + + public override BoundNode? VisitDelegateCreationExpression(BoundDelegateCreationExpression node) + { + return ExtensionMethodReferenceRewriter.VisitDelegateCreationExpression(this, node); + } + + public override BoundNode VisitFunctionPointerLoad(BoundFunctionPointerLoad node) + { + return ExtensionMethodReferenceRewriter.VisitFunctionPointerLoad(this, node); + } + + [return: NotNullIfNotNull(nameof(symbol))] + public override PropertySymbol? VisitPropertySymbol(PropertySymbol? symbol) + { + Debug.Assert(symbol?.GetIsNewExtensionMember() != true); + return base.VisitPropertySymbol(symbol); + } + } +} diff --git a/src/Compilers/CSharp/Portable/Lowering/ExtensionMethodReferenceRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/ExtensionMethodReferenceRewriter.cs new file mode 100644 index 0000000000000..1e6b2dbb0a649 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Lowering/ExtensionMethodReferenceRewriter.cs @@ -0,0 +1,247 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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; +using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.PooledObjects; + +namespace Microsoft.CodeAnalysis.CSharp +{ + /// + /// Replaces references to extension methods with references to their implementation methods + /// + internal sealed class ExtensionMethodReferenceRewriter : BoundTreeRewriterWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator + { + private ExtensionMethodReferenceRewriter() + { + } + + public static BoundStatement Rewrite(BoundStatement statement) + { + var rewriter = new ExtensionMethodReferenceRewriter(); + return (BoundStatement)rewriter.Visit(statement); + } + + public override BoundNode VisitCall(BoundCall node) + { + return VisitCall(this, node); + } + + public static BoundNode VisitCall(BoundTreeRewriter rewriter, BoundCall node) + { + Debug.Assert(node != null); + + BoundExpression rewrittenCall; + + if (LocalRewriter.TryGetReceiver(node, out BoundCall? receiver1)) + { + // Handle long call chain of both instance and extension method invocations. + var calls = ArrayBuilder.GetInstance(); + + calls.Push(node); + node = receiver1; + + while (LocalRewriter.TryGetReceiver(node, out BoundCall? receiver2)) + { + calls.Push(node); + node = receiver2; + } + + // Rewrite the receiver + BoundExpression? rewrittenReceiver = (BoundExpression?)rewriter.Visit(node.ReceiverOpt); + + do + { + rewrittenCall = visitArgumentsAndFinishRewrite(rewriter, node, rewrittenReceiver); + rewrittenReceiver = rewrittenCall; + } + while (calls.TryPop(out node!)); + + calls.Free(); + } + else + { + // Rewrite the receiver + BoundExpression? rewrittenReceiver = (BoundExpression?)rewriter.Visit(node.ReceiverOpt); + rewrittenCall = visitArgumentsAndFinishRewrite(rewriter, node, rewrittenReceiver); + } + + return rewrittenCall; + + static BoundExpression visitArgumentsAndFinishRewrite(BoundTreeRewriter rewriter, BoundCall node, BoundExpression? rewrittenReceiver) + { + return updateCall( + node, + VisitMethodSymbolWithExtensionRewrite(rewriter, node.Method), + rewriter.VisitSymbols(node.OriginalMethodsOpt), + rewrittenReceiver, + rewriter.VisitList(node.Arguments), + node.ArgumentRefKindsOpt, + node.InvokedAsExtensionMethod, + rewriter.VisitType(node.Type)); + } + + static BoundExpression updateCall( + BoundCall boundCall, + MethodSymbol method, + ImmutableArray originalMethodsOpt, + BoundExpression? receiverOpt, + ImmutableArray arguments, + ImmutableArray argumentRefKinds, + bool invokedAsExtensionMethod, + TypeSymbol type) + { + if (receiverOpt is not null && arguments.Length == method.ParameterCount - 1) + { + Debug.Assert(boundCall.Method.OriginalDefinition.TryGetCorrespondingExtensionImplementationMethod() == (object)method.OriginalDefinition); + Debug.Assert(!boundCall.Method.IsStatic); + + var receiverRefKind = method.Parameters[0].RefKind; + + if (argumentRefKinds.IsDefault) + { + if (receiverRefKind != RefKind.None) + { + var builder = ArrayBuilder.GetInstance(method.ParameterCount, RefKind.None); + builder[0] = argumentRefKindFromReceiverRefKind(receiverRefKind); + argumentRefKinds = builder.ToImmutableAndFree(); + } + } + else + { + argumentRefKinds = argumentRefKinds.Insert(0, argumentRefKindFromReceiverRefKind(receiverRefKind)); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Test this code path + } + + invokedAsExtensionMethod = true; + + Debug.Assert(receiverOpt.Type!.Equals(method.Parameters[0].Type, TypeCompareKind.ConsiderEverything)); + + arguments = arguments.Insert(0, receiverOpt); + receiverOpt = null; + } + + return boundCall.Update( + receiverOpt, + boundCall.InitialBindingReceiverIsSubjectToCloning, + method, + arguments, + default, + argumentRefKinds, + boundCall.IsDelegateCall, + boundCall.Expanded, + invokedAsExtensionMethod, + default, + default, + boundCall.ResultKind, + originalMethodsOpt, + type); + + static RefKind argumentRefKindFromReceiverRefKind(RefKind receiverRefKind) + { + return SyntheticBoundNodeFactory.ArgumentRefKindFromParameterRefKind(receiverRefKind, useStrictArgumentRefKinds: false); + } + } + } + + [return: NotNullIfNotNull(nameof(method))] + private static MethodSymbol? VisitMethodSymbolWithExtensionRewrite(BoundTreeRewriter rewriter, MethodSymbol? method) + { + if (method?.GetIsNewExtensionMember() == true && + method.OriginalDefinition.TryGetCorrespondingExtensionImplementationMethod() is MethodSymbol implementationMethod) + { + method = implementationMethod.AsMember(method.ContainingSymbol.ContainingType). + ConstructIfGeneric(method.ContainingType.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.Concat(method.TypeArgumentsWithAnnotations)); + } + + return rewriter.VisitMethodSymbol(method); + } + + [return: NotNullIfNotNull(nameof(method))] + public override MethodSymbol? VisitMethodSymbol(MethodSymbol? method) + { + Debug.Assert(method?.GetIsNewExtensionMember() != true || + method.OriginalDefinition.TryGetCorrespondingExtensionImplementationMethod() is null); + // All possibly interesting methods should go through VisitMethodSymbolWithExtensionRewrite first + Debug.Assert(method is null || + method.ContainingSymbol is not NamedTypeSymbol || + method.MethodKind is (MethodKind.Constructor or MethodKind.StaticConstructor) || + method.OriginalDefinition is ErrorMethodSymbol || + new StackTrace(fNeedFileInfo: false).GetFrame(1)?.GetMethod() switch + { + { Name: nameof(VisitTypeOfOperator) } => method is { Name: "GetTypeFromHandle", IsExtensionMethod: false }, // GetTypeFromHandle cannot be an extension method + { Name: nameof(VisitRefTypeOperator) } => method is { Name: "GetTypeFromHandle", IsExtensionMethod: false }, // GetTypeFromHandle cannot be an extension method + { Name: nameof(VisitReadOnlySpanFromArray) } => method is { Name: "op_Implicit", IsExtensionMethod: false }, // Conversion operator from array to span cannot be an extension method + { Name: nameof(VisitLoweredConditionalAccess) } => // Nullable.HasValue cannot be an extension method + method.ContainingAssembly.GetSpecialTypeMember(SpecialMember.System_Nullable_T_get_HasValue) == (object)method.OriginalDefinition, + { Name: nameof(VisitUnaryOperator) } => !method.IsExtensionMethod, // Expression tree context. At the moment an operator cannot be an extension method + { Name: nameof(VisitUserDefinedConditionalLogicalOperator) } => !method.IsExtensionMethod, // Expression tree context. At the moment an operator cannot be an extension method + { Name: nameof(VisitCollectionElementInitializer) } => !method.IsExtensionMethod, // Expression tree context. At the moment an extension method cannot be used in expression tree here. + { Name: nameof(VisitAwaitableInfo) } => method is { Name: "GetResult", IsExtensionMethod: false }, // Cannot be an extension method + { Name: nameof(VisitMethodSymbolWithExtensionRewrite), DeclaringType: { } declaringType } => declaringType == typeof(ExtensionMethodReferenceRewriter), + _ => false + }); + + return base.VisitMethodSymbol(method); + } + + public override BoundNode? VisitMethodDefIndex(BoundMethodDefIndex node) + { + MethodSymbol method = node.Method; + Debug.Assert(method.IsDefinition); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : From the code coverage and other instrumentations perspective, should we remap the index to the implementation symbol? + TypeSymbol? type = this.VisitType(node.Type); + return node.Update(method, type); + } + + public override BoundNode? VisitDelegateCreationExpression(BoundDelegateCreationExpression node) + { + return VisitDelegateCreationExpression(this, node); + } + + public static BoundNode VisitDelegateCreationExpression(BoundTreeRewriter rewriter, BoundDelegateCreationExpression node) + { + var methodOpt = VisitMethodSymbolWithExtensionRewrite(rewriter, node.MethodOpt); + var argument = (BoundExpression)rewriter.Visit(node.Argument); + var type = rewriter.VisitType(node.Type); + bool isExtensionMethod = node.IsExtensionMethod; + + if (!isExtensionMethod && argument is not BoundTypeExpression && methodOpt?.IsStatic == true) + { + Debug.Assert(node.MethodOpt!.OriginalDefinition.TryGetCorrespondingExtensionImplementationMethod() == (object)methodOpt.OriginalDefinition); + isExtensionMethod = true; + } + + return node.Update(argument, methodOpt, isExtensionMethod, node.WasTargetTyped, type); + } + + public override BoundNode VisitFunctionPointerLoad(BoundFunctionPointerLoad node) + { + return VisitFunctionPointerLoad(this, node); + } + + public static BoundNode VisitFunctionPointerLoad(BoundTreeRewriter rewriter, BoundFunctionPointerLoad node) + { + MethodSymbol targetMethod = VisitMethodSymbolWithExtensionRewrite(rewriter, node.TargetMethod); + TypeSymbol? constrainedToTypeOpt = rewriter.VisitType(node.ConstrainedToTypeOpt); + TypeSymbol? type = rewriter.VisitType(node.Type); + return node.Update(targetMethod, constrainedToTypeOpt, type); + } + + protected override BoundBinaryOperator.UncommonData? VisitBinaryOperatorData(BoundBinaryOperator node) + { + Debug.Assert(node.Method is null || + (!node.Method.IsExtensionMethod && !node.Method.GetIsNewExtensionMember())); // Expression tree context. At the moment an operator cannot be an extension method + + return base.VisitBinaryOperatorData(node); + } + + [return: NotNullIfNotNull(nameof(symbol))] + public override PropertySymbol? VisitPropertySymbol(PropertySymbol? symbol) + { + Debug.Assert(symbol?.GetIsNewExtensionMember() != true); + return base.VisitPropertySymbol(symbol); + } + } +} diff --git a/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorFinallyMethodSymbol.cs b/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorFinallyMethodSymbol.cs index a8200be6deb4d..97aa7f30f3370 100644 --- a/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorFinallyMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorFinallyMethodSymbol.cs @@ -27,7 +27,7 @@ namespace Microsoft.CodeAnalysis.CSharp /// NOTE: Finally is a private void nonvirtual instance method with no parameters. /// It is a valid JIT inlining target as long as JIT may consider inlining profitable. /// - internal sealed class IteratorFinallyMethodSymbol : SynthesizedInstanceMethodSymbol, ISynthesizedMethodBodyImplementationSymbol + internal sealed class IteratorFinallyMethodSymbol : SynthesizedMethodSymbol, ISynthesizedMethodBodyImplementationSymbol { private readonly IteratorStateMachine _stateMachineType; private readonly string _name; diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/DelegateCacheContainer.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/DelegateCacheContainer.cs index 3472bb4419165..68c424eb9ffa1 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/DelegateCacheContainer.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/DelegateCacheContainer.cs @@ -18,22 +18,27 @@ internal sealed class DelegateCacheContainer : SynthesizedContainer private readonly Dictionary<(TypeSymbol?, TypeSymbol, MethodSymbol), FieldSymbol> _delegateFields = new(CLRSignatureComparer.Instance); /// Creates a type-scope concrete delegate cache container. - internal DelegateCacheContainer(TypeSymbol containingType, int generationOrdinal) - : base(GeneratedNames.DelegateCacheContainerType(generationOrdinal), containingMethod: null) + internal DelegateCacheContainer(NamedTypeSymbol containingType, int generationOrdinal) + : base(GeneratedNames.DelegateCacheContainerType(generationOrdinal)) { Debug.Assert(containingType.IsDefinition); _containingSymbol = containingType; } - /// Creates a method-scope generic delegate cache container. - internal DelegateCacheContainer(MethodSymbol ownerMethod, int topLevelMethodOrdinal, int ownerUniqueId, int generationOrdinal) - : base(GeneratedNames.DelegateCacheContainerType(generationOrdinal, ownerMethod.Name, topLevelMethodOrdinal, ownerUniqueId), ownerMethod) + /// Creates a generic delegate cache container "scoped" to a specific . + internal DelegateCacheContainer(NamedTypeSymbol containingType, Symbol owner, int topLevelMethodOrdinal, int ownerUniqueId, int generationOrdinal) + : base(GeneratedNames.DelegateCacheContainerType(generationOrdinal, owner.Name, topLevelMethodOrdinal, ownerUniqueId), + owner is NamedTypeSymbol type ? + type.TypeParameters : + (owner.ContainingType is { IsExtension: true } extensionType ? extensionType.TypeParameters : []).Concat( + TypeMap.ConcatMethodTypeParameters((MethodSymbol)owner, stopAt: null))) { - Debug.Assert(ownerMethod.IsDefinition); - Debug.Assert(ownerMethod.Arity > 0); + Debug.Assert(containingType.IsDefinition); + Debug.Assert(owner.IsDefinition); + Debug.Assert(owner is NamedTypeSymbol { Arity: > 0 } or MethodSymbol { Arity: > 0 }); - _containingSymbol = ownerMethod.ContainingType; + _containingSymbol = containingType; _constructedContainer = Construct(ConstructedFromTypeParameters); } diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/DelegateCacheRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/DelegateCacheRewriter.cs index 101f8a8a5800e..6e1c31d953cdb 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/DelegateCacheRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/DelegateCacheRewriter.cs @@ -22,7 +22,7 @@ internal sealed class DelegateCacheRewriter private readonly SyntheticBoundNodeFactory _factory; private readonly int _topLevelMethodOrdinal; - private Dictionary? _genericCacheContainers; + private Dictionary? _genericCacheContainers; internal DelegateCacheRewriter(SyntheticBoundNodeFactory factory, int topLevelMethodOrdinal) { @@ -90,7 +90,7 @@ private DelegateCacheContainer GetOrAddCacheContainer(BoundDelegateCreationExpre // // In the above case, only one cached delegate is necessary, and it could be assigned to the container 'owned' by LF1. - if (!TryGetOwnerFunction(_factory.CurrentFunction, boundDelegateCreation, out var ownerFunction)) + if (!TryGetOwnerFunctionOrExtensionType(_factory.CurrentFunction, boundDelegateCreation, out Symbol? owner)) { var typeCompilationState = _factory.CompilationState; container = typeCompilationState.ConcreteDelegateCacheContainer; @@ -105,15 +105,15 @@ private DelegateCacheContainer GetOrAddCacheContainer(BoundDelegateCreationExpre } else { - var containers = _genericCacheContainers ??= new Dictionary(ReferenceEqualityComparer.Instance); + var containers = _genericCacheContainers ??= new Dictionary(ReferenceEqualityComparer.Instance); - if (containers.TryGetValue(ownerFunction, out container)) + if (containers.TryGetValue(owner, out container)) { return container; } - container = new DelegateCacheContainer(ownerFunction, _topLevelMethodOrdinal, containers.Count, generation); - containers.Add(ownerFunction, container); + container = new DelegateCacheContainer(_factory.CompilationState.Type, owner, _topLevelMethodOrdinal, ownerUniqueId: containers.Count, generation); + containers.Add(owner, container); } _factory.AddNestedType(container); @@ -121,7 +121,7 @@ private DelegateCacheContainer GetOrAddCacheContainer(BoundDelegateCreationExpre return container; } - private static bool TryGetOwnerFunction(MethodSymbol currentFunction, BoundDelegateCreationExpression boundDelegateCreation, [NotNullWhen(true)] out MethodSymbol? ownerFunction) + private static bool TryGetOwnerFunctionOrExtensionType(MethodSymbol currentFunction, BoundDelegateCreationExpression boundDelegateCreation, [NotNullWhen(true)] out Symbol? owner) { var targetMethod = boundDelegateCreation.MethodOpt; Debug.Assert(targetMethod is { }); @@ -139,16 +139,23 @@ private static bool TryGetOwnerFunction(MethodSymbol currentFunction, BoundDeleg // // Therefore, without too much analysis, we select the closest generic enclosing function as the cache container owner. - for (Symbol? enclosingSymbol = currentFunction; enclosingSymbol is MethodSymbol enclosingMethod; enclosingSymbol = enclosingSymbol.ContainingSymbol) + Symbol? enclosingSymbol = currentFunction; + for (; enclosingSymbol is MethodSymbol enclosingMethod; enclosingSymbol = enclosingSymbol.ContainingSymbol) { if (enclosingMethod.Arity > 0) { - ownerFunction = enclosingMethod; + owner = enclosingMethod; return true; } } - ownerFunction = null; + if (enclosingSymbol is NamedTypeSymbol { IsExtension: true, Arity: > 0 }) + { + owner = enclosingSymbol; + return true; + } + + owner = null; return false; } @@ -173,16 +180,24 @@ private static bool TryGetOwnerFunction(MethodSymbol currentFunction, BoundDeleg FindTypeParameters(delegateType, usedTypeParameters); FindTypeParameters(targetMethod, usedTypeParameters); - for (Symbol? enclosingSymbol = currentFunction; enclosingSymbol is MethodSymbol enclosingMethod; enclosingSymbol = enclosingSymbol.ContainingSymbol) + Symbol? enclosingSymbol = currentFunction; + for (; enclosingSymbol is MethodSymbol enclosingMethod; enclosingSymbol = enclosingSymbol.ContainingSymbol) { if (usedTypeParametersContains(usedTypeParameters, enclosingMethod.TypeParameters)) { - ownerFunction = enclosingMethod; + owner = enclosingMethod; return true; } } - ownerFunction = null; + if (enclosingSymbol is NamedTypeSymbol { IsExtension: true, Arity: > 0 } extensionType && + usedTypeParametersContains(usedTypeParameters, extensionType.TypeParameters)) + { + owner = enclosingSymbol; + return true; + } + + owner = null; return false; } finally diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/DynamicSiteContainer.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/DynamicSiteContainer.cs index 70231c91adda7..a02f486447157 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/DynamicSiteContainer.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/DynamicSiteContainer.cs @@ -15,7 +15,9 @@ internal sealed class DynamicSiteContainer : SynthesizedContainer, ISynthesizedM private readonly MethodSymbol _topLevelMethod; internal DynamicSiteContainer(string name, MethodSymbol topLevelMethod, MethodSymbol containingMethod) - : base(name, containingMethod) + : base(name, + (topLevelMethod.ContainingSymbol is NamedTypeSymbol { IsExtension: true } extensionType ? extensionType.TypeParameters : []).Concat( + TypeMap.ConcatMethodTypeParameters(containingMethod, stopAt: null))) { Debug.Assert(topLevelMethod != null); _topLevelMethod = topLevelMethod; @@ -23,7 +25,16 @@ internal DynamicSiteContainer(string name, MethodSymbol topLevelMethod, MethodSy public override Symbol ContainingSymbol { - get { return _topLevelMethod.ContainingSymbol; } + get + { + var containingSymbol = _topLevelMethod.ContainingSymbol; + if (containingSymbol is NamedTypeSymbol { IsExtension: true }) + { + return containingSymbol.ContainingSymbol; + } + + return containingSymbol; + } } public override TypeKind TypeKind diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.PatternLocalRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.PatternLocalRewriter.cs index 9b1e482372253..56b944a4888b2 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.PatternLocalRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.PatternLocalRewriter.cs @@ -169,7 +169,7 @@ void addArg(RefKind refKind, BoundExpression expression) Debug.Assert(method.Name == WellKnownMemberNames.DeconstructMethodName); int extensionExtra; - if (method.IsStatic) + if (method.IsStatic) // Tracked by https://github.com/dotnet/roslyn/issues/76130: Test this code path with new extensions { Debug.Assert(method.IsExtensionMethod); receiver = _factory.Type(method.ContainingType); diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.cs index 8e73de6531706..6f8840715c10a 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.cs @@ -412,7 +412,7 @@ public override BoundNode VisitLocalFunctionStatement(BoundLocalFunctionStatemen } } - static bool hasReturnTypeOrParameter(LocalFunctionSymbol localFunction, Func predicate) => + static bool hasReturnTypeOrParameter(MethodSymbol localFunction, Func predicate) => predicate(localFunction.ReturnTypeWithAnnotations) || localFunction.ParameterTypesWithAnnotations.Any(predicate); } diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs index 46d37fdd2d589..74264343a3cbd 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs @@ -77,7 +77,7 @@ public override BoundNode VisitUserDefinedConditionalLogicalOperator(BoundUserDe if (_inExpressionLambda) { - return node.Update(operatorKind, node.LogicalOperator, node.TrueOperator, node.FalseOperator, node.ConstrainedToTypeOpt, node.ResultKind, loweredLeft, loweredRight, type); + return node.Update(operatorKind, node.LogicalOperator, node.TrueOperator, node.FalseOperator, node.ConstrainedToTypeOpt, node.ResultKind, originalUserDefinedOperatorsOpt: default, loweredLeft, loweredRight, type); } BoundAssignmentOperator tempAssignment; @@ -125,6 +125,12 @@ public BoundExpression VisitBinaryOperator(BoundBinaryOperator node, BoundUnaryO return VisitUtf8Addition(node); } + if (IsBinaryStringConcatenation(node)) + { + Debug.Assert(applyParentUnaryOperator is null); + return VisitStringConcatenation(node); + } + // In machine-generated code we frequently end up with binary operator trees that are deep on the left, // such as a + b + c + d ... // To avoid blowing the call stack, we make an explicit stack of the binary operators to the left, @@ -135,7 +141,7 @@ public BoundExpression VisitBinaryOperator(BoundBinaryOperator node, BoundUnaryO for (BoundBinaryOperator? current = node; current != null && current.ConstantValueOpt == null; current = current.Left as BoundBinaryOperator) { // The regular visit mechanism will handle this. - if (current.InterpolatedStringHandlerData is not null || current.OperatorKind is BinaryOperatorKind.Utf8Addition) + if (current.InterpolatedStringHandlerData is not null || current.OperatorKind is BinaryOperatorKind.Utf8Addition || IsBinaryStringConcatenation(current)) { Debug.Assert(stack.Count >= 1); break; @@ -208,7 +214,7 @@ private BoundExpression MakeBinaryOperator( case BinaryOperatorKind.ObjectAndStringConcatenation: case BinaryOperatorKind.StringAndObjectConcatenation: case BinaryOperatorKind.StringConcatenation: - return RewriteStringConcatenation(syntax, operatorKind, loweredLeft, loweredRight, type); + throw ExceptionUtilities.UnexpectedValue(operatorKind); case BinaryOperatorKind.DelegateCombination: return RewriteDelegateOperation(syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_Delegate__Combine); case BinaryOperatorKind.DelegateRemoval: @@ -256,7 +262,7 @@ private BoundExpression MakeBinaryOperator( case BinaryOperatorKind.ObjectAndStringConcatenation: case BinaryOperatorKind.StringAndObjectConcatenation: case BinaryOperatorKind.StringConcatenation: - return RewriteStringConcatenation(syntax, operatorKind, loweredLeft, loweredRight, type); + throw ExceptionUtilities.UnexpectedValue(operatorKind); case BinaryOperatorKind.StringEqual: return RewriteStringEquality(oldNode, syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_String__op_Equality); diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs index 021a5509ae2d7..913c4f7053771 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs @@ -54,7 +54,7 @@ public BoundExpression VisitDynamicInvocation(BoundDynamicInvocation node, bool { // Calling a static method defined on the current class via its simple name. Debug.Assert(_factory.CurrentType is { }); - loweredReceiver = new BoundTypeExpression(node.Syntax, null, _factory.CurrentType); + loweredReceiver = new BoundTypeExpression(node.Syntax, null, _factory.CurrentType); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Follow up (_factory.CompilationState.Type?) } else { @@ -199,8 +199,8 @@ private void InterceptCallAndAdjustArguments( // When the original call is to an instance method, and the interceptor is an extension method, // we need to take special care to intercept with the extension method as though it is being called in reduced form. Debug.Assert(receiverOpt is not BoundTypeExpression || method.IsStatic); - var needToReduce = receiverOpt is not (null or BoundTypeExpression) && interceptor.IsExtensionMethod; - var symbolForCompare = needToReduce ? ReducedExtensionMethodSymbol.Create(interceptor, receiverOpt!.Type, _compilation, out _) : interceptor; + var needToReduce = receiverOpt is not (null or BoundTypeExpression) && interceptor.IsExtensionMethod; // Tracked by https://github.com/dotnet/roslyn/issues/76130: Test this code path with new extensions + var symbolForCompare = needToReduce ? ReducedExtensionMethodSymbol.Create(interceptor, receiverOpt!.Type, _compilation, out _) : interceptor; // Tracked by https://github.com/dotnet/roslyn/issues/76130 : test interceptors if (!MemberSignatureComparer.InterceptorsComparer.Equals(method, symbolForCompare)) { @@ -245,7 +245,7 @@ private void InterceptCallAndAdjustArguments( break; } - if (invokedAsExtensionMethod && interceptor.IsStatic && !interceptor.IsExtensionMethod) + if (invokedAsExtensionMethod && interceptor.IsStatic && !interceptor.IsExtensionMethod) // Tracked by https://github.com/dotnet/roslyn/issues/76130: Test this code path with new extensions { // Special case when intercepting an extension method call in reduced form with a non-extension. this._diagnostics.Add(ErrorCode.ERR_InterceptorMustHaveMatchingThisParameter, attributeLocation, method.Parameters[0], method); @@ -323,7 +323,7 @@ public override BoundNode VisitCall(BoundCall node) BoundExpression rewrittenCall; - if (tryGetReceiver(node, out BoundCall? receiver1)) + if (TryGetReceiver(node, out BoundCall? receiver1)) { // Handle long call chain of both instance and extension method invocations. var calls = ArrayBuilder.GetInstance(); @@ -331,7 +331,7 @@ public override BoundNode VisitCall(BoundCall node) calls.Push(node); node = receiver1; - while (tryGetReceiver(node, out BoundCall? receiver2)) + while (TryGetReceiver(node, out BoundCall? receiver2)) { calls.Push(node); node = receiver2; @@ -358,26 +358,6 @@ public override BoundNode VisitCall(BoundCall node) return rewrittenCall; - // Gets the instance or extension invocation receiver if any. - static bool tryGetReceiver(BoundCall node, [MaybeNullWhen(returnValue: false)] out BoundCall receiver) - { - if (node.ReceiverOpt is BoundCall instanceReceiver) - { - receiver = instanceReceiver; - return true; - } - - if (node.InvokedAsExtensionMethod && node.Arguments is [BoundCall extensionReceiver, ..]) - { - Debug.Assert(node.ReceiverOpt is null); - receiver = extensionReceiver; - return true; - } - - receiver = null; - return false; - } - BoundExpression visitArgumentsAndFinishRewrite(BoundCall node, BoundExpression? rewrittenReceiver) { MethodSymbol method = node.Method; @@ -434,6 +414,28 @@ BoundExpression visitArgumentsAndFinishRewrite(BoundCall node, BoundExpression? } } + /// + /// Gets the instance or extension invocation receiver if any. + /// + internal static bool TryGetReceiver(BoundCall node, [MaybeNullWhen(returnValue: false)] out BoundCall receiver) + { + if (node.ReceiverOpt is BoundCall instanceReceiver) + { + receiver = instanceReceiver; + return true; + } + + if (node.InvokedAsExtensionMethod && node.Arguments is [BoundCall extensionReceiver, ..]) + { + Debug.Assert(node.ReceiverOpt is null); + receiver = extensionReceiver; + return true; + } + + receiver = null; + return false; + } + private BoundExpression MakeCall( BoundCall? node, SyntaxNode syntax, @@ -1229,15 +1231,29 @@ internal static bool CanSkipRewriting( if (!ignoreComReceiver) { - var receiverNamedType = invokedAsExtensionMethod ? - ((MethodSymbol)methodOrIndexer).Parameters[0].Type as NamedTypeSymbol : - methodOrIndexer.ContainingType; + NamedTypeSymbol? receiverNamedType = tryGetReceiverNamedType(methodOrIndexer, invokedAsExtensionMethod); isComReceiver = receiverNamedType is { IsComImport: true }; } return rewrittenArguments.Length == methodOrIndexer.GetParameterCount() && argsToParamsOpt.IsDefault && !isComReceiver; + + static NamedTypeSymbol? tryGetReceiverNamedType(Symbol methodOrIndexer, bool invokedAsExtensionMethod) + { + if (invokedAsExtensionMethod) + { + return ((MethodSymbol)methodOrIndexer).Parameters[0].Type as NamedTypeSymbol; + } + + if (methodOrIndexer.GetIsNewExtensionMember()) + { + Debug.Assert(methodOrIndexer.ContainingType.ExtensionParameter is not null); + return methodOrIndexer.ContainingType.ExtensionParameter.Type as NamedTypeSymbol; + } + + return (NamedTypeSymbol?)methodOrIndexer.ContainingType; + } } private static ImmutableArray GetRefKindsOrNull(ArrayBuilder refKinds) diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CollectionExpression.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CollectionExpression.cs index 4f4d5c20dfdb1..fe1967fcf02b7 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CollectionExpression.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CollectionExpression.cs @@ -384,7 +384,7 @@ private BoundExpression VisitCollectionInitializerCollectionExpression(BoundColl { return expressionElement switch { - BoundCollectionElementInitializer collectionInitializer => MakeCollectionInitializer(rewrittenReceiver, collectionInitializer), + BoundCollectionElementInitializer collectionInitializer => MakeCollectionInitializer(collectionInitializer), BoundDynamicCollectionElementInitializer dynamicInitializer => MakeDynamicCollectionInitializer(rewrittenReceiver, dynamicInitializer), var e => throw ExceptionUtilities.UnexpectedValue(e) }; diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CompoundAssignmentOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CompoundAssignmentOperator.cs index 6b87177c37ffb..3b295eb9b6e35 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CompoundAssignmentOperator.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CompoundAssignmentOperator.cs @@ -22,7 +22,6 @@ public override BoundNode VisitCompoundAssignmentOperator(BoundCompoundAssignmen private BoundExpression VisitCompoundAssignmentOperator(BoundCompoundAssignmentOperator node, bool used) { Debug.Assert(TypeSymbol.Equals(node.Right.Type, node.Operator.RightType, TypeCompareKind.ConsiderEverything2)); - BoundExpression loweredRight = VisitExpression(node.Right); var temps = ArrayBuilder.GetInstance(); var stores = ArrayBuilder.GetInstance(); @@ -55,6 +54,8 @@ private BoundExpression VisitCompoundAssignmentOperator(BoundCompoundAssignmentO // side before storing the lambda to a temp for use in both possible branches. // The first store to memberAccessReceiver has already been taken care of above by TransformCompoundAssignmentLHS + Debug.Assert(!IsBinaryStringConcatenation(binaryOperator)); + var eventTemps = ArrayBuilder.GetInstance(); var sequence = ArrayBuilder.GetInstance(); @@ -74,6 +75,7 @@ private BoundExpression VisitCompoundAssignmentOperator(BoundCompoundAssignmentO sequence.Add(nonEventStore); // var loweredRight = handler; + BoundExpression loweredRight = VisitExpression(node.Right); if (CanChangeValueBetweenReads(loweredRight)) { loweredRight = _factory.StoreToTemp(loweredRight, out BoundAssignmentOperator possibleHandlerAssignment); @@ -88,7 +90,7 @@ private BoundExpression VisitCompoundAssignmentOperator(BoundCompoundAssignmentO loweredRight); // transformedLHS = storeNonEvent + loweredRight - rewrittenAssignment = rewriteAssignment(lhsRead); + rewrittenAssignment = rewriteAssignment(lhsRead, loweredRight, rightIsVisited: true); Debug.Assert(rewrittenAssignment.Type is { }); // Final conditional @@ -98,7 +100,7 @@ private BoundExpression VisitCompoundAssignmentOperator(BoundCompoundAssignmentO } else { - rewrittenAssignment = rewriteAssignment(lhsRead); + rewrittenAssignment = rewriteAssignment(lhsRead, node.Right, rightIsVisited: false); } Debug.Assert(rewrittenAssignment.Type is { }); @@ -115,7 +117,7 @@ private BoundExpression VisitCompoundAssignmentOperator(BoundCompoundAssignmentO stores.Free(); return result; - BoundExpression rewriteAssignment(BoundExpression leftRead) + BoundExpression rewriteAssignment(BoundExpression leftRead, BoundExpression right, bool rightIsVisited) { SyntaxNode syntax = node.Syntax; @@ -139,7 +141,18 @@ BoundExpression rewriteAssignment(BoundExpression leftRead) RemovePlaceholderReplacement(node.LeftPlaceholder); } - BoundExpression operand = MakeBinaryOperator(syntax, node.Operator.Kind, opLHS, loweredRight, node.Operator.ReturnType, node.Operator.Method, node.Operator.ConstrainedToTypeOpt, isCompoundAssignment: true); + BoundExpression operand; + if (IsBinaryStringConcatenation(node.Operator.Kind)) + { + Debug.Assert(!rightIsVisited); + Debug.Assert(node.Operator.ReturnType is { SpecialType: SpecialType.System_String }); + operand = VisitCompoundAssignmentStringConcatenation(opLHS, right, node.Operator.Kind, node.Syntax); + } + else + { + var loweredRight = rightIsVisited ? right : VisitExpression(right); + operand = MakeBinaryOperator(syntax, node.Operator.Kind, opLHS, loweredRight, node.Operator.ReturnType, node.Operator.Method, node.Operator.ConstrainedToTypeOpt, isCompoundAssignment: true); + } Debug.Assert(node.Left.Type is { }); BoundExpression opFinal = operand; diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ForEachStatement.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ForEachStatement.cs index 306b42bad04f0..2b7c275bcc0a6 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ForEachStatement.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ForEachStatement.cs @@ -141,8 +141,8 @@ private BoundStatement RewriteForEachEnumerator( ImmutableArray iterationVariables, BoundForEachDeconstructStep? deconstruction, BoundAwaitableInfo? awaitableInfo, - GeneratedLabelSymbol breakLabel, - GeneratedLabelSymbol continueLabel, + LabelSymbol breakLabel, + LabelSymbol continueLabel, BoundStatement rewrittenBody) { var forEachSyntax = (CSharpSyntaxNode)node.Syntax; @@ -181,7 +181,7 @@ private BoundStatement RewriteForEachEnumerator( // ((C)(x)).GetEnumerator(); OR (x).GetEnumerator(); OR async variants (which fill-in arguments for optional parameters) BoundExpression enumeratorVarInitValue = SynthesizeCall(getEnumeratorInfo, forEachSyntax, receiver, - allowExtensionAndOptionalParameters: isAsync || getEnumeratorInfo.Method.IsExtensionMethod, firstRewrittenArgument: firstRewrittenArgument); + allowExtensionAndOptionalParameters: isAsync || getEnumeratorInfo.Method.IsExtensionMethod || getEnumeratorInfo.Method.GetIsNewExtensionMember(), firstRewrittenArgument: firstRewrittenArgument); // E e = ((C)(x)).GetEnumerator(); BoundStatement enumeratorVarDecl = MakeLocalDeclaration(forEachSyntax, enumeratorVar, enumeratorVarInitValue); @@ -602,8 +602,8 @@ private BoundStatement RewriteForEachStatementAsFor( BoundExpression? elementConversion, ImmutableArray iterationVariables, BoundForEachDeconstructStep? deconstructionOpt, - GeneratedLabelSymbol breakLabel, - GeneratedLabelSymbol continueLabel, + LabelSymbol breakLabel, + LabelSymbol continueLabel, BoundStatement rewrittenBody) { NamedTypeSymbol? collectionType = (NamedTypeSymbol?)collectionExpression.Type; @@ -898,8 +898,8 @@ private BoundStatement RewriteSingleDimensionalArrayForEachEnumerator( BoundExpression? elementConversion, ImmutableArray iterationVariables, BoundForEachDeconstructStep? deconstruction, - GeneratedLabelSymbol breakLabel, - GeneratedLabelSymbol continueLabel, + LabelSymbol breakLabel, + LabelSymbol continueLabel, BoundStatement rewrittenBody) { Debug.Assert(collectionExpression.Type is { TypeKind: TypeKind.Array }); @@ -1047,8 +1047,8 @@ private BoundStatement RewriteMultiDimensionalArrayForEachEnumerator( BoundExpression? elementConversion, ImmutableArray iterationVariables, BoundForEachDeconstructStep? deconstruction, - GeneratedLabelSymbol breakLabel, - GeneratedLabelSymbol continueLabel, + LabelSymbol breakLabel, + LabelSymbol continueLabel, BoundStatement rewrittenBody) { Debug.Assert(collectionExpression.Type is { TypeKind: TypeKind.Array }); @@ -1158,7 +1158,7 @@ private BoundStatement RewriteMultiDimensionalArrayForEachEnumerator( // int p_dimension = a.GetLowerBound(dimension); BoundStatement positionVarDecl = MakeLocalDeclaration(forEachSyntax, positionVar[dimension], currentDimensionLowerBound); - GeneratedLabelSymbol breakLabelInner = dimension == 0 // outermost for-loop + LabelSymbol breakLabelInner = dimension == 0 // outermost for-loop ? breakLabel // i.e. the one that break statements will jump to : new GeneratedLabelSymbol("break"); // Should not affect emitted code since unused @@ -1178,7 +1178,7 @@ private BoundStatement RewriteMultiDimensionalArrayForEachEnumerator( BoundStatement positionIncrement = MakePositionIncrement(forEachSyntax, boundPositionVar[dimension], intType); BoundStatement body; - GeneratedLabelSymbol continueLabelInner; + LabelSymbol continueLabelInner; if (forLoop == null) { diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ForStatement.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ForStatement.cs index 1ac1cdd3d013b..6160089918162 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ForStatement.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ForStatement.cs @@ -44,8 +44,8 @@ private BoundStatement RewriteForStatementWithoutInnerLocals( BoundExpression? rewrittenCondition, BoundStatement? rewrittenIncrement, BoundStatement rewrittenBody, - GeneratedLabelSymbol breakLabel, - GeneratedLabelSymbol continueLabel, + LabelSymbol breakLabel, + LabelSymbol continueLabel, bool hasErrors) { Debug.Assert(original.Kind is BoundKind.ForStatement or BoundKind.ForEachStatement or BoundKind.CollectionExpressionSpreadElement); diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ObjectOrCollectionInitializerExpression.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ObjectOrCollectionInitializerExpression.cs index 2141d021dd429..ec0cd11e141fe 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ObjectOrCollectionInitializerExpression.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ObjectOrCollectionInitializerExpression.cs @@ -74,18 +74,57 @@ private ImmutableArray MakeObjectOrCollectionInitializersForExp case BoundKind.CollectionInitializerExpression: var result = ArrayBuilder.GetInstance(); - AddCollectionInitializers(result, null, ((BoundCollectionInitializerExpression)initializerExpression).Initializers); + addCollectionInitializersForExpressionTree(result, ((BoundCollectionInitializerExpression)initializerExpression).Initializers); return result.ToImmutableAndFree(); default: throw ExceptionUtilities.UnexpectedValue(initializerExpression.Kind); } + + void addCollectionInitializersForExpressionTree(ArrayBuilder result, ImmutableArray initializers) + { + foreach (var initializer in initializers) + { + // In general bound initializers may contain bad expressions or element initializers. + // We don't lower them if they contain errors, so it's safe to assume an element initializer. + + if (initializer.Kind != BoundKind.CollectionElementInitializer) + { + throw ExceptionUtilities.UnexpectedValue(initializer.Kind); + } + + var elementInitializer = (BoundCollectionElementInitializer)initializer; + + // NOTE: Calls cannot be omitted within an expression tree (CS0765); this should already + // have been checked. + Debug.Assert(!elementInitializer.AddMethod.CallsAreOmitted(initializer.SyntaxTree)); + + Debug.Assert(!elementInitializer.InvokedAsExtensionMethod); + Debug.Assert(!elementInitializer.AddMethod.IsExtensionMethod); + Debug.Assert(!elementInitializer.AddMethod.GetIsNewExtensionMember()); + Debug.Assert(elementInitializer.Arguments.Length == elementInitializer.AddMethod.ParameterCount); + Debug.Assert(elementInitializer.ImplicitReceiverOpt is BoundObjectOrCollectionValuePlaceholder); + + result.Add( + VisitExpression( + elementInitializer.Update( + elementInitializer.AddMethod, + elementInitializer.Arguments, + implicitReceiverOpt: null, + elementInitializer.Expanded, + elementInitializer.ArgsToParamsOpt, + elementInitializer.DefaultArguments, + elementInitializer.InvokedAsExtensionMethod, + elementInitializer.ResultKind, + elementInitializer.Type))); + } + } } // Rewrite collection initializer add method calls: // 2) new List { 1 }; // ~ - private void AddCollectionInitializers(ArrayBuilder result, BoundExpression? rewrittenReceiver, ImmutableArray initializers) + private void AddCollectionInitializers(ArrayBuilder result, BoundExpression rewrittenReceiver, ImmutableArray initializers) { Debug.Assert(rewrittenReceiver is { } || _inExpressionLambda); @@ -97,7 +136,7 @@ private void AddCollectionInitializers(ArrayBuilder result, Bou BoundExpression? rewrittenInitializer; if (initializer.Kind == BoundKind.CollectionElementInitializer) { - rewrittenInitializer = MakeCollectionInitializer(rewrittenReceiver, (BoundCollectionElementInitializer)initializer); + rewrittenInitializer = MakeCollectionInitializer((BoundCollectionElementInitializer)initializer); } else { @@ -137,7 +176,7 @@ private BoundExpression MakeDynamicCollectionInitializer(BoundExpression rewritt // Rewrite collection initializer element Add method call: // new List { 1, 2, 3 }; OR new List { { 1, 2 }, 3 }; OR [1, 2, 3] // ~ ~~~~~~~~ - private BoundExpression? MakeCollectionInitializer(BoundExpression? rewrittenReceiver, BoundCollectionElementInitializer initializer) + private BoundExpression? MakeCollectionInitializer(BoundCollectionElementInitializer initializer) { MethodSymbol addMethod = initializer.AddMethod; @@ -146,22 +185,22 @@ private BoundExpression MakeDynamicCollectionInitializer(BoundExpression rewritt .Skip(addMethod.IsExtensionMethod ? 1 : 0) .All(p => p.RefKind is RefKind.None or RefKind.In or RefKind.RefReadOnlyParameter)); Debug.Assert(initializer.Arguments.Any()); - Debug.Assert(rewrittenReceiver != null || _inExpressionLambda); + Debug.Assert(!_inExpressionLambda); var syntax = initializer.Syntax; if (_allowOmissionOfConditionalCalls) { - // NOTE: Calls cannot be omitted within an expression tree (CS0765); this should already - // have been checked. if (addMethod.CallsAreOmitted(initializer.SyntaxTree)) { return null; } } + BoundExpression? rewrittenReceiver = VisitExpression(initializer.ImplicitReceiverOpt); + var argumentRefKindsOpt = default(ImmutableArray); - if (addMethod.Parameters[0].RefKind == RefKind.Ref) + if (initializer.InvokedAsExtensionMethod && addMethod.Parameters[0].RefKind == RefKind.Ref) { // If the Add method is an extension which takes a `ref this` as the first parameter, implicitly add a `ref` to the argument // Initializer element syntax cannot have `ref`, `in`, or `out` keywords. @@ -186,20 +225,14 @@ private BoundExpression MakeDynamicCollectionInitializer(BoundExpression rewritt var rewrittenType = VisitType(initializer.Type); +#if DEBUG if (initializer.InvokedAsExtensionMethod) { Debug.Assert(addMethod.IsStatic); Debug.Assert(addMethod.IsExtensionMethod); - Debug.Assert(!_inExpressionLambda, "Expression trees do not support extension Add"); - rewrittenReceiver = null; - } - - if (_inExpressionLambda) - { - Debug.Assert(temps.Count == 0); - temps.Free(); - return initializer.Update(addMethod, rewrittenArguments, rewrittenReceiver, expanded: false, argsToParamsOpt: default, defaultArguments: default, invokedAsExtensionMethod: false, initializer.ResultKind, rewrittenType); + Debug.Assert(rewrittenReceiver is null); } +#endif if (Instrument) { diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StringConcat.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StringConcat.cs index 9b0daebe8a387..24bdbf5987572 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StringConcat.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StringConcat.cs @@ -14,592 +14,557 @@ namespace Microsoft.CodeAnalysis.CSharp { internal sealed partial class LocalRewriter { - /// - /// The strategy of this rewrite is to do rewrite "locally". - /// We analyze arguments of the concat in a shallow fashion assuming that - /// lowering and optimizations (including this one) is already done for the arguments. - /// Based on the arguments we select the most appropriate pattern for the current node. - /// - /// NOTE: it is not guaranteed that the node that we chose will be the most optimal since we have only - /// local information - i.e. we look at the arguments, but we do not know about siblings. - /// When we move to the parent, the node may be rewritten by this or some another optimization. - /// - /// Example: - /// result = ( "abc" + "def" + null ?? expr1 + "moo" + "baz" ) + expr2 - /// - /// Will rewrite into: - /// result = Concat("abcdef", expr2) - /// - /// However there will be transient nodes like Concat(expr1 + "moo") that will not be present in the - /// resulting tree. - /// - /// - private BoundExpression RewriteStringConcatenation(SyntaxNode syntax, BinaryOperatorKind operatorKind, BoundExpression loweredLeft, BoundExpression loweredRight, TypeSymbol type) + private static bool IsBinaryStringConcatenation([NotNullWhen(true)] BoundBinaryOperator? binaryOperator) + => binaryOperator is { OperatorKind: var kind } && IsBinaryStringConcatenation(kind); + + private static bool IsBinaryStringConcatenation(BinaryOperatorKind binaryOperator) + => binaryOperator is BinaryOperatorKind.StringConcatenation or BinaryOperatorKind.StringAndObjectConcatenation or BinaryOperatorKind.ObjectAndStringConcatenation; + + private BoundExpression VisitCompoundAssignmentStringConcatenation(BoundExpression left, BoundExpression unvisitedRight, BinaryOperatorKind operatorKind, SyntaxNode syntax) { - Debug.Assert( - operatorKind == BinaryOperatorKind.StringConcatenation || - operatorKind == BinaryOperatorKind.StringAndObjectConcatenation || - operatorKind == BinaryOperatorKind.ObjectAndStringConcatenation); + Debug.Assert(IsBinaryStringConcatenation(operatorKind)); + Debug.Assert(!_inExpressionLambda); - if (_inExpressionLambda) + ArrayBuilder arguments; + if (unvisitedRight is BoundBinaryOperator { InterpolatedStringHandlerData: null } rightBinary && IsBinaryStringConcatenation(rightBinary)) + { + CollectAndVisitConcatArguments(rightBinary, left, out arguments); + Debug.Assert(ReferenceEquals(arguments[0], left)); + } + else { - return RewriteStringConcatInExpressionLambda(syntax, operatorKind, loweredLeft, loweredRight, type); + arguments = ArrayBuilder.GetInstance(); + var concatMethods = new WellKnownConcatRelatedMethods(_compilation); + VisitAndAddConcatArgumentInReverseOrder(unvisitedRight, argumentAlreadyVisited: false, arguments, ref concatMethods); + VisitAndAddConcatArgumentInReverseOrder(left, argumentAlreadyVisited: true, arguments, ref concatMethods); + arguments.ReverseContents(); } - // Convert both sides to a string (calling ToString if necessary) - loweredLeft = ConvertConcatExprToString(loweredLeft); - loweredRight = ConvertConcatExprToString(loweredRight); + return CreateStringConcat(syntax, arguments); + } - Debug.Assert(loweredLeft.Type is { } && (loweredLeft.Type.IsStringType() || loweredLeft.Type.IsErrorType()) || loweredLeft.ConstantValueOpt?.IsNull == true); - Debug.Assert(loweredRight.Type is { } && (loweredRight.Type.IsStringType() || loweredRight.Type.IsErrorType()) || loweredRight.ConstantValueOpt?.IsNull == true); + private BoundExpression VisitStringConcatenation(BoundBinaryOperator originalOperator) + { + Debug.Assert(IsBinaryStringConcatenation(originalOperator)); - // try fold two args without flattening. - var folded = TryFoldTwoConcatOperands(loweredLeft, loweredRight); - if (folded != null) + if (_inExpressionLambda) { - return folded; + // If this is an expression tree, we can't optimize anything. Just do a standard visit and return. + return RewriteStringConcatInExpressionLambda(originalOperator); } - // flatten and merge - ( expr1 + "A" ) + ("B" + expr2) ===> (expr1 + "AB" + expr2) - ArrayBuilder leftFlattened = ArrayBuilder.GetInstance(); - ArrayBuilder rightFlattened = ArrayBuilder.GetInstance(); + // We'll walk the children in a depth-first order, pull all the arguments out, and then visit them. We'll fold any constant arguments as + // we go, pulling them all into a string literal. + CollectAndVisitConcatArguments(originalOperator, visitedCompoundAssignmentLeftRead: null, out var arguments); - FlattenConcatArg(loweredLeft, leftFlattened); - FlattenConcatArg(loweredRight, rightFlattened); + return CreateStringConcat(originalOperator.Syntax, arguments); + } - if (leftFlattened.Any() && rightFlattened.Any()) + /// + /// Produces a new string.Concat call in the most efficient manner for the given arguments. It is expected that the arguments are already visited, and the following optimizations + /// have been done: + /// + /// Any consecutive constant strings or chars have been folded. + /// Any nested string.Concat calls have had their arguments deconstructed into . + /// + /// It is not valid to call this method inside an expression tree; that should be handled by a standard recursive rewrite. + /// + private BoundExpression CreateStringConcat(SyntaxNode originalSyntax, ArrayBuilder visitedArguments) + { + Debug.Assert(!_inExpressionLambda); + Debug.Assert(visitedArguments.All(arg => arg.Type!.SpecialType is SpecialType.System_String or SpecialType.System_Char or SpecialType.System_Object)); + // There are a few different lowering patterns that we take: + // + // 1. If all the added expressions were folded into a single constant, we can just return that. + // 2. If all the added expressions are strings, then we want to use one of the `string.Concat(string)`-based overloads: if 4 or less, + // we'll use one of the hardcoded overloads. Otherwise, we'll use `string.Concat(string[])`. + // 3. If all the added expressions are strings or chars, we can use the `string.Concat(ReadOnlySpan)`-based overloads. If there are + // more than 4 arguments, or if `string.Concat(ReadOnlySpan)`-based overloads are not present, we will instead fall back to + // `string.Concat(string[])`. + // 4. If there are objects among the added expression, we'll use the `string.Concat(string)`-based overloads, and call ToString on the + // arguments to avoid boxing structs by converting them into objects. If there are more than 4, we'll use `string.Concat(string[])`. + + switch (visitedArguments) { - folded = TryFoldTwoConcatOperands(leftFlattened.Last(), rightFlattened.First()); - if (folded != null) - { - rightFlattened[0] = folded; - leftFlattened.RemoveLast(); - } + case []: + // All the arguments were null or the empty string. We can just return a constant empty string. + visitedArguments.Free(); + return _factory.StringLiteral(string.Empty); + case [{ ConstantValueOpt.IsString: true } arg]: + // We were able to fold a constant, so we can just return that constant. + visitedArguments.Free(); + return arg; + case [{ ConstantValueOpt: { IsChar: true, CharValue: var @char } } arg]: + // We were able to fold a constant, so we can just return that constant. + visitedArguments.Free(); + return _factory.StringLiteral(@char.ToString()); } - leftFlattened.AddRange(rightFlattened); - rightFlattened.Free(); - - BoundExpression? result; + var concatKind = StringConcatenationRewriteKind.AllStrings; - switch (leftFlattened.Count) + foreach (var arg in visitedArguments) { - case 0: - result = _factory.StringLiteral(string.Empty); - break; + var argumentType = arg.Type; + // Null arguments should have been eliminated before now. + Debug.Assert(argumentType is not null); + switch (argumentType.SpecialType) + { + case SpecialType.System_String: + continue; - case 1: - // All code paths which reach here (through TryFoldTwoConcatOperands) have already called - // RewriteStringConcatenationOneExpr if necessary - result = leftFlattened[0]; - break; + case SpecialType.System_Char: + // If we're concating a constant char, we can just treat it as if it's a one-character string, which is more preferable. + if (concatKind == StringConcatenationRewriteKind.AllStrings && arg.ConstantValueOpt is not { IsChar: true }) + { + concatKind = StringConcatenationRewriteKind.AllStringsOrChars; + } + continue; - case 2: - var left = leftFlattened[0]; - var right = leftFlattened[1]; + default: + concatKind = StringConcatenationRewriteKind.InvolvesObjects; + break; + } - if (!TryRewriteStringConcatenationWithSpanBasedConcat(syntax, leftFlattened, out result)) - { - result = RewriteStringConcatenationTwoExprs(syntax, left, right); - } - break; + // We explicitly continued in the string and char cases, so we're in the worst case InvolvesObject at this point and can stop looping + break; + } - case 3: + switch (concatKind, visitedArguments.Count) + { + case (_, 0): + throw ExceptionUtilities.Unreachable(); + + case (_, 1): + // Only 1 argument. We need to make sure that it's not null, but otherwise we don't need to call Concat and can just use ToString. + var arg = ConvertConcatExprToString(visitedArguments[0]); + visitedArguments.Free(); + return _factory.Coalesce(arg, _factory.StringLiteral(string.Empty)); + + case (StringConcatenationRewriteKind.AllStringsOrChars, <= 4): + // We can use one of the `string.Concat(ReadOnlySpan)`-based overloads. + var concatMember = visitedArguments.Count switch { - var first = leftFlattened[0]; - var second = leftFlattened[1]; - var third = leftFlattened[2]; + 2 => SpecialMember.System_String__Concat_2ReadOnlySpans, + 3 => SpecialMember.System_String__Concat_3ReadOnlySpans, + 4 => SpecialMember.System_String__Concat_4ReadOnlySpans, + _ => throw ExceptionUtilities.Unreachable(), + }; - if (!TryRewriteStringConcatenationWithSpanBasedConcat(syntax, leftFlattened, out result)) - { - result = RewriteStringConcatenationThreeExprs(syntax, first, second, third); - } + bool needsImplicitConversionFromStringToSpan = visitedArguments.Any(arg => arg.Type is { SpecialType: SpecialType.System_String }); + var charType = _compilation.GetSpecialType(SpecialType.System_Char); + + if (!TryGetSpecialTypeMethod(originalSyntax, concatMember, out var spanConcat, isOptional: true) + || !TryGetNeededToSpanMembers(this, originalSyntax, needsImplicitConversionFromStringToSpan, charType, out var readOnlySpanCtorRefParamChar, out var stringImplicitConversionToReadOnlySpan)) + { + goto fallbackStrings; } - break; - case 4: + return RewriteStringConcatenationWithSpanBasedConcat(originalSyntax, _factory, spanConcat, stringImplicitConversionToReadOnlySpan, readOnlySpanCtorRefParamChar, visitedArguments); + + case (StringConcatenationRewriteKind.AllStrings, _): + case (StringConcatenationRewriteKind.AllStringsOrChars, _): + case (StringConcatenationRewriteKind.InvolvesObjects, _): +fallbackStrings: + +#pragma warning disable IDE0055// Fix formatting + // All other cases can be handled here +#pragma warning restore IDE0055// Fix formatting + concatMember = visitedArguments.Count switch + { + 2 => SpecialMember.System_String__ConcatStringString, + 3 => SpecialMember.System_String__ConcatStringStringString, + 4 => SpecialMember.System_String__ConcatStringStringStringString, + >= 5 => SpecialMember.System_String__ConcatStringArray, + _ => throw ExceptionUtilities.UnexpectedValue(visitedArguments.Count), + }; + + for (int i = 0; i < visitedArguments.Count; i++) { - var first = leftFlattened[0]; - var second = leftFlattened[1]; - var third = leftFlattened[2]; - var fourth = leftFlattened[3]; + visitedArguments[i] = ConvertConcatExprToString(visitedArguments[i]); + } - if (!TryRewriteStringConcatenationWithSpanBasedConcat(syntax, leftFlattened, out result)) - { - result = RewriteStringConcatenationFourExprs(syntax, first, second, third, fourth); - } + var finalArguments = visitedArguments.ToImmutableAndFree(); + + if (finalArguments.Length > 4) + { + var array = _factory.ArrayOrEmpty(_factory.SpecialType(SpecialType.System_String), finalArguments); + finalArguments = [array]; } - break; + + var method = UnsafeGetSpecialTypeMethod(originalSyntax, concatMember); + Debug.Assert(method is not null); + return BoundCall.Synthesized(originalSyntax, receiverOpt: null, initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown, method, finalArguments); default: - result = RewriteStringConcatenationManyExprs(syntax, leftFlattened.ToImmutable()); - break; + throw ExceptionUtilities.UnexpectedValue(concatKind); } - - leftFlattened.Free(); - return result; } /// - /// digs into known concat operators and unwraps their arguments - /// otherwise returns the expression as-is - /// - /// Generally we only need to recognize same node patterns that we create as a result of concatenation rewrite. + /// Given an unvisited string concat binary operator and potential compound assignment left-hand side read, visits all the arguments for passing to + /// and performs any optimizations on the arguments that can be done. This + /// includes coalescing consecutive constant strings or chars into a single string constant, and deconstructing nested string.Concat calls. /// - private void FlattenConcatArg(BoundExpression lowered, ArrayBuilder flattened) + private void CollectAndVisitConcatArguments(BoundBinaryOperator originalOperator, BoundExpression? visitedCompoundAssignmentLeftRead, out ArrayBuilder destinationArguments) { - if (TryExtractStringConcatArgs(lowered, out var arguments)) + Debug.Assert(!_inExpressionLambda); + destinationArguments = ArrayBuilder.GetInstance(); + var concatMethods = new WellKnownConcatRelatedMethods(_compilation); + pushArguments(this, originalOperator, destinationArguments, ref concatMethods); + if (visitedCompoundAssignmentLeftRead is not null) { - flattened.AddRange(arguments); + // We don't expect to be able to optimize anything about the compound assignment left read, so we just add it as-is. This assert should be kept in sync + // with the cases that can be optimized by the VisitAndAddConcatArgumentInReverseOrder method below; if we ever find a case that can be optimized, we may + // need to consider whether to do so. The visiting logic in the parent function here depends on only one argument being added for a compound assignment + // left read, so if we ever do introduce optimizations here that result in more than one argument being added to destinationArguments, we'll need to adjust + // that logic. + Debug.Assert(visitedCompoundAssignmentLeftRead is + not (BoundCall or BoundConversion { ConversionKind: ConversionKind.Boxing, Type.SpecialType: SpecialType.System_Object, Operand.Type.SpecialType: SpecialType.System_Char }) + and { ConstantValueOpt: null }); + destinationArguments.Add(visitedCompoundAssignmentLeftRead); } - else - { - // fallback - if nothing above worked, leave arg as-is - flattened.Add(lowered); - } - } + destinationArguments.ReverseContents(); - /// - /// Determines whether an expression is a known string concat operator (with or without a subsequent ?? ""), and extracts - /// its args if so. - /// - /// True if this is a call to a known string concat operator and its arguments are successfully extracted, false otherwise - private bool TryExtractStringConcatArgs(BoundExpression lowered, out ImmutableArray arguments) - { - switch (lowered) + // We push these in reverse order to take advantage of the left-recursive nature of the tree and avoid needing a second stack + static void pushArguments(LocalRewriter self, BoundBinaryOperator binaryOperator, ArrayBuilder arguments, ref WellKnownConcatRelatedMethods concatMethods) { - case BoundCall boundCall: - var method = boundCall.Method; - if (method.IsStatic && method.ContainingType.SpecialType == SpecialType.System_String) + while (true) + { + if (shouldRecurse(binaryOperator.Right, out var right)) { - if ((object)method == (object)_compilation.GetSpecialTypeMember(SpecialMember.System_String__ConcatStringString) || - (object)method == (object)_compilation.GetSpecialTypeMember(SpecialMember.System_String__ConcatStringStringString) || - (object)method == (object)_compilation.GetSpecialTypeMember(SpecialMember.System_String__ConcatStringStringStringString)) - { - arguments = boundCall.Arguments; - return true; - } - - if ((object)method == (object)_compilation.GetSpecialTypeMember(SpecialMember.System_String__ConcatStringArray)) - { - var args = boundCall.Arguments[0] as BoundArrayCreation; - if (args != null) - { - var initializer = args.InitializerOpt; - if (initializer != null) - { - arguments = initializer.Initializers; - return true; - } - } - } + pushArguments(self, right, arguments, ref concatMethods); } - break; - - case BoundNullCoalescingOperator boundCoalesce: - Debug.Assert(boundCoalesce.LeftPlaceholder is null); - Debug.Assert(boundCoalesce.LeftConversion is null); - - // The RHS may be a constant value with an identity conversion to string even - // if it is not a string: in particular, the null literal behaves this way. - // To be safe, check that the constant value is actually a string before - // attempting to access its value as a string. - - var rightConstant = boundCoalesce.RightOperand.ConstantValueOpt; - if (rightConstant != null && rightConstant.IsString && rightConstant.StringValue.Length == 0) + else { - arguments = ImmutableArray.Create(boundCoalesce.LeftOperand); - return true; + self.VisitAndAddConcatArgumentInReverseOrder(binaryOperator.Right, argumentAlreadyVisited: false, arguments, ref concatMethods); } - break; - - case BoundSequence { SideEffects.Length: 0, Value: BoundCall sequenceCall } sequence: - if ((object)sequenceCall.Method == _compilation.GetSpecialTypeMember(SpecialMember.System_String__Concat_2ReadOnlySpans) || - (object)sequenceCall.Method == _compilation.GetSpecialTypeMember(SpecialMember.System_String__Concat_3ReadOnlySpans) || - (object)sequenceCall.Method == _compilation.GetSpecialTypeMember(SpecialMember.System_String__Concat_4ReadOnlySpans)) + if (shouldRecurse(binaryOperator.Left, out var left)) { - // Faced a span-based `string.Concat` call. Since we can produce such call on the previous iterations ourselves, we need to unwrap it. - // The key thing is that we need not to only extract arguments, but also unwrap them from being spans and for chars also wrap them into `ToString` calls. - var wrappedArgs = sequenceCall.Arguments; - var unwrappedArgsBuilder = ArrayBuilder.GetInstance(capacity: wrappedArgs.Length); - - var locals = PooledHashSet.GetInstance(); - locals.AddAll(sequence.Locals); - - foreach (var wrappedArg in wrappedArgs) - { - switch (wrappedArg) - { - // Check whether a call is an implicit `string -> ReadOnlySpan` conversion - case BoundCall { Method: var argMethod, Arguments: [var singleArgument] } when (object)argMethod == _compilation.GetSpecialTypeMember(SpecialMember.System_String__op_Implicit_ToReadOnlySpanOfChar): - unwrappedArgsBuilder.Add(singleArgument); - break; - // This complicated check is for a sequence, which wraps a span around single char. - // The sequence needs to have this shape: `{ locals: , sideEffects: temp = , result: new ReadOnlySpan(in temp) }` - case BoundSequence - { - Locals.Length: 0, - SideEffects: [BoundAssignmentOperator { Right.Type.SpecialType: SpecialType.System_Char } assignment], - Value: BoundObjectCreationExpression { Constructor: var objectCreationConstructor, Arguments: [BoundLocal constructorLocal] } - } when constructorLocal == assignment.Left && - locals.Remove(constructorLocal.LocalSymbol) && - (object)objectCreationConstructor.OriginalDefinition == _compilation.GetSpecialTypeMember(SpecialMember.System_ReadOnlySpan_T__ctor_Reference) && - objectCreationConstructor.ContainingType.IsReadOnlySpanChar(): - var wrappedExpr = ConvertConcatExprToString(assignment.Right); - unwrappedArgsBuilder.Add(wrappedExpr); - break; - default: - locals.Free(); - unwrappedArgsBuilder.Free(); - arguments = default; - return false; - } - } - - if (locals.Count > 0) - { - // Not all locals are part of a known shape - locals.Free(); - unwrappedArgsBuilder.Free(); - arguments = default; - return false; - } + binaryOperator = left; + } + else + { + self.VisitAndAddConcatArgumentInReverseOrder(binaryOperator.Left, argumentAlreadyVisited: false, arguments, ref concatMethods); + break; + } + } - locals.Free(); - arguments = unwrappedArgsBuilder.ToImmutableAndFree(); + static bool shouldRecurse(BoundExpression expr, [NotNullWhen(true)] out BoundBinaryOperator? binaryOperator) + { + binaryOperator = expr as BoundBinaryOperator; + if (IsBinaryStringConcatenation(binaryOperator) && binaryOperator.InterpolatedStringHandlerData is null) + { return true; } - - break; + else + { + binaryOperator = null; + return false; + } + } } - - arguments = default; - return false; } /// - /// folds two concat operands into one expression if possible - /// otherwise returns null + /// Visits the given argument if necessary and adds it to the final arguments list. It is expected that is being in reverse order, due to the left-recursive + /// nature of the binary tree that we're traversing. /// - private BoundExpression? TryFoldTwoConcatOperands(BoundExpression loweredLeft, BoundExpression loweredRight) + /// + /// This method may end up deciding that the passed argument doesn't need to be included in the concat argument list (if, for example, it's a null constant or an empty string), and not add it + /// to . It will also fold consecutive constant strings or chars into a single string constant, to avoid unnecessary concatenation. It may also do other optimizations, + /// such as deconstructing nested string.Concat calls. + /// + private void VisitAndAddConcatArgumentInReverseOrder(BoundExpression argument, bool argumentAlreadyVisited, ArrayBuilder finalArguments, ref WellKnownConcatRelatedMethods wellKnownConcatOptimizationMethods) { - // both left and right are constants - var leftConst = loweredLeft.ConstantValueOpt; - var rightConst = loweredRight.ConstantValueOpt; - - if (leftConst != null && rightConst != null) + Debug.Assert(argument is not BoundBinaryOperator { InterpolatedStringHandlerData: null } op || !IsBinaryStringConcatenation(op)); + if (!argumentAlreadyVisited) { - // const concat may fail to fold if strings are huge. - // This would be unusual. - ConstantValue? concatenated = TryFoldTwoConcatConsts(leftConst, rightConst); - if (concatenated != null) - { - return _factory.StringLiteral(concatenated); - } + argument = VisitExpression(argument); } - // one or another is null. - if (IsNullOrEmptyStringConstant(loweredLeft)) + if (argument is BoundConversion { ConversionKind: ConversionKind.Boxing, Type.SpecialType: SpecialType.System_Object, Operand: { Type.SpecialType: SpecialType.System_Char } operand }) + { + argument = operand; + } + else if (argument is BoundCall call) { - if (IsNullOrEmptyStringConstant(loweredRight)) + if (wellKnownConcatOptimizationMethods.IsWellKnownConcatMethod(call, out var concatArguments)) { - return _factory.Literal(string.Empty); - } + for (int i = concatArguments.Length - 1; i >= 0; i--) + { + VisitAndAddConcatArgumentInReverseOrder(concatArguments[i], argumentAlreadyVisited: true, finalArguments, ref wellKnownConcatOptimizationMethods); + } - return RewriteStringConcatenationOneExpr(loweredRight); + return; + } + else if (wellKnownConcatOptimizationMethods.IsCharToString(call, out var charExpression)) + { + argument = charExpression; + } } - else if (IsNullOrEmptyStringConstant(loweredRight)) + // This is `strValue ?? ""`, possibly from a nested binary addition of an interpolated string. We can just directly use the left operand + else if (argument is BoundNullCoalescingOperator { LeftOperand: { Type.SpecialType: SpecialType.System_String } left, RightOperand: BoundLiteral { ConstantValueOpt: { IsString: true, RopeValue.IsEmpty: true } } }) { - return RewriteStringConcatenationOneExpr(loweredLeft); + argument = left; } - return null; - } + switch (argument.ConstantValueOpt) + { + case { IsNull: true } or { IsString: true, RopeValue.IsEmpty: true }: + // If this is a null constant or an empty string, then we don't need to include it in the final arguments list + return; - private static bool IsNullOrEmptyStringConstant(BoundExpression operand) - { - return (operand.ConstantValueOpt != null && string.IsNullOrEmpty(operand.ConstantValueOpt.StringValue)) || - operand.IsDefaultValue(); - } + case { IsString: true } or { IsChar: true }: + // See if we can merge this argument with the previous one + if (finalArguments.Count > 0 && finalArguments[^1].ConstantValueOpt is { IsString: true } or { IsChar: true }) + { + var constantValue = finalArguments[^1].ConstantValueOpt!; + var previous = getRope(constantValue); + var current = getRope(argument.ConstantValueOpt!); + // We're visiting arguments in reverse order, so we need to prepend this constant value, not append + finalArguments[^1] = _factory.StringLiteral(ConstantValue.CreateFromRope(Rope.Concat(current, previous))); + return; + } - /// - /// folds two concat constants into one if possible - /// otherwise returns null. - /// It is generally always possible to concat constants, unless resulting string would be too large. - /// - private static ConstantValue? TryFoldTwoConcatConsts(ConstantValue leftConst, ConstantValue rightConst) - { - var leftVal = leftConst.StringValue; - var rightVal = rightConst.StringValue; + break; + } + + finalArguments.Add(argument); - if (!leftConst.IsDefaultValue && !rightConst.IsDefaultValue) + static Rope getRope(ConstantValue constantValue) { - Debug.Assert(leftVal is { } && rightVal is { }); - if (leftVal.Length + rightVal.Length < 0) + Debug.Assert(constantValue.IsString || constantValue.IsChar); + if (constantValue.IsString) + { + return constantValue.RopeValue!; + } + else { - return null; + return Rope.ForString(constantValue.CharValue.ToString()); } } - - // TODO: if transient string allocations are an issue, consider introducing constants that contain builders. - // it may be not so easy to even get here though, since typical - // "A" + "B" + "C" + ... cases should be folded in the binder as spec requires so. - // we would be mostly picking here edge cases like "A" + (object)null + "B" + (object)null + ... - return ConstantValue.Create(leftVal + rightVal); } - /// - /// Strangely enough there is such a thing as unary concatenation and it must be rewritten. - /// - private BoundExpression RewriteStringConcatenationOneExpr(BoundExpression loweredOperand) + private enum StringConcatenationRewriteKind { - // If it's a call to 'string.Concat' (or is something which ends in '?? ""', which this method also extracts), - // we know the result cannot be null. Otherwise return loweredOperand ?? "" - if (TryExtractStringConcatArgs(loweredOperand, out _)) - { - return loweredOperand; - } - else - { - return _factory.Coalesce(loweredOperand, _factory.Literal("")); - } + AllStrings, + AllStringsOrChars, + InvolvesObjects, } - private BoundExpression RewriteStringConcatenationTwoExprs(SyntaxNode syntax, BoundExpression loweredLeft, BoundExpression loweredRight) + private struct WellKnownConcatRelatedMethods(CSharpCompilation compilation) { - Debug.Assert(loweredLeft.HasAnyErrors || loweredLeft.Type is { } && loweredLeft.Type.IsStringType()); - Debug.Assert(loweredRight.HasAnyErrors || loweredRight.Type is { } && loweredRight.Type.IsStringType()); + private readonly CSharpCompilation _compilation = compilation; - var method = UnsafeGetSpecialTypeMethod(syntax, SpecialMember.System_String__ConcatStringString); - Debug.Assert((object)method != null); + private MethodSymbol? _concatStringString = ErrorMethodSymbol.UnknownMethod; + private MethodSymbol? _concatStringStringString = ErrorMethodSymbol.UnknownMethod; + private MethodSymbol? _concatStringStringStringString = ErrorMethodSymbol.UnknownMethod; + private MethodSymbol? _concatStringArray = ErrorMethodSymbol.UnknownMethod; + private MethodSymbol? _objectToString = ErrorMethodSymbol.UnknownMethod; - return BoundCall.Synthesized(syntax, receiverOpt: null, initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown, method, loweredLeft, loweredRight); - } - - private BoundExpression RewriteStringConcatenationThreeExprs(SyntaxNode syntax, BoundExpression loweredFirst, BoundExpression loweredSecond, BoundExpression loweredThird) - { - Debug.Assert(loweredFirst.HasAnyErrors || loweredFirst.Type is { } && loweredFirst.Type.IsStringType()); - Debug.Assert(loweredSecond.HasAnyErrors || loweredSecond.Type is { } && loweredSecond.Type.IsStringType()); - Debug.Assert(loweredThird.HasAnyErrors || loweredThird.Type is { } && loweredThird.Type.IsStringType()); + public bool IsWellKnownConcatMethod(BoundCall call, out ImmutableArray arguments) + { + if (!call.ArgsToParamsOpt.IsDefault) + { + // If the arguments were explicitly ordered, we don't want to try doing any optimizations, so just assume that + // it's not a well-known concat method. + arguments = default; + return false; + } - var method = UnsafeGetSpecialTypeMethod(syntax, SpecialMember.System_String__ConcatStringStringString); - Debug.Assert((object)method != null); + if (IsConcatNonArray(call, ref _concatStringString, SpecialMember.System_String__ConcatStringString, out arguments) + || IsConcatNonArray(call, ref _concatStringStringString, SpecialMember.System_String__ConcatStringStringString, out arguments) + || IsConcatNonArray(call, ref _concatStringStringStringString, SpecialMember.System_String__ConcatStringStringStringString, out arguments)) + { + return true; + } - return BoundCall.Synthesized(syntax, receiverOpt: null, initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown, method, ImmutableArray.Create(loweredFirst, loweredSecond, loweredThird)); - } + InitializeField(ref _concatStringArray, SpecialMember.System_String__ConcatStringArray); + if ((object)call.Method == _concatStringArray && call.Arguments[0] is BoundArrayCreation array) + { + arguments = array.InitializerOpt?.Initializers ?? []; + return true; + } - private BoundExpression RewriteStringConcatenationFourExprs(SyntaxNode syntax, BoundExpression loweredFirst, BoundExpression loweredSecond, BoundExpression loweredThird, BoundExpression loweredFourth) - { - Debug.Assert(loweredFirst.HasAnyErrors || loweredFirst.Type is { } && loweredFirst.Type.IsStringType()); - Debug.Assert(loweredSecond.HasAnyErrors || loweredSecond.Type is { } && loweredSecond.Type.IsStringType()); - Debug.Assert(loweredThird.HasAnyErrors || loweredThird.Type is { } && loweredThird.Type.IsStringType()); - Debug.Assert(loweredFourth.HasAnyErrors || loweredFourth.Type is { } && loweredFourth.Type.IsStringType()); + arguments = default; + return false; + } - var method = UnsafeGetSpecialTypeMethod(syntax, SpecialMember.System_String__ConcatStringStringStringString); - Debug.Assert((object)method != null); + public bool IsCharToString(BoundCall call, [NotNullWhen(true)] out BoundExpression? charExpression) + { + InitializeField(ref _objectToString, SpecialMember.System_Object__ToString); + if (call is { Arguments: [], ReceiverOpt.Type: NamedTypeSymbol { SpecialType: SpecialType.System_Char } charType, Method: { Name: "ToString" } method } + && (object)method.GetLeastOverriddenMethod(charType) == _objectToString) + { + charExpression = call.ReceiverOpt; + return true; + } - return BoundCall.Synthesized(syntax, receiverOpt: null, initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown, method, ImmutableArray.Create(loweredFirst, loweredSecond, loweredThird, loweredFourth)); - } + charExpression = null; + return false; + } - private BoundExpression RewriteStringConcatenationManyExprs(SyntaxNode syntax, ImmutableArray loweredArgs) - { - Debug.Assert(loweredArgs.Length > 4); - Debug.Assert(loweredArgs.All(a => a.HasErrors || a.Type is { } && a.Type.IsStringType())); + private readonly void InitializeField(ref MethodSymbol? member, SpecialMember specialMember) + { + if ((object?)member == ErrorMethodSymbol.UnknownMethod) + { + member = _compilation.GetSpecialTypeMember(specialMember) as MethodSymbol; + } + } - var method = UnsafeGetSpecialTypeMethod(syntax, SpecialMember.System_String__ConcatStringArray); - Debug.Assert((object)method != null); + private readonly bool IsConcatNonArray(BoundCall call, ref MethodSymbol? concatMethod, SpecialMember concatSpecialMember, out ImmutableArray arguments) + { + InitializeField(ref concatMethod, concatSpecialMember); - var array = _factory.ArrayOrEmpty(_factory.SpecialType(SpecialType.System_String), loweredArgs); + if ((object)call.Method == concatMethod) + { + arguments = call.Arguments; + return true; + } - return BoundCall.Synthesized(syntax, receiverOpt: null, initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown, method, array); + arguments = default; + return false; + } } - private bool TryRewriteStringConcatenationWithSpanBasedConcat(SyntaxNode syntax, ArrayBuilder args, [NotNullWhen(true)] out BoundExpression? result) + private static bool TryGetNeededToSpanMembers( + LocalRewriter self, + SyntaxNode syntax, + bool needsImplicitConversionFromStringToSpan, + NamedTypeSymbol charType, + [NotNullWhen(true)] out MethodSymbol? readOnlySpanCtorRefParamChar, + out MethodSymbol? stringImplicitConversionToReadOnlySpan) { - // We should have called this only for 2, 3 or 4 arguments - Debug.Assert(args.Count is >= 2 and <= 4); + readOnlySpanCtorRefParamChar = null; + stringImplicitConversionToReadOnlySpan = null; - var preparedArgs = ArrayBuilder.GetInstance(capacity: args.Count); - - var needsSpanRefParamConstructor = false; - var needsImplicitConversionFromStringToSpan = false; - - NamedTypeSymbol? charType = null; - - foreach (var arg in args) + if (self.TryGetSpecialTypeMethod(syntax, SpecialMember.System_ReadOnlySpan_T__ctor_Reference, out MethodSymbol? readOnlySpanCtorRefParamGeneric, isOptional: true) && + readOnlySpanCtorRefParamGeneric.Parameters[0].RefKind != RefKind.Out) { - Debug.Assert(arg.HasAnyErrors || arg.Type?.IsStringType() == true); - - if (arg is BoundCall { ReceiverOpt: { Type: NamedTypeSymbol { SpecialType: SpecialType.System_Char } receiverCharType } receiver } potentialToStringCall && - (object)potentialToStringCall.Method.GetLeastOverriddenMethod(charType) == _compilation.GetSpecialTypeMember(SpecialMember.System_Object__ToString)) - { - needsSpanRefParamConstructor = true; - charType = receiverCharType; - preparedArgs.Add(receiver); - continue; - } - else if (arg.ConstantValueOpt is { IsString: true, StringValue: [char c] }) - { - preparedArgs.Add( - new BoundLiteral( - arg.Syntax, constantValueOpt: ConstantValue.Create(c), - charType ?? _compilation.GetSpecialType(SpecialType.System_Char))); // We will pull 'charType' from BoundCall, if it is bad an error has been already reported elsewhere - continue; - } - - preparedArgs.Add(arg); - needsImplicitConversionFromStringToSpan = true; + var readOnlySpanOfChar = readOnlySpanCtorRefParamGeneric.ContainingType.Construct(charType); + readOnlySpanCtorRefParamChar = readOnlySpanCtorRefParamGeneric.AsMember(readOnlySpanOfChar); } - - // It only makes sense to lower using span-based concat if at least one operand is a char. - // Because otherwise we will just wrap every string operand into span conversion and use span-based concat - // which is unnecessary IL bloat. Thus we require `needsSpanRefParamConstructor` to be true - if (!needsSpanRefParamConstructor) + else { - preparedArgs.Free(); - result = null; return false; } - // Just direct consequence of a condition above since we capture `char` type and set `needsSpanRefParamConstructor` at the same time - Debug.Assert(charType is not null); - - var concatMember = preparedArgs.Count switch - { - 2 => SpecialMember.System_String__Concat_2ReadOnlySpans, - 3 => SpecialMember.System_String__Concat_3ReadOnlySpans, - 4 => SpecialMember.System_String__Concat_4ReadOnlySpans, - _ => throw ExceptionUtilities.Unreachable(), - }; - - if (TryGetSpecialTypeMethod(syntax, concatMember, out MethodSymbol? spanConcat, isOptional: true) && - tryGetNeededToSpanMembers(this, syntax, needsImplicitConversionFromStringToSpan, charType, out MethodSymbol? readOnlySpanCtorRefParamChar, out MethodSymbol? stringImplicitConversionToReadOnlySpan)) + if (needsImplicitConversionFromStringToSpan) { - result = rewriteStringConcatenationWithSpanBasedConcat( - syntax, - _factory, - spanConcat, - stringImplicitConversionToReadOnlySpan, - readOnlySpanCtorRefParamChar, - preparedArgs.ToImmutableAndFree()); - - return true; + return self.TryGetSpecialTypeMethod(syntax, SpecialMember.System_String__op_Implicit_ToReadOnlySpanOfChar, out stringImplicitConversionToReadOnlySpan, isOptional: true); } - preparedArgs.Free(); - result = null; - return false; + return true; + } + + private static BoundExpression RewriteStringConcatenationWithSpanBasedConcat( + SyntaxNode syntax, + SyntheticBoundNodeFactory factory, + MethodSymbol spanConcat, + MethodSymbol? stringImplicitConversionToReadOnlySpan, + MethodSymbol readOnlySpanCtorRefParamChar, + ArrayBuilder args) + { + var localsBuilder = ArrayBuilder.GetInstance(); - static bool tryGetNeededToSpanMembers( - LocalRewriter self, - SyntaxNode syntax, - bool needsImplicitConversionFromStringToSpan, - NamedTypeSymbol charType, - [NotNullWhen(true)] out MethodSymbol? readOnlySpanCtorRefParamChar, - out MethodSymbol? stringImplicitConversionToReadOnlySpan) + for (int i = 0; i < args.Count; i++) { - readOnlySpanCtorRefParamChar = null; - stringImplicitConversionToReadOnlySpan = null; + BoundExpression? arg = args[i]; + Debug.Assert(arg.Type is not null); - if (self.TryGetSpecialTypeMethod(syntax, SpecialMember.System_ReadOnlySpan_T__ctor_Reference, out MethodSymbol? readOnlySpanCtorRefParamGeneric, isOptional: true) && - readOnlySpanCtorRefParamGeneric.Parameters[0].RefKind != RefKind.Out) + if (arg.Type.SpecialType == SpecialType.System_Char) { - var readOnlySpanOfChar = readOnlySpanCtorRefParamGeneric.ContainingType.Construct(charType); - readOnlySpanCtorRefParamChar = readOnlySpanCtorRefParamGeneric.AsMember(readOnlySpanOfChar); + var temp = factory.StoreToTemp(arg, out var tempAssignment); + localsBuilder.Add(temp.LocalSymbol); + + Debug.Assert(readOnlySpanCtorRefParamChar.Parameters[0].RefKind != RefKind.Out); + + var wrappedChar = new BoundObjectCreationExpression( + arg.Syntax, + readOnlySpanCtorRefParamChar, + [temp], + argumentNamesOpt: default, + argumentRefKindsOpt: [readOnlySpanCtorRefParamChar.Parameters[0].RefKind == RefKind.Ref ? RefKind.Ref : RefKindExtensions.StrictIn], + expanded: false, + argsToParamsOpt: default, + defaultArguments: default, + constantValueOpt: null, + initializerExpressionOpt: null, + type: readOnlySpanCtorRefParamChar.ContainingType); + + args[i] = new BoundSequence( + arg.Syntax, + [], + [tempAssignment], + wrappedChar, + wrappedChar.Type); } else { - return false; - } - - if (needsImplicitConversionFromStringToSpan) - { - return self.TryGetSpecialTypeMethod(syntax, SpecialMember.System_String__op_Implicit_ToReadOnlySpanOfChar, out stringImplicitConversionToReadOnlySpan, isOptional: true); + Debug.Assert(arg.HasAnyErrors || arg.Type.SpecialType == SpecialType.System_String); + Debug.Assert(stringImplicitConversionToReadOnlySpan is not null); + args[i] = BoundCall.Synthesized(arg.Syntax, receiverOpt: null, initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown, stringImplicitConversionToReadOnlySpan, arg); } - - return true; } - static BoundExpression rewriteStringConcatenationWithSpanBasedConcat( - SyntaxNode syntax, - SyntheticBoundNodeFactory factory, - MethodSymbol spanConcat, - MethodSymbol? stringImplicitConversionToReadOnlySpan, - MethodSymbol readOnlySpanCtorRefParamChar, - ImmutableArray args) - { - var preparedArgsBuilder = ArrayBuilder.GetInstance(capacity: args.Length); - var localsBuilder = ArrayBuilder.GetInstance(); + var concatCall = BoundCall.Synthesized(syntax, receiverOpt: null, initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown, spanConcat, args.ToImmutableAndFree()); - foreach (var arg in args) - { - Debug.Assert(arg.Type is not null); + var oldSyntax = factory.Syntax; + factory.Syntax = syntax; - if (arg.Type.SpecialType == SpecialType.System_Char) - { - var temp = factory.StoreToTemp(arg, out var tempAssignment); - localsBuilder.Add(temp.LocalSymbol); - - Debug.Assert(readOnlySpanCtorRefParamChar.Parameters[0].RefKind != RefKind.Out); - - var wrappedChar = new BoundObjectCreationExpression( - arg.Syntax, - readOnlySpanCtorRefParamChar, - [temp], - argumentNamesOpt: default, - argumentRefKindsOpt: [readOnlySpanCtorRefParamChar.Parameters[0].RefKind == RefKind.Ref ? RefKind.Ref : RefKindExtensions.StrictIn], - expanded: false, - argsToParamsOpt: default, - defaultArguments: default, - constantValueOpt: null, - initializerExpressionOpt: null, - type: readOnlySpanCtorRefParamChar.ContainingType); - - preparedArgsBuilder.Add(new BoundSequence( - arg.Syntax, - [], - [tempAssignment], - wrappedChar, - wrappedChar.Type)); - } - else - { - Debug.Assert(arg.HasAnyErrors || arg.Type.SpecialType == SpecialType.System_String); - Debug.Assert(stringImplicitConversionToReadOnlySpan is not null); - preparedArgsBuilder.Add(BoundCall.Synthesized(arg.Syntax, receiverOpt: null, initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown, stringImplicitConversionToReadOnlySpan, arg)); - } - } - - var concatCall = BoundCall.Synthesized(syntax, receiverOpt: null, initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown, spanConcat, preparedArgsBuilder.ToImmutableAndFree()); + var sequence = factory.Sequence( + localsBuilder.ToImmutableAndFree(), + [], + concatCall); - var oldSyntax = factory.Syntax; - factory.Syntax = syntax; - - var sequence = factory.Sequence( - localsBuilder.ToImmutableAndFree(), - [], - concatCall); - - factory.Syntax = oldSyntax; - return sequence; - } + factory.Syntax = oldSyntax; + return sequence; } /// /// Most of the above optimizations are not applicable in expression trees as the operator /// must stay a binary operator. We cannot do much beyond constant folding which is done in binder. /// - private BoundExpression RewriteStringConcatInExpressionLambda(SyntaxNode syntax, BinaryOperatorKind operatorKind, BoundExpression loweredLeft, BoundExpression loweredRight, TypeSymbol type) + private BoundExpression RewriteStringConcatInExpressionLambda(BoundBinaryOperator original) { - SpecialMember member = (operatorKind == BinaryOperatorKind.StringConcatenation) ? - SpecialMember.System_String__ConcatStringString : - SpecialMember.System_String__ConcatObjectObject; + BoundBinaryOperator? current = original; + Debug.Assert(IsBinaryStringConcatenation(current)); + var stack = ArrayBuilder.GetInstance(); + + while (true) + { + stack.Push(current); + + if (current.Left is BoundBinaryOperator left && IsBinaryStringConcatenation(left)) + { + current = left; + } + else + { + break; + } + } + + Debug.Assert(stack.Count > 0); + BoundExpression currentResult = VisitExpression(stack.Peek().Left); + + while (stack.TryPop(out current)) + { + var right = VisitExpression(current.Right); - var method = UnsafeGetSpecialTypeMethod(syntax, member); - Debug.Assert((object)method != null); + SpecialMember member = (current.OperatorKind == BinaryOperatorKind.StringConcatenation) ? + SpecialMember.System_String__ConcatStringString : + SpecialMember.System_String__ConcatObjectObject; - return new BoundBinaryOperator(syntax, operatorKind, constantValueOpt: null, method, constrainedToTypeOpt: null, default(LookupResultKind), loweredLeft, loweredRight, type); + var method = UnsafeGetSpecialTypeMethod(current.Syntax, member); + Debug.Assert(method is not null); + + currentResult = new BoundBinaryOperator(current.Syntax, current.OperatorKind, constantValueOpt: null, method, constrainedToTypeOpt: null, default(LookupResultKind), currentResult, right, current.Type); + } + + stack.Free(); + return currentResult; } /// @@ -621,18 +586,9 @@ private BoundExpression ConvertConcatExprToString(BoundExpression expr) } } - // If expression is of form `constantChar.ToString()` then unwrap it from a `ToString()` call so we can lower it to a constant later - // NOTE: We get `object.ToString()` from a compilation because we just need to compare symbols and don't need all error recovery of `TryGetSpecialTypeMethod` - if (expr is BoundCall { Type.SpecialType: SpecialType.System_String, Method: { Name: "ToString" } method, ReceiverOpt: { Type: NamedTypeSymbol { SpecialType: SpecialType.System_Char } charType, ConstantValueOpt.IsChar: true } } call && - method.GetLeastOverriddenMember(charType) == _compilation.GetSpecialTypeMember(SpecialMember.System_Object__ToString)) - { - expr = call.ReceiverOpt; - } - // Is the expression a constant char? If so, we can // simply make it a literal string instead and avoid any // allocations for converting the char to a string at run time. - // Similarly if it's a literal null, don't do anything special. if (expr is { ConstantValueOpt: { } cv }) { if (cv.SpecialType == SpecialType.System_Char) @@ -641,7 +597,8 @@ private BoundExpression ConvertConcatExprToString(BoundExpression expr) } else if (cv.IsNull) { - return expr; + // Should have been dropped by now. + throw ExceptionUtilities.Unreachable(); } } diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_WhileStatement.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_WhileStatement.cs index 910a0c4e3f7f5..ba92006518868 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_WhileStatement.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_WhileStatement.cs @@ -42,8 +42,8 @@ private BoundStatement RewriteWhileStatement( BoundNode loop, BoundExpression rewrittenCondition, BoundStatement rewrittenBody, - GeneratedLabelSymbol breakLabel, - GeneratedLabelSymbol continueLabel, + LabelSymbol breakLabel, + LabelSymbol continueLabel, bool hasErrors) { Debug.Assert(loop.Kind is BoundKind.WhileStatement or BoundKind.ForEachStatement or BoundKind.CollectionExpressionSpreadElement); @@ -108,8 +108,8 @@ private BoundStatement RewriteWhileStatement( ImmutableArray locals, BoundExpression rewrittenCondition, BoundStatement rewrittenBody, - GeneratedLabelSymbol breakLabel, - GeneratedLabelSymbol continueLabel, + LabelSymbol breakLabel, + LabelSymbol continueLabel, bool hasErrors) { if (locals.IsEmpty) diff --git a/src/Compilers/CSharp/Portable/Lowering/MethodToClassRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/MethodToClassRewriter.cs index de13dc92deff2..a870c8678eb7f 100644 --- a/src/Compilers/CSharp/Portable/Lowering/MethodToClassRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/MethodToClassRewriter.cs @@ -13,11 +13,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols { - /// - /// a bound node rewriter that rewrites types properly (which in some cases the automatically-generated - /// base class does not). This is used in the lambda rewriter, the iterator rewriter, and the async rewriter. - /// - internal abstract partial class MethodToClassRewriter : BoundTreeRewriterWithStackGuard + internal abstract partial class MethodToClassRewriter : BoundTreeToDifferentEnclosingContextRewriter { // For each captured variable, information about its replacement. May be populated lazily (that is, not all // upfront) by subclasses. Specifically, the async rewriter produces captured symbols for temps, including @@ -27,21 +23,9 @@ internal abstract partial class MethodToClassRewriter : BoundTreeRewriterWithSta // created in the first pass. protected Dictionary proxies = new Dictionary(); - // A mapping from every local variable to its replacement local variable. Local variables are replaced when - // their types change due to being inside of a generic method. Otherwise we reuse the original local (even - // though its containing method is not correct because the code is moved into another method) - protected readonly Dictionary localMap = new Dictionary(); - - // A mapping for types in the original method to types in its replacement. This is mainly necessary - // when the original method was generic, as type parameters in the original method are mapping into - // type parameters of the resulting class. - protected abstract TypeMap TypeMap { get; } - // Subclasses override this method to fetch a frame pointer. protected abstract BoundExpression FramePointer(SyntaxNode syntax, NamedTypeSymbol frameClass); - protected abstract MethodSymbol CurrentMethod { get; } - // Containing type for any synthesized members. protected abstract NamedTypeSymbol ContainingType { get; } @@ -65,30 +49,13 @@ protected MethodToClassRewriter(VariableSlotAllocator? slotAllocator, TypeCompil this._placeholderMap = new Dictionary(); } - public override BoundNode DefaultVisit(BoundNode node) - { - Debug.Fail($"Override the visitor for {node.Kind}"); - return base.DefaultVisit(node); - } - /// /// Returns true if the specified local/parameter needs to be hoisted to a field. /// Variable may be hoisted even if it is not captured, to improve debugging experience. /// protected abstract bool NeedsProxy(Symbol localOrParameter); - protected void RewriteLocals(ImmutableArray locals, ArrayBuilder newLocals) - { - foreach (var local in locals) - { - if (TryRewriteLocal(local, out LocalSymbol? newLocal)) - { - newLocals.Add(newLocal); - } - } - } - - protected bool TryRewriteLocal(LocalSymbol local, [NotNullWhen(true)] out LocalSymbol? newLocal) + protected sealed override bool TryRewriteLocal(LocalSymbol local, [NotNullWhen(true)] out LocalSymbol? newLocal) { if (NeedsProxy(local)) { @@ -97,126 +64,29 @@ protected bool TryRewriteLocal(LocalSymbol local, [NotNullWhen(true)] out LocalS return false; } - if (localMap.TryGetValue(local, out newLocal)) - { - return true; - } - - var newType = VisitType(local.Type); - if (TypeSymbol.Equals(newType, local.Type, TypeCompareKind.ConsiderEverything2)) - { - newLocal = local; - } - else - { - newLocal = new TypeSubstitutedLocalSymbol(local, TypeWithAnnotations.Create(newType), CurrentMethod); - localMap.Add(local, newLocal); - } - - return true; - } - - private ImmutableArray RewriteLocals(ImmutableArray locals) - { - if (locals.IsEmpty) return locals; - var newLocals = ArrayBuilder.GetInstance(); - RewriteLocals(locals, newLocals); - return newLocals.ToImmutableAndFree(); - } - - public override BoundNode VisitCatchBlock(BoundCatchBlock node) - { - if (!node.Locals.IsDefaultOrEmpty) - { - // Yield/await aren't supported in catch block atm, but we need to rewrite the type - // of the variables owned by the catch block. Note that one of these variables might be a closure frame reference. - var newLocals = RewriteLocals(node.Locals); - - return node.Update( - newLocals, - (BoundExpression?)this.Visit(node.ExceptionSourceOpt), - this.VisitType(node.ExceptionTypeOpt), - (BoundStatementList?)this.Visit(node.ExceptionFilterPrologueOpt), - (BoundExpression?)this.Visit(node.ExceptionFilterOpt), - (BoundBlock?)this.Visit(node.Body)!, - node.IsSynthesizedAsyncCatchAll); - } - - return base.VisitCatchBlock(node)!; - } - - public override BoundNode VisitBlock(BoundBlock node) - => VisitBlock(node, removeInstrumentation: false); - - protected BoundBlock VisitBlock(BoundBlock node, bool removeInstrumentation) - { - // Note: Instrumentation variable is intentionally not rewritten. It should never be lifted. - - var newLocals = RewriteLocals(node.Locals); - var newLocalFunctions = node.LocalFunctions; - var newStatements = VisitList(node.Statements); - var newInstrumentation = removeInstrumentation ? null : (BoundBlockInstrumentation?)Visit(node.Instrumentation); - return node.Update(newLocals, newLocalFunctions, node.HasUnsafeModifier, newInstrumentation, newStatements); + return base.TryRewriteLocal(local, out newLocal); } public abstract override BoundNode VisitScope(BoundScope node); - public override BoundNode VisitSequence(BoundSequence node) - { - var newLocals = RewriteLocals(node.Locals); - var newSideEffects = VisitList(node.SideEffects); - var newValue = (BoundExpression)this.Visit(node.Value); - var newType = this.VisitType(node.Type); - return node.Update(newLocals, newSideEffects, newValue, newType); - } - public override BoundNode VisitForStatement(BoundForStatement node) { - var newOuterLocals = RewriteLocals(node.OuterLocals); - var initializer = (BoundStatement?)this.Visit(node.Initializer); - var newInnerLocals = RewriteLocals(node.InnerLocals); - var condition = (BoundExpression?)this.Visit(node.Condition); - var increment = (BoundStatement?)this.Visit(node.Increment); - var body = (BoundStatement)this.Visit(node.Body); - return node.Update(newOuterLocals, initializer, newInnerLocals, condition, increment, body, node.BreakLabel, node.ContinueLabel); + throw ExceptionUtilities.Unreachable(); } public override BoundNode VisitDoStatement(BoundDoStatement node) { - var newLocals = RewriteLocals(node.Locals); - BoundExpression condition = (BoundExpression)this.Visit(node.Condition); - BoundStatement body = (BoundStatement)this.Visit(node.Body); - return node.Update(newLocals, condition, body, node.BreakLabel, node.ContinueLabel); + throw ExceptionUtilities.Unreachable(); } public override BoundNode VisitWhileStatement(BoundWhileStatement node) { - var newLocals = RewriteLocals(node.Locals); - BoundExpression condition = (BoundExpression)this.Visit(node.Condition); - BoundStatement body = (BoundStatement)this.Visit(node.Body); - return node.Update(newLocals, condition, body, node.BreakLabel, node.ContinueLabel); + throw ExceptionUtilities.Unreachable(); } public override BoundNode VisitUsingStatement(BoundUsingStatement node) { - var newLocals = RewriteLocals(node.Locals); - var declarations = (BoundMultipleLocalDeclarations?)this.Visit(node.DeclarationsOpt); - var expression = (BoundExpression?)this.Visit(node.ExpressionOpt); - var body = (BoundStatement)this.Visit(node.Body); - return node.Update(newLocals, declarations, expression, body, node.AwaitOpt, node.PatternDisposeInfoOpt); - } - - [return: NotNullIfNotNull(nameof(type))] - public sealed override TypeSymbol? VisitType(TypeSymbol? type) - { - return TypeMap.SubstituteType(type).Type; - } - - public override BoundNode VisitMethodInfo(BoundMethodInfo node) - { - var rewrittenMethod = VisitMethodSymbol(node.Method); - // No need to rewrite the node's type, because it is always System.Reflection.MethodInfo - return node.Update(rewrittenMethod, node.GetMethodFromHandle, node.Type); + throw ExceptionUtilities.Unreachable(); } public override BoundNode VisitPropertyAccess(BoundPropertyAccess node) @@ -262,64 +132,6 @@ public override BoundNode VisitCall(BoundCall node) rewrittenType); } - public override BoundNode VisitBinaryOperator(BoundBinaryOperator node) - { - // Local rewriter should have already rewritten interpolated strings into their final form of calls and gotos - Debug.Assert(node.InterpolatedStringHandlerData is null); - - return node.Update( - node.OperatorKind, - node.ConstantValueOpt, - VisitMethodSymbol(node.Method), - VisitType(node.ConstrainedToType), - node.ResultKind, - (BoundExpression)Visit(node.Left), - (BoundExpression)Visit(node.Right), - VisitType(node.Type)); - } - - public override BoundNode VisitUnaryOperator(BoundUnaryOperator node) - => node.Update( - node.OperatorKind, - (BoundExpression)Visit(node.Operand), - node.ConstantValueOpt, - VisitMethodSymbol(node.MethodOpt), - VisitType(node.ConstrainedToTypeOpt), - node.ResultKind, - VisitType(node.Type)); - - public override BoundNode? VisitConversion(BoundConversion node) - { - var conversion = node.Conversion; - - if (conversion.Method is not null) - { - conversion = conversion.SetConversionMethod(VisitMethodSymbol(conversion.Method)); - } - - return node.Update( - (BoundExpression)Visit(node.Operand), - conversion, - node.IsBaseConversion, - node.Checked, - node.ExplicitCastInCode, - node.ConstantValueOpt, - node.ConversionGroupOpt, - VisitType(node.Type)); - } - - public override BoundNode? VisitUserDefinedConditionalLogicalOperator(BoundUserDefinedConditionalLogicalOperator node) - => node.Update( - node.OperatorKind, - VisitMethodSymbol(node.LogicalOperator), - VisitMethodSymbol(node.TrueOperator), - VisitMethodSymbol(node.FalseOperator), - VisitType(node.ConstrainedToTypeOpt), - node.ResultKind, - (BoundExpression)Visit(node.Left), - (BoundExpression)Visit(node.Right), - VisitType(node.Type)); - private MethodSymbol GetMethodWrapperForBaseNonVirtualCall(MethodSymbol methodBeingCalled, SyntaxNode syntax) { var newMethod = GetOrCreateBaseFunctionWrapper(methodBeingCalled, syntax); @@ -411,7 +223,7 @@ public sealed override BoundNode VisitLocal(BoundLocal node) // if a local needs a proxy it should have been allocated by its declaration node. Debug.Assert(!NeedsProxy(node.LocalSymbol)); - return VisitUnhoistedLocal(node); + return base.VisitLocal(node)!; } public override BoundNode? VisitLocalId(BoundLocalId node) @@ -442,16 +254,6 @@ private bool TryGetHoistedField(Symbol variable, [NotNullWhen(true)] out FieldSy return false; } - private BoundNode VisitUnhoistedLocal(BoundLocal node) - { - if (this.localMap.TryGetValue(node.LocalSymbol, out LocalSymbol? replacementLocal)) - { - return new BoundLocal(node.Syntax, replacementLocal, node.ConstantValueOpt, replacementLocal.Type, node.HasErrors); - } - - return base.VisitLocal(node)!; - } - public override BoundNode VisitAwaitableInfo(BoundAwaitableInfo node) { var awaitablePlaceholder = node.AwaitableInstancePlaceholder; @@ -558,29 +360,6 @@ public override BoundNode VisitFieldAccess(BoundFieldAccess node) return node.Update(receiverOpt, fieldSymbol, node.ConstantValueOpt, node.ResultKind, type); } - public override BoundNode VisitObjectCreationExpression(BoundObjectCreationExpression node) - { - var rewritten = (BoundObjectCreationExpression?)base.VisitObjectCreationExpression(node); - Debug.Assert(rewritten != null); - if (!TypeSymbol.Equals(rewritten.Type, node.Type, TypeCompareKind.ConsiderEverything2) && (object)node.Constructor != null) - { - MethodSymbol ctor = VisitMethodSymbol(node.Constructor); - rewritten = rewritten.Update( - ctor, - rewritten.Arguments, - rewritten.ArgumentNamesOpt, - rewritten.ArgumentRefKindsOpt, - rewritten.Expanded, - rewritten.ArgsToParamsOpt, - rewritten.DefaultArguments, - rewritten.ConstantValueOpt, - rewritten.InitializerExpressionOpt, - rewritten.Type); - } - - return rewritten; - } - public override BoundNode VisitDelegateCreationExpression(BoundDelegateCreationExpression node) { BoundExpression originalArgument = node.Argument; @@ -598,60 +377,8 @@ public override BoundNode VisitDelegateCreationExpression(BoundDelegateCreationE return node.Update(rewrittenArgument, method, node.IsExtensionMethod, node.WasTargetTyped, type); } - public override BoundNode VisitFunctionPointerLoad(BoundFunctionPointerLoad node) - { - return node.Update(VisitMethodSymbol(node.TargetMethod), VisitType(node.ConstrainedToTypeOpt), VisitType(node.Type)); - } - - public override BoundNode VisitLoweredConditionalAccess(BoundLoweredConditionalAccess node) - { - var receiver = (BoundExpression)this.Visit(node.Receiver); - var whenNotNull = (BoundExpression)this.Visit(node.WhenNotNull); - var whenNullOpt = (BoundExpression?)this.Visit(node.WhenNullOpt); - TypeSymbol type = this.VisitType(node.Type); - return node.Update(receiver, VisitMethodSymbol(node.HasValueMethodOpt), whenNotNull, whenNullOpt, node.Id, node.ForceCopyOfNullableValueType, type); - } - - [return: NotNullIfNotNull(nameof(method))] - protected MethodSymbol? VisitMethodSymbol(MethodSymbol? method) - { - if (method is null) - { - return null; - } - - if (method.ContainingType.IsAnonymousType) - { - // Method of an anonymous type - var newType = (NamedTypeSymbol)TypeMap.SubstituteType(method.ContainingType).AsTypeSymbolOnly(); - if (ReferenceEquals(newType, method.ContainingType)) - { - // Anonymous type symbol was not rewritten - return method; - } - - // get a new method by name - foreach (var member in newType.GetMembers(method.Name)) - { - if (member.Kind == SymbolKind.Method) - { - return (MethodSymbol)member; - } - } - - throw ExceptionUtilities.Unreachable(); - } - else - { - // Method of a regular type - return ((MethodSymbol)method.OriginalDefinition) - .AsMember((NamedTypeSymbol)TypeMap.SubstituteType(method.ContainingType).AsTypeSymbolOnly()) - .ConstructIfGeneric(TypeMap.SubstituteTypes(method.TypeArgumentsWithAnnotations)); - } - } - [return: NotNullIfNotNull(nameof(property))] - private PropertySymbol? VisitPropertySymbol(PropertySymbol? property) + private new PropertySymbol? VisitPropertySymbol(PropertySymbol? property) { if (property is null) { @@ -685,7 +412,7 @@ public override BoundNode VisitLoweredConditionalAccess(BoundLoweredConditionalA throw ExceptionUtilities.Unreachable(); } - private FieldSymbol VisitFieldSymbol(FieldSymbol field) + private new FieldSymbol VisitFieldSymbol(FieldSymbol field) { // Property of a regular type return ((FieldSymbol)field.OriginalDefinition) @@ -714,14 +441,6 @@ public override BoundNode VisitObjectInitializerMember(BoundObjectInitializerMem return node.Update(member, arguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, node.Expanded, node.ArgsToParamsOpt, node.DefaultArguments, node.ResultKind, node.AccessorKind, receiverType, type); } - public override BoundNode VisitReadOnlySpanFromArray(BoundReadOnlySpanFromArray node) - { - BoundExpression operand = (BoundExpression)this.Visit(node.Operand); - MethodSymbol method = VisitMethodSymbol(node.ConversionMethod); - TypeSymbol type = this.VisitType(node.Type); - return node.Update(operand, method, type); - } - private static bool BaseReferenceInReceiverWasRewritten([NotNullWhen(true)] BoundExpression? originalReceiver, [NotNullWhen(true)] BoundExpression? rewrittenReceiver) { return originalReceiver is { Kind: BoundKind.BaseReference } && @@ -732,7 +451,7 @@ private static bool BaseReferenceInReceiverWasRewritten([NotNullWhen(true)] Boun /// A wrapper method that is created for non-virtually calling a base-class /// virtual method from other classes (like those created for lambdas...). /// - private sealed partial class BaseMethodWrapperSymbol : SynthesizedMethodBaseSymbol + internal sealed partial class BaseMethodWrapperSymbol : SynthesizedMethodBaseSymbol { internal BaseMethodWrapperSymbol(NamedTypeSymbol containingType, MethodSymbol methodBeingWrapped, SyntaxNode syntax, string name) : base(containingType, methodBeingWrapped, syntax.SyntaxTree.GetReference(syntax), syntax.GetLocation(), name, DeclarationModifiers.Private, @@ -756,13 +475,6 @@ internal BaseMethodWrapperSymbol(NamedTypeSymbol containingType, MethodSymbol me AssignTypeMapAndTypeParameters(typeMap, typeParameters); } - - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) - { - base.AddSynthesizedAttributes(moduleBuilder, ref attributes); - - AddSynthesizedAttribute(ref attributes, this.DeclaringCompilation.TrySynthesizeAttribute(WellKnownMember.System_Diagnostics_DebuggerHiddenAttribute__ctor)); - } } } } diff --git a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/IteratorAndAsyncCaptureWalker.cs b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/IteratorAndAsyncCaptureWalker.cs index d8ce97fa4088f..26b8010c98131 100644 --- a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/IteratorAndAsyncCaptureWalker.cs +++ b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/IteratorAndAsyncCaptureWalker.cs @@ -284,6 +284,8 @@ public override BoundNode VisitParameter(BoundParameter node) private void TryHoistTopLevelParameter(BoundParameter node) { + Debug.Assert(!topLevelMethod.GetIsNewExtensionMember()); // extension methods were replaced with implementation methods earlier in the pipeline + if (node.ParameterSymbol.ContainingSymbol == topLevelMethod) { CaptureVariable(node.ParameterSymbol, node.Syntax); diff --git a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineTypeSymbol.cs b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineTypeSymbol.cs index 1dbc00cef4295..3756651f2dada 100644 --- a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineTypeSymbol.cs @@ -19,7 +19,7 @@ internal abstract class StateMachineTypeSymbol : SynthesizedContainer, ISynthesi public readonly MethodSymbol KickoffMethod; public StateMachineTypeSymbol(VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, MethodSymbol kickoffMethod, int kickoffMethodOrdinal) - : base(MakeName(slotAllocatorOpt, compilationState, kickoffMethod, kickoffMethodOrdinal), kickoffMethod) + : base(MakeName(slotAllocatorOpt, compilationState, kickoffMethod, kickoffMethodOrdinal), TypeMap.ConcatMethodTypeParameters(kickoffMethod, stopAt: null)) { Debug.Assert(kickoffMethod != null); this.KickoffMethod = kickoffMethod; diff --git a/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs b/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs index 20589154af9bc..a796c718606bb 100644 --- a/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs +++ b/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs @@ -72,22 +72,6 @@ protected override void MethodChecks(BindingDiagnosticBag diagnostics) // TODO: move more functionality into here, making these symbols more lazy } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) - { - base.AddSynthesizedAttributes(moduleBuilder, ref attributes); - - // do not generate attributes for members of compiler-generated types: - if (ContainingType.IsImplicitlyDeclared) - { - return; - } - - var compilation = this.DeclaringCompilation; - - AddSynthesizedAttribute(ref attributes, - compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor)); - } - public sealed override ImmutableArray TypeParameters { get { return _typeParameters; } diff --git a/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs b/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs index 58eb9d9a7c2d9..15748f836eb9c 100644 --- a/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs +++ b/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs @@ -148,7 +148,7 @@ public void AddNestedType(NamedTypeSymbol nestedType) { // It is only valid to call this on a bound node factory with a module builder. Debug.Assert(ModuleBuilderOpt is { }); - ModuleBuilderOpt.AddSynthesizedDefinition(CurrentType, nestedType.GetCciAdapter()); + ModuleBuilderOpt.AddSynthesizedDefinition(nestedType.ContainingType, nestedType.GetCciAdapter()); } public void OpenNestedType(NamedTypeSymbol nestedType) @@ -479,6 +479,11 @@ public BoundBlock Block(ImmutableArray locals, ImmutableArray locals, ImmutableArray localFunctions, ImmutableArray statements) + { + return Block(locals, ImmutableArray.CastUp(localFunctions), statements); + } + + public BoundBlock Block(ImmutableArray locals, ImmutableArray localFunctions, ImmutableArray statements) { return new BoundBlock(Syntax, locals, localFunctions, hasUnsafeModifier: false, instrumentation: null, statements) { WasCompilerGenerated = true }; } @@ -858,35 +863,40 @@ public BoundCall Call(BoundExpression? receiver, MethodSymbol method, ImmutableA return new BoundCall( Syntax, receiver, initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown, method, args, - argumentNamesOpt: default(ImmutableArray), argumentRefKindsOpt: getArgumentRefKinds(method, useStrictArgumentRefKinds), isDelegateCall: false, expanded: false, + argumentNamesOpt: default(ImmutableArray), argumentRefKindsOpt: ArgumentRefKindsFromParameterRefKinds(method, useStrictArgumentRefKinds), isDelegateCall: false, expanded: false, invokedAsExtensionMethod: false, argsToParamsOpt: default(ImmutableArray), defaultArguments: default(BitVector), resultKind: LookupResultKind.Viable, type: method.ReturnType, hasErrors: method.OriginalDefinition is ErrorMethodSymbol) { WasCompilerGenerated = true }; + } - static ImmutableArray getArgumentRefKinds(MethodSymbol method, bool useStrictArgumentRefKinds) + public static ImmutableArray ArgumentRefKindsFromParameterRefKinds(MethodSymbol method, bool useStrictArgumentRefKinds) + { + var result = method.ParameterRefKinds; + + if (!result.IsDefaultOrEmpty && (result.Contains(RefKind.RefReadOnlyParameter) || + (useStrictArgumentRefKinds && result.Contains(RefKind.In)))) { - var result = method.ParameterRefKinds; + var builder = ArrayBuilder.GetInstance(result.Length); - if (!result.IsDefaultOrEmpty && (result.Contains(RefKind.RefReadOnlyParameter) || - (useStrictArgumentRefKinds && result.Contains(RefKind.In)))) + foreach (var refKind in result) { - var builder = ArrayBuilder.GetInstance(result.Length); - - foreach (var refKind in result) - { - builder.Add(refKind switch - { - RefKind.In or RefKind.RefReadOnlyParameter when useStrictArgumentRefKinds => RefKindExtensions.StrictIn, - RefKind.RefReadOnlyParameter => RefKind.In, - _ => refKind - }); - } - - return builder.ToImmutableAndFree(); + builder.Add(ArgumentRefKindFromParameterRefKind(refKind, useStrictArgumentRefKinds)); } - return result; + return builder.ToImmutableAndFree(); } + + return result; + } + + public static RefKind ArgumentRefKindFromParameterRefKind(RefKind refKind, bool useStrictArgumentRefKinds) + { + return refKind switch + { + RefKind.In or RefKind.RefReadOnlyParameter when useStrictArgumentRefKinds => RefKindExtensions.StrictIn, + RefKind.RefReadOnlyParameter => RefKind.In, + _ => refKind + }; } public BoundCall Call(BoundExpression? receiver, MethodSymbol method, ImmutableArray refKinds, ImmutableArray args) diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index c0c710471165a..02c032c391286 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -84,7 +84,7 @@ internal enum TerminatorState IsEndOfFunctionPointerParameterList = 1 << 23, IsEndOfFunctionPointerParameterListErrored = 1 << 24, IsEndOfFunctionPointerCallingConvention = 1 << 25, - IsEndOfRecordOrClassOrStructOrInterfaceSignature = 1 << 26, + IsEndOfTypeSignature = 1 << 26, IsExpressionOrPatternInCaseLabelOfSwitchStatement = 1 << 27, IsPatternInSwitchExpressionArm = 1 << 28, } @@ -128,7 +128,7 @@ private bool IsTerminator() case TerminatorState.IsEndOfFunctionPointerParameterList when this.IsEndOfFunctionPointerParameterList(errored: false): case TerminatorState.IsEndOfFunctionPointerParameterListErrored when this.IsEndOfFunctionPointerParameterList(errored: true): case TerminatorState.IsEndOfFunctionPointerCallingConvention when this.IsEndOfFunctionPointerCallingConvention(): - case TerminatorState.IsEndOfRecordOrClassOrStructOrInterfaceSignature when this.IsEndOfRecordOrClassOrStructOrInterfaceSignature(): + case TerminatorState.IsEndOfTypeSignature when this.IsEndOfTypeSignature(): return true; } } @@ -1634,24 +1634,25 @@ private bool IsPartialType() private bool IsPartialMember() { - // note(cyrusn): this could have been written like so: - // - // return - // this.CurrentToken.ContextualKind == SyntaxKind.PartialKeyword && - // this.PeekToken(1).Kind == SyntaxKind.VoidKeyword; - // - // However, we want to be lenient and allow the user to write - // 'partial' in most modifier lists. We will then provide them with - // a more specific message later in binding that they are doing - // something wrong. - // - // Some might argue that the simple check would suffice. - // However, we'd like to maintain behavior with - // previously shipped versions, and so we're keeping this code. + Debug.Assert(this.CurrentToken.ContextualKind == SyntaxKind.PartialKeyword); + + // Check for: + // partial event + if (this.PeekToken(1).Kind == SyntaxKind.EventKeyword) + { + return true; + } - // Here we check for: + // Check for constructor: + // partial Identifier( + if (this.PeekToken(1).Kind == SyntaxKind.IdentifierToken && + this.PeekToken(2).Kind == SyntaxKind.OpenParenToken) + { + return IsFeatureEnabled(MessageID.IDS_FeaturePartialEventsAndConstructors); + } + + // Check for method/property: // partial ReturnType MemberName - Debug.Assert(this.CurrentToken.ContextualKind == SyntaxKind.PartialKeyword); using var _ = this.GetDisposableResetPoint(resetOnDispose: true); this.EatToken(); // partial @@ -1692,13 +1693,13 @@ private MemberDeclarationSyntax ParseTypeDeclaration(SyntaxList attributes, SyntaxListBuilder modifiers) + private TypeDeclarationSyntax ParseMainTypeDeclaration(SyntaxList attributes, SyntaxListBuilder modifiers) { Debug.Assert(this.CurrentToken.Kind is SyntaxKind.ClassKeyword or SyntaxKind.StructKeyword or SyntaxKind.InterfaceKeyword || - this.CurrentToken.ContextualKind == SyntaxKind.RecordKeyword); + this.CurrentToken.ContextualKind is SyntaxKind.RecordKeyword or SyntaxKind.ExtensionKeyword); // "top-level" expressions and statements should never occur inside an asynchronous context Debug.Assert(!IsInAsync); @@ -1728,19 +1729,34 @@ private TypeDeclarationSyntax ParseClassOrStructOrInterfaceDeclaration(SyntaxLis keyword = ConvertToKeyword(this.EatToken()); } + bool isExtension = keyword.Kind == SyntaxKind.ExtensionKeyword; var outerSaveTerm = _termState; - _termState |= TerminatorState.IsEndOfRecordOrClassOrStructOrInterfaceSignature; + _termState |= TerminatorState.IsEndOfTypeSignature; var saveTerm = _termState; _termState |= TerminatorState.IsPossibleAggregateClauseStartOrStop; - var name = this.ParseIdentifierToken(); + SyntaxToken? name; + if (isExtension) + { + name = null; + if (this.CurrentToken.Kind == SyntaxKind.IdentifierToken) + { + keyword = AddTrailingSkippedSyntax(keyword, this.AddError(this.EatToken(), ErrorCode.ERR_ExtensionDisallowsName)); + } + } + else + { + name = this.ParseIdentifierToken(); + } + var typeParameters = this.ParseTypeParameterList(); - var paramList = CurrentToken.Kind == SyntaxKind.OpenParenToken - ? ParseParenthesizedParameterList() : null; + // For extension declarations, there must be a parameter list + var paramList = CurrentToken.Kind == SyntaxKind.OpenParenToken || isExtension + ? ParseParenthesizedParameterList(forExtension: isExtension) : null; - var baseList = this.ParseBaseList(); + var baseList = isExtension ? null : this.ParseBaseList(); _termState = saveTerm; // Parse class body @@ -1882,7 +1898,7 @@ bool tryScanRecordStart([NotNullWhen(true)] out SyntaxToken? keyword, out Syntax } static TypeDeclarationSyntax constructTypeDeclaration(ContextAwareSyntax syntaxFactory, SyntaxList attributes, SyntaxListBuilder modifiers, SyntaxToken keyword, SyntaxToken? recordModifier, - SyntaxToken name, TypeParameterListSyntax typeParameters, ParameterListSyntax? paramList, BaseListSyntax baseList, SyntaxListBuilder constraints, + SyntaxToken? name, TypeParameterListSyntax typeParameters, ParameterListSyntax? paramList, BaseListSyntax? baseList, SyntaxListBuilder constraints, SyntaxToken? openBrace, SyntaxListBuilder members, SyntaxToken? closeBrace, SyntaxToken semicolon) { var modifiersList = (SyntaxList)modifiers.ToList(); @@ -1891,6 +1907,7 @@ static TypeDeclarationSyntax constructTypeDeclaration(ContextAwareSyntax syntaxF switch (keyword.Kind) { case SyntaxKind.ClassKeyword: + Debug.Assert(name is not null); return syntaxFactory.ClassDeclaration( attributes, modifiersList, @@ -1906,6 +1923,7 @@ static TypeDeclarationSyntax constructTypeDeclaration(ContextAwareSyntax syntaxF semicolon); case SyntaxKind.StructKeyword: + Debug.Assert(name is not null); return syntaxFactory.StructDeclaration( attributes, modifiersList, @@ -1921,6 +1939,7 @@ static TypeDeclarationSyntax constructTypeDeclaration(ContextAwareSyntax syntaxF semicolon); case SyntaxKind.InterfaceKeyword: + Debug.Assert(name is not null); return syntaxFactory.InterfaceDeclaration( attributes, modifiersList, @@ -1939,6 +1958,7 @@ static TypeDeclarationSyntax constructTypeDeclaration(ContextAwareSyntax syntaxF // record struct ... // record ... // record class ... + Debug.Assert(name is not null); SyntaxKind declarationKind = recordModifier?.Kind == SyntaxKind.StructKeyword ? SyntaxKind.RecordStructDeclaration : SyntaxKind.RecordDeclaration; return syntaxFactory.RecordDeclaration( declarationKind, @@ -1956,6 +1976,21 @@ static TypeDeclarationSyntax constructTypeDeclaration(ContextAwareSyntax syntaxF closeBrace, semicolon); + case SyntaxKind.ExtensionKeyword: + Debug.Assert(name is null); + Debug.Assert(baseList is null); + return syntaxFactory.ExtensionDeclaration( + attributes, + modifiers.ToList(), + keyword, + typeParameters, + paramList, + constraints, + openBrace, + members, + closeBrace, + semicolon); + default: throw ExceptionUtilities.UnexpectedValue(keyword.Kind); } @@ -2053,8 +2088,8 @@ private bool IsPossibleAggregateClauseStartOrStop() private BaseListSyntax ParseBaseList() { - // We are only called from ParseClassOrStructOrInterfaceDeclaration which unilaterally sets this. - Debug.Assert((_termState & TerminatorState.IsEndOfRecordOrClassOrStructOrInterfaceSignature) != 0); + // We are only called from ParseMainTypeDeclaration which unilaterally sets this. + Debug.Assert((_termState & TerminatorState.IsEndOfTypeSignature) != 0); var colon = this.TryEatToken(SyntaxKind.ColonToken); if (colon == null) @@ -2163,7 +2198,7 @@ private TypeParameterConstraintClauseSyntax ParseTypeParameterConstraintClause() bool haveComma; if (this.CurrentToken.Kind == SyntaxKind.OpenBraceToken - || ((_termState & TerminatorState.IsEndOfRecordOrClassOrStructOrInterfaceSignature) != 0 && this.CurrentToken.Kind == SyntaxKind.SemicolonToken) + || ((_termState & TerminatorState.IsEndOfTypeSignature) != 0 && this.CurrentToken.Kind == SyntaxKind.SemicolonToken) || this.CurrentToken.Kind == SyntaxKind.EqualsGreaterThanToken || this.CurrentToken.ContextualKind == SyntaxKind.WhereKeyword) { @@ -2389,6 +2424,12 @@ private bool IsTypeDeclarationStart() // older code that is not using C# 9 we conditionally parse based on langversion return IsFeatureEnabled(MessageID.IDS_FeatureRecords); } + + if (IsExtensionContainerStart()) + { + return true; + } + return false; default: @@ -3064,6 +3105,11 @@ private MemberDeclarationSyntax ParseMemberDeclarationCore(SyntaxKind parentKind bool isPossibleTypeDeclaration; this.ParseModifiers(modifiers, forAccessors: false, forTopLevelStatements: false, out isPossibleTypeDeclaration); + if (IsExtensionContainerStart()) + { + return this.ParseMainTypeDeclaration(attributes, modifiers); + } + // Check for constructor form if (this.CurrentToken.Kind == SyntaxKind.IdentifierToken && this.PeekToken(1).Kind == SyntaxKind.OpenParenToken) { @@ -3193,6 +3239,11 @@ private MemberDeclarationSyntax ParseMemberDeclarationCore(SyntaxKind parentKind } } + private bool IsExtensionContainerStart() + { + return this.CurrentToken.ContextualKind == SyntaxKind.ExtensionKeyword && IsFeatureEnabled(MessageID.IDS_FeatureExtensions); + } + // if the modifiers do not contain async or replace and the type is the identifier "async" or "replace", then // add that identifier to the modifiers and assign a new type from the identifierOrThisOpt and the // type parameter list @@ -3307,7 +3358,7 @@ private ConstructorDeclarationSyntax ParseConstructorDeclaration( _termState |= TerminatorState.IsEndOfMethodSignature; try { - var paramList = this.ParseParenthesizedParameterList(); + var paramList = this.ParseParenthesizedParameterList(forExtension: false); var initializer = this.CurrentToken.Kind == SyntaxKind.ColonToken ? this.ParseConstructorInitializer() : null; @@ -3447,7 +3498,7 @@ private bool IsEndOfTypeParameterList() private bool IsEndOfMethodSignature() => this.CurrentToken.Kind is SyntaxKind.SemicolonToken or SyntaxKind.OpenBraceToken; - private bool IsEndOfRecordOrClassOrStructOrInterfaceSignature() + private bool IsEndOfTypeSignature() { return this.CurrentToken.Kind is SyntaxKind.SemicolonToken or SyntaxKind.OpenBraceToken; } @@ -3473,7 +3524,7 @@ private MethodDeclarationSyntax ParseMethodDeclaration( var saveTerm = _termState; _termState |= TerminatorState.IsEndOfMethodSignature; - var paramList = this.ParseParenthesizedParameterList(); + var paramList = this.ParseParenthesizedParameterList(forExtension: false); var constraints = default(SyntaxListBuilder); if (this.CurrentToken.ContextualKind == SyntaxKind.WhereKeyword) @@ -3685,7 +3736,7 @@ private ConversionOperatorDeclarationSyntax TryParseConversionOperatorDeclaratio type = ParseIdentifierName(); } - var paramList = this.ParseParenthesizedParameterList(); + var paramList = this.ParseParenthesizedParameterList(forExtension: false); this.ParseBlockAndExpressionBodiesWithSemicolon(out var blockBody, out var expressionBody, out var semicolon); @@ -3889,7 +3940,7 @@ private MemberDeclarationSyntax ParseOperatorDeclaration( } } - var paramList = this.ParseParenthesizedParameterList(); + var paramList = this.ParseParenthesizedParameterList(forExtension: false); switch (paramList.Parameters.Count) { @@ -4505,14 +4556,14 @@ private static SyntaxKind GetAccessorKind(SyntaxToken accessorName) }; } - internal ParameterListSyntax ParseParenthesizedParameterList() + internal ParameterListSyntax ParseParenthesizedParameterList(bool forExtension) { - if (this.IsIncrementalAndFactoryContextMatches && CanReuseParameterList(this.CurrentNode as CSharp.Syntax.ParameterListSyntax)) + if (this.IsIncrementalAndFactoryContextMatches && CanReuseParameterList(this.CurrentNode as CSharp.Syntax.ParameterListSyntax, allowOptionalIdentifier: forExtension)) { return (ParameterListSyntax)this.EatNode(); } - var parameters = this.ParseParameterList(out var open, out var close, SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken); + var parameters = this.ParseParameterList(out var open, out var close, SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, forExtension); return _syntaxFactory.ParameterList(open, parameters, close); } @@ -4523,11 +4574,11 @@ internal BracketedParameterListSyntax ParseBracketedParameterList() return (BracketedParameterListSyntax)this.EatNode(); } - var parameters = this.ParseParameterList(out var open, out var close, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken); + var parameters = this.ParseParameterList(out var open, out var close, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken, forExtension: false); return _syntaxFactory.BracketedParameterList(open, parameters, close); } - private static bool CanReuseParameterList(CSharp.Syntax.ParameterListSyntax list) + private static bool CanReuseParameterList(Syntax.ParameterListSyntax list, bool allowOptionalIdentifier) { if (list == null) { @@ -4546,7 +4597,7 @@ private static bool CanReuseParameterList(CSharp.Syntax.ParameterListSyntax list foreach (var parameter in list.Parameters) { - if (!CanReuseParameter(parameter)) + if (!CanReuseParameter(parameter, allowOptionalIdentifier)) { return false; } @@ -4555,7 +4606,7 @@ private static bool CanReuseParameterList(CSharp.Syntax.ParameterListSyntax list return true; } - private static bool CanReuseBracketedParameterList(CSharp.Syntax.BracketedParameterListSyntax list) + private static bool CanReuseBracketedParameterList(Syntax.BracketedParameterListSyntax list) { if (list == null) { @@ -4574,7 +4625,7 @@ private static bool CanReuseBracketedParameterList(CSharp.Syntax.BracketedParame foreach (var parameter in list.Parameters) { - if (!CanReuseParameter(parameter)) + if (!CanReuseParameter(parameter, allowOptionalIdentifier: false)) { return false; } @@ -4587,22 +4638,28 @@ private SeparatedSyntaxList ParseParameterList( out SyntaxToken open, out SyntaxToken close, SyntaxKind openKind, - SyntaxKind closeKind) + SyntaxKind closeKind, + bool forExtension) { open = this.EatToken(openKind); var saveTerm = _termState; _termState |= TerminatorState.IsEndOfParameterList; + Func parseElement = forExtension + ? static @this => @this.ParseParameter(allowOptionalIdentifier: true) + : static @this => @this.ParseParameter(allowOptionalIdentifier: false); + var parameters = ParseCommaSeparatedSyntaxList( ref open, closeKind, static @this => @this.IsPossibleParameter(), - static @this => @this.ParseParameter(), + parseElement, skipBadParameterListTokens, allowTrailingSeparator: false, - requireOneElement: false, + requireOneElement: forExtension, // For extension declarations, we require at least one receiver parameter allowSemicolonAsSeparator: false); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : consider suppressing parsing diagnostics on extension parameters beyond the first one _termState = saveTerm; close = this.EatToken(closeKind); @@ -4642,7 +4699,7 @@ private bool IsPossibleParameter() } } - private static bool CanReuseParameter(CSharp.Syntax.ParameterSyntax parameter) + private static bool CanReuseParameter(CSharp.Syntax.ParameterSyntax parameter, bool allowOptionalIdentifier) { if (parameter == null) { @@ -4673,14 +4730,22 @@ private static bool CanReuseParameter(CSharp.Syntax.ParameterSyntax parameter) } } + // We can only reuse parameters without identifiers (found in extension declarations) in context that allow optional identifiers. + // The reverse is fine though. Normal parameters (from non extensions) can be re-used into an extension declaration + // as all normal parameters are legal extension parameters. + if (!allowOptionalIdentifier && parameter.Identifier.Kind() == SyntaxKind.None) + { + return false; + } + return true; } #nullable enable - private ParameterSyntax ParseParameter() + private ParameterSyntax ParseParameter(bool allowOptionalIdentifier) { - if (this.IsIncrementalAndFactoryContextMatches && CanReuseParameter(this.CurrentNode as CSharp.Syntax.ParameterSyntax)) + if (this.IsIncrementalAndFactoryContextMatches && CanReuseParameter(this.CurrentNode as Syntax.ParameterSyntax, allowOptionalIdentifier)) { return (ParameterSyntax)this.EatNode(); } @@ -4699,19 +4764,22 @@ private ParameterSyntax ParseParameter() } var type = this.ParseType(mode: ParseTypeMode.Parameter); - SyntaxToken identifier; + SyntaxToken? identifier; if (this.CurrentToken.Kind == SyntaxKind.IdentifierToken && IsCurrentTokenWhereOfConstraintClause()) { - identifier = this.AddError(CreateMissingIdentifierToken(), ErrorCode.ERR_IdentifierExpected); + identifier = allowOptionalIdentifier ? null : this.AddError(CreateMissingIdentifierToken(), ErrorCode.ERR_IdentifierExpected); } else { - identifier = this.ParseIdentifierToken(); + // The receiver parameter on an extension declaration may have a name or not + identifier = allowOptionalIdentifier && this.CurrentToken.Kind != SyntaxKind.IdentifierToken + ? null + : this.ParseIdentifierToken(); } // When the user type "int goo[]", give them a useful error - if (this.CurrentToken.Kind is SyntaxKind.OpenBracketToken && this.PeekToken(1).Kind is SyntaxKind.CloseBracketToken) + if (identifier is not null && this.CurrentToken.Kind is SyntaxKind.OpenBracketToken && this.PeekToken(1).Kind is SyntaxKind.CloseBracketToken) { identifier = AddTrailingSkippedSyntax(identifier, SyntaxList.List( this.AddError(this.EatToken(), ErrorCode.ERR_BadArraySyntax), @@ -5053,25 +5121,26 @@ private void ParseVariableDeclarators( } else if (this.CurrentToken.Kind == SyntaxKind.CommaToken) { - // If we see `for (int i = 0, j < ...` then we do not want to consume j as the next declarator. + // If we see `for (int i = 0, i < ...` then we do not want to consume the second 'i' as the next declarator as it + // is more likely that the user meant to write `for (int i = 0; i < ...` instead and accidentally + // used a comma instead of a semicolon. // - // Legal forms here are `for (int i = 0, j; ...` or `for (int i = 0, j = ...` or `for (int i = 0, j)`. + // Note: the legal forms that we must keep parsing as a variable declarator are: // - // We also accept: `for (int i = 0, ;` as that's likely an intermediary state prior to writing the next - // variable. + // for (int i = 0, j, k; ... // identifier comma + // for (int i = 0, j = ... // identifier equals + // for (int i = 0, j; ... // identifier semicolon // - // Anything else we'll treat as as more likely to be the following conditional. + // We also accept: `for (int i = 0, ;` as that's likely an intermediary state prior to writing the + // next variable. Anything else we'll treat as as more likely to be the following conditional. if (flags.HasFlag(VariableFlags.ForStatement) && this.PeekToken(1).Kind != SyntaxKind.SemicolonToken) { - // `int i = 0, ...` where what follows is not an identifier. Don't treat this as the start of a - // second variable. - if (!IsTrueIdentifier(this.PeekToken(1))) - break; + var isLegalVariableDeclaratorStart = + IsTrueIdentifier(this.PeekToken(1)) && + this.PeekToken(2).Kind is SyntaxKind.CommaToken or SyntaxKind.EqualsToken or SyntaxKind.SemicolonToken; - // `int i = 0, j ...` where what follows is not something that continues a variable declaration. - // In this case, treat that `j` as the start of the condition expression instead. - if (this.PeekToken(2).Kind is not (SyntaxKind.SemicolonToken or SyntaxKind.EqualsToken or SyntaxKind.CloseParenToken)) + if (!isLegalVariableDeclaratorStart) break; } @@ -5445,7 +5514,7 @@ private bool IsLocalFunctionAfterIdentifier() using var _ = this.GetDisposableResetPoint(resetOnDispose: true); var typeParameterListOpt = this.ParseTypeParameterList(); - var paramList = ParseParenthesizedParameterList(); + var paramList = ParseParenthesizedParameterList(forExtension: false); if (!paramList.IsMissing && (this.CurrentToken.Kind is SyntaxKind.OpenBraceToken or SyntaxKind.EqualsGreaterThanToken || @@ -5505,7 +5574,7 @@ private DelegateDeclarationSyntax ParseDelegateDeclaration(SyntaxList); if (this.CurrentToken.ContextualKind == SyntaxKind.WhereKeyword) @@ -5683,7 +5752,7 @@ private bool IsTrueIdentifier() { if (this.CurrentToken.Kind == SyntaxKind.IdentifierToken) { - if (!IsCurrentTokenPartialKeywordOfPartialMethodOrType() && + if (!IsCurrentTokenPartialKeywordOfPartialMemberOrType() && !IsCurrentTokenQueryKeywordInQuery() && !IsCurrentTokenWhereOfConstraintClause()) { @@ -5730,7 +5799,7 @@ private SyntaxToken ParseIdentifierToken(ErrorCode code = ErrorCode.ERR_Identifi // show the correct parameter help in this case. So, when we see "partial" we check if it's being used // as an identifier or as a contextual keyword. If it's the latter then we bail out. See // Bug: vswhidbey/542125 - if (IsCurrentTokenPartialKeywordOfPartialMethodOrType() || IsCurrentTokenQueryKeywordInQuery()) + if (IsCurrentTokenPartialKeywordOfPartialMemberOrType() || IsCurrentTokenQueryKeywordInQuery()) { var result = CreateMissingIdentifierToken(); result = this.AddError(result, ErrorCode.ERR_InvalidExprTerm, this.CurrentToken.Text); @@ -5757,7 +5826,7 @@ private bool IsCurrentTokenQueryKeywordInQuery() return this.IsInQuery && this.IsCurrentTokenQueryContextualKeyword; } - private bool IsCurrentTokenPartialKeywordOfPartialMethodOrType() + private bool IsCurrentTokenPartialKeywordOfPartialMemberOrType() { if (this.CurrentToken.ContextualKind == SyntaxKind.PartialKeyword) { @@ -8432,7 +8501,7 @@ private bool IsPossibleMethodDeclarationFollowingNullableType() var saveTerm = _termState; _termState |= TerminatorState.IsEndOfMethodSignature; - var paramList = this.ParseParenthesizedParameterList(); + var paramList = this.ParseParenthesizedParameterList(forExtension: false); _termState = saveTerm; var separatedParameters = paramList.Parameters.GetWithSeparators(); @@ -10543,7 +10612,7 @@ private LocalFunctionStatementSyntax TryParseLocalFunctionStatementBody( TypeParameterListSyntax typeParameterListOpt = this.ParseTypeParameterList(); // "await f()" still makes sense, so don't force accept a local function if there's a type parameter list. - ParameterListSyntax paramList = this.ParseParenthesizedParameterList(); + ParameterListSyntax paramList = this.ParseParenthesizedParameterList(forExtension: false); // "await x()" is ambiguous (see note at start of this method), but we assume "await x(await y)" is meant to be a function if it's in a non-async context. if (!forceLocalFunc) { @@ -13189,7 +13258,7 @@ AnonymousMethodExpressionSyntax parseAnonymousMethodExpressionWorker() ParameterListSyntax parameterList = null; if (this.CurrentToken.Kind == SyntaxKind.OpenParenToken) { - parameterList = this.ParseParenthesizedParameterList(); + parameterList = this.ParseParenthesizedParameterList(forExtension: false); } // In mismatched braces cases (missing a }) it is possible for delegate declarations to be @@ -13264,7 +13333,7 @@ private bool IsAnonymousFunctionAsyncModifier() return true; case var kind: return IsPredefinedType(kind); - }; + } } /// diff --git a/src/Compilers/CSharp/Portable/Parser/Lexer.cs b/src/Compilers/CSharp/Portable/Parser/Lexer.cs index 22fbe4e66345a..3ef0208c74f8a 100644 --- a/src/Compilers/CSharp/Portable/Parser/Lexer.cs +++ b/src/Compilers/CSharp/Portable/Parser/Lexer.cs @@ -786,7 +786,7 @@ private bool TryScanInterpolatedString(ref TokenInfo info) if (TextWindow.PeekChar(1) is '$' or '@' or '"') { // $$ - definitely starts a raw interpolated string. - // $@ - definitely starts an interplated string. + // $@ - definitely starts an interpolated string. // // This will also match for $@@. This is an error case when the user thinks they can mix verbatim and raw // interpolations together. This will be properly handled in ScanInterpolatedStringLiteral diff --git a/src/Compilers/CSharp/Portable/PublicAPI.Shipped.txt b/src/Compilers/CSharp/Portable/PublicAPI.Shipped.txt index d5ea07698847c..8a57ade1b401c 100644 --- a/src/Compilers/CSharp/Portable/PublicAPI.Shipped.txt +++ b/src/Compilers/CSharp/Portable/PublicAPI.Shipped.txt @@ -1,6 +1,17 @@ #nullable enable [RSEXPERIMENTAL001]Microsoft.CodeAnalysis.CSharp.CSharpCompilation.GetSemanticModel(Microsoft.CodeAnalysis.SyntaxTree! syntaxTree, Microsoft.CodeAnalysis.SemanticModelOptions options) -> Microsoft.CodeAnalysis.SemanticModel! -static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetInterceptorMethod(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.InvocationExpressionSyntax! node, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.IMethodSymbol? +[RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser +[RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.Dispose() -> void +[RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.ParseLeadingTrivia() -> Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.Result +[RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.ParseNextToken() -> Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.Result +[RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.ParseTrailingTrivia() -> Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.Result +[RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.ResetTo(Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.Result result) -> void +[RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.Result +[RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.Result.ContextualKind.get -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +[RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.Result.Result() -> void +[RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.Result.Token.get -> Microsoft.CodeAnalysis.SyntaxToken +[RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.SkipForwardTo(int position) -> void +[RSEXPERIMENTAL003]static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.CreateTokenParser(Microsoft.CodeAnalysis.Text.SourceText! sourceText, Microsoft.CodeAnalysis.CSharp.CSharpParseOptions? options = null) -> Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser! ~Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken asyncKeyword, Microsoft.CodeAnalysis.SyntaxToken delegateKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax parameterList, Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode body) -> Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax ~Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken asyncKeyword, Microsoft.CodeAnalysis.SyntaxToken delegateKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax ~Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax.WithAsyncKeyword(Microsoft.CodeAnalysis.SyntaxToken asyncKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax @@ -14,6 +25,9 @@ abstract Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode.Accept(Microsof abstract Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.GetRoot(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode! abstract Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.Options.get -> Microsoft.CodeAnalysis.CSharp.CSharpParseOptions! abstract Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.TryGetRoot(out Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode? root) -> bool +abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.Data.get -> string! +abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.GetDisplayLocation() -> string! +abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.Version.get -> int abstract Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousFunctionExpressionSyntax.AsyncKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken abstract Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousFunctionExpressionSyntax.Block.get -> Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? abstract Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousFunctionExpressionSyntax.ExpressionBody.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? @@ -115,6 +129,7 @@ Microsoft.CodeAnalysis.CSharp.Conversion.IsNumeric.get -> bool Microsoft.CodeAnalysis.CSharp.Conversion.IsObjectCreation.get -> bool Microsoft.CodeAnalysis.CSharp.Conversion.IsPointer.get -> bool Microsoft.CodeAnalysis.CSharp.Conversion.IsReference.get -> bool +Microsoft.CodeAnalysis.CSharp.Conversion.IsSpan.get -> bool Microsoft.CodeAnalysis.CSharp.Conversion.IsStackAlloc.get -> bool Microsoft.CodeAnalysis.CSharp.Conversion.IsSwitchExpression.get -> bool Microsoft.CodeAnalysis.CSharp.Conversion.IsThrow.get -> bool @@ -259,11 +274,13 @@ Microsoft.CodeAnalysis.CSharp.ForEachStatementInfo.ForEachStatementInfo() -> voi Microsoft.CodeAnalysis.CSharp.ForEachStatementInfo.GetEnumeratorMethod.get -> Microsoft.CodeAnalysis.IMethodSymbol? Microsoft.CodeAnalysis.CSharp.ForEachStatementInfo.IsAsynchronous.get -> bool Microsoft.CodeAnalysis.CSharp.ForEachStatementInfo.MoveNextMethod.get -> Microsoft.CodeAnalysis.IMethodSymbol? +Microsoft.CodeAnalysis.CSharp.InterceptableLocation Microsoft.CodeAnalysis.CSharp.LanguageVersion Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp1 = 1 -> Microsoft.CodeAnalysis.CSharp.LanguageVersion Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp10 = 1000 -> Microsoft.CodeAnalysis.CSharp.LanguageVersion Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp11 = 1100 -> Microsoft.CodeAnalysis.CSharp.LanguageVersion Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp12 = 1200 -> Microsoft.CodeAnalysis.CSharp.LanguageVersion +Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp13 = 1300 -> Microsoft.CodeAnalysis.CSharp.LanguageVersion Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp2 = 2 -> Microsoft.CodeAnalysis.CSharp.LanguageVersion Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp3 = 3 -> Microsoft.CodeAnalysis.CSharp.LanguageVersion Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp4 = 4 -> Microsoft.CodeAnalysis.CSharp.LanguageVersion @@ -322,6 +339,14 @@ Microsoft.CodeAnalysis.CSharp.Syntax.AliasQualifiedNameSyntax.Update(Microsoft.C Microsoft.CodeAnalysis.CSharp.Syntax.AliasQualifiedNameSyntax.WithAlias(Microsoft.CodeAnalysis.CSharp.Syntax.IdentifierNameSyntax! alias) -> Microsoft.CodeAnalysis.CSharp.Syntax.AliasQualifiedNameSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.AliasQualifiedNameSyntax.WithColonColonToken(Microsoft.CodeAnalysis.SyntaxToken colonColonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.AliasQualifiedNameSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.AliasQualifiedNameSyntax.WithName(Microsoft.CodeAnalysis.CSharp.Syntax.SimpleNameSyntax! name) -> Microsoft.CodeAnalysis.CSharp.Syntax.AliasQualifiedNameSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax.AddConstraints(params Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax.AllowsKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax.Constraints.get -> Microsoft.CodeAnalysis.SeparatedSyntaxList +Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken allowsKeyword, Microsoft.CodeAnalysis.SeparatedSyntaxList constraints) -> Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax.WithAllowsKeyword(Microsoft.CodeAnalysis.SyntaxToken allowsKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax.WithConstraints(Microsoft.CodeAnalysis.SeparatedSyntaxList constraints) -> Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintSyntax Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousFunctionExpressionSyntax Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousFunctionExpressionSyntax.AddBlockAttributeLists(params Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousFunctionExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousFunctionExpressionSyntax.AddBlockStatements(params Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousFunctionExpressionSyntax! @@ -1194,6 +1219,10 @@ Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax.WithAttributeLists(M Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax.WithDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax! declaration) -> Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax.WithModifiers(Microsoft.CodeAnalysis.SyntaxTokenList modifiers) -> Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax.WithSemicolonToken(Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax.Token.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken token) -> Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax.WithToken(Microsoft.CodeAnalysis.SyntaxToken token) -> Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.AddAttributeLists(params Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.AddExterns(params Microsoft.CodeAnalysis.CSharp.Syntax.ExternAliasDirectiveSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! @@ -2208,6 +2237,12 @@ Microsoft.CodeAnalysis.CSharp.Syntax.RefExpressionSyntax.RefKeyword.get -> Micro Microsoft.CodeAnalysis.CSharp.Syntax.RefExpressionSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken refKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.RefExpressionSyntax.WithExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.RefExpressionSyntax.WithRefKeyword(Microsoft.CodeAnalysis.SyntaxToken refKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefExpressionSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax.RefKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax.StructKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken refKeyword, Microsoft.CodeAnalysis.SyntaxToken structKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax.WithRefKeyword(Microsoft.CodeAnalysis.SyntaxToken refKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax.WithStructKeyword(Microsoft.CodeAnalysis.SyntaxToken structKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeExpressionSyntax Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeExpressionSyntax.CloseParenToken.get -> Microsoft.CodeAnalysis.SyntaxToken Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeExpressionSyntax.Expression.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! @@ -2868,6 +2903,8 @@ Microsoft.CodeAnalysis.CSharp.SyntaxKind.AddKeyword = 8419 -> Microsoft.CodeAnal Microsoft.CodeAnalysis.CSharp.SyntaxKind.AddressOfExpression = 8737 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.AliasKeyword = 8407 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.AliasQualifiedName = 8620 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.SyntaxKind.AllowsConstraintClause = 8879 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.SyntaxKind.AllowsKeyword = 8450 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.AmpersandAmpersandToken = 8261 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.AmpersandEqualsToken = 8279 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.AmpersandToken = 8198 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind @@ -3043,6 +3080,7 @@ Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExternKeyword = 8359 -> Microsoft.CodeA Microsoft.CodeAnalysis.CSharp.SyntaxKind.FalseKeyword = 8324 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.FalseLiteralExpression = 8753 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.FieldDeclaration = 8873 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.SyntaxKind.FieldExpression = 8757 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.FieldKeyword = 8412 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.FileKeyword = 8449 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.FileScopedNamespaceDeclaration = 8845 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind @@ -3255,6 +3293,7 @@ Microsoft.CodeAnalysis.CSharp.SyntaxKind.QuestionQuestionEqualsToken = 8284 -> M Microsoft.CodeAnalysis.CSharp.SyntaxKind.QuestionQuestionToken = 8265 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.QuestionToken = 8219 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.RangeExpression = 8658 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.SyntaxKind.RazorContentToken = 8523 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.ReadOnlyKeyword = 8348 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.RecordDeclaration = 9063 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.RecordKeyword = 8444 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind @@ -3264,6 +3303,7 @@ Microsoft.CodeAnalysis.CSharp.SyntaxKind.ReferenceDirectiveTrivia = 8561 -> Micr Microsoft.CodeAnalysis.CSharp.SyntaxKind.ReferenceKeyword = 8481 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.RefExpression = 9050 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.RefKeyword = 8360 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.SyntaxKind.RefStructConstraint = 8880 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.RefType = 9051 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.RefTypeExpression = 8767 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.RefTypeKeyword = 8368 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind @@ -3422,6 +3462,8 @@ Microsoft.CodeAnalysis.CSharp.SyntaxKind.YieldKeyword = 8405 -> Microsoft.CodeAn Microsoft.CodeAnalysis.CSharp.SyntaxKind.YieldReturnStatement = 8806 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.TypedConstantExtensions Microsoft.CodeAnalysis.CSharpExtensions +override abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.Equals(object? obj) -> bool +override abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.GetHashCode() -> int override abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseFieldDeclarationSyntax.AttributeLists.get -> Microsoft.CodeAnalysis.SyntaxList override abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseFieldDeclarationSyntax.Modifiers.get -> Microsoft.CodeAnalysis.SyntaxTokenList override abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseMethodDeclarationSyntax.AttributeLists.get -> Microsoft.CodeAnalysis.SyntaxList @@ -3462,6 +3504,7 @@ override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.Visit(Microsoft.Code override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitAccessorDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.AccessorDeclarationSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitAccessorList(Microsoft.CodeAnalysis.CSharp.Syntax.AccessorListSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitAliasQualifiedName(Microsoft.CodeAnalysis.CSharp.Syntax.AliasQualifiedNameSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? +override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitAllowsConstraintClause(Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitAnonymousMethodExpression(Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitAnonymousObjectCreationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousObjectCreationExpressionSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitAnonymousObjectMemberDeclarator(Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousObjectMemberDeclaratorSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? @@ -3543,6 +3586,7 @@ override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitExpressionEleme override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitExpressionStatement(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionStatementSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitExternAliasDirective(Microsoft.CodeAnalysis.CSharp.Syntax.ExternAliasDirectiveSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitFieldDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? +override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitFieldExpression(Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitFileScopedNamespaceDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitFinallyClause(Microsoft.CodeAnalysis.CSharp.Syntax.FinallyClauseSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitFixedStatement(Microsoft.CodeAnalysis.CSharp.Syntax.FixedStatementSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? @@ -3635,6 +3679,7 @@ override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitRecordDeclarati override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitRecursivePattern(Microsoft.CodeAnalysis.CSharp.Syntax.RecursivePatternSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitReferenceDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.ReferenceDirectiveTriviaSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitRefExpression(Microsoft.CodeAnalysis.CSharp.Syntax.RefExpressionSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? +override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitRefStructConstraint(Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitRefType(Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitRefTypeExpression(Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeExpressionSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitRefValueExpression(Microsoft.CodeAnalysis.CSharp.Syntax.RefValueExpressionSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? @@ -3731,6 +3776,8 @@ override Microsoft.CodeAnalysis.CSharp.Syntax.AccessorListSyntax.Accept(Microsof override Microsoft.CodeAnalysis.CSharp.Syntax.AccessorListSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? override Microsoft.CodeAnalysis.CSharp.Syntax.AliasQualifiedNameSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void override Microsoft.CodeAnalysis.CSharp.Syntax.AliasQualifiedNameSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? +override Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void +override Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? override Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void override Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? override Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax.AsyncKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken @@ -3996,6 +4043,8 @@ override Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax.AttributeLi override Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax.Declaration.get -> Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax! override Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax.Modifiers.get -> Microsoft.CodeAnalysis.SyntaxTokenList override Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax.SemicolonToken.get -> Microsoft.CodeAnalysis.SyntaxToken +override Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void +override Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? override Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void override Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? override Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.AttributeLists.get -> Microsoft.CodeAnalysis.SyntaxList @@ -4323,6 +4372,8 @@ override Microsoft.CodeAnalysis.CSharp.Syntax.ReferenceDirectiveTriviaSyntax.Has override Microsoft.CodeAnalysis.CSharp.Syntax.ReferenceDirectiveTriviaSyntax.IsActive.get -> bool override Microsoft.CodeAnalysis.CSharp.Syntax.RefExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void override Microsoft.CodeAnalysis.CSharp.Syntax.RefExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? +override Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void +override Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? override Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void override Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? override Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void @@ -4570,6 +4621,9 @@ static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetForEachStatementInfo(th static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetForEachStatementInfo(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.ForEachStatementSyntax! forEachStatement) -> Microsoft.CodeAnalysis.CSharp.ForEachStatementInfo static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetInConversion(this Microsoft.CodeAnalysis.Operations.ICompoundAssignmentOperation! compoundAssignment) -> Microsoft.CodeAnalysis.CSharp.Conversion static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetIndexerGroup(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! expression, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Collections.Immutable.ImmutableArray +static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetInterceptableLocation(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.InvocationExpressionSyntax! node, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.CSharp.InterceptableLocation? +static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetInterceptorMethod(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.InvocationExpressionSyntax! node, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.IMethodSymbol? +static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetInterceptsLocationAttributeSyntax(this Microsoft.CodeAnalysis.CSharp.InterceptableLocation! location) -> string! static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetLastDirective(this Microsoft.CodeAnalysis.SyntaxNode! node, System.Func? predicate = null) -> Microsoft.CodeAnalysis.CSharp.Syntax.DirectiveTriviaSyntax? static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetMemberGroup(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.AttributeSyntax! attribute, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Collections.Immutable.ImmutableArray static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetMemberGroup(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.ConstructorInitializerSyntax! initializer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Collections.Immutable.ImmutableArray @@ -4674,6 +4728,8 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.AccessorList(Microsoft.CodeAn static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.AliasQualifiedName(Microsoft.CodeAnalysis.CSharp.Syntax.IdentifierNameSyntax! alias, Microsoft.CodeAnalysis.CSharp.Syntax.SimpleNameSyntax! name) -> Microsoft.CodeAnalysis.CSharp.Syntax.AliasQualifiedNameSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.AliasQualifiedName(Microsoft.CodeAnalysis.CSharp.Syntax.IdentifierNameSyntax! alias, Microsoft.CodeAnalysis.SyntaxToken colonColonToken, Microsoft.CodeAnalysis.CSharp.Syntax.SimpleNameSyntax! name) -> Microsoft.CodeAnalysis.CSharp.Syntax.AliasQualifiedNameSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.AliasQualifiedName(string! alias, Microsoft.CodeAnalysis.CSharp.Syntax.SimpleNameSyntax! name) -> Microsoft.CodeAnalysis.CSharp.Syntax.AliasQualifiedNameSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.AllowsConstraintClause(Microsoft.CodeAnalysis.SeparatedSyntaxList constraints = default(Microsoft.CodeAnalysis.SeparatedSyntaxList)) -> Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.AllowsConstraintClause(Microsoft.CodeAnalysis.SyntaxToken allowsKeyword, Microsoft.CodeAnalysis.SeparatedSyntaxList constraints) -> Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.AnonymousMethodExpression(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode! body) -> Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.AnonymousMethodExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax? parameterList, Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode! body) -> Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.AnonymousMethodExpression(Microsoft.CodeAnalysis.SyntaxToken asyncKeyword, Microsoft.CodeAnalysis.SyntaxToken delegateKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode! body) -> Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax! @@ -4922,6 +4978,8 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExternAliasDirective(string! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FieldDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax! declaration) -> Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FieldDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax! declaration) -> Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FieldDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax! declaration, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FieldExpression() -> Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FieldExpression(Microsoft.CodeAnalysis.SyntaxToken token) -> Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FileScopedNamespaceDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FileScopedNamespaceDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name, Microsoft.CodeAnalysis.SyntaxList externs, Microsoft.CodeAnalysis.SyntaxList usings, Microsoft.CodeAnalysis.SyntaxList members) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FileScopedNamespaceDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken namespaceKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name, Microsoft.CodeAnalysis.SyntaxToken semicolonToken, Microsoft.CodeAnalysis.SyntaxList externs, Microsoft.CodeAnalysis.SyntaxList usings, Microsoft.CodeAnalysis.SyntaxList members) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! @@ -5257,6 +5315,8 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ReferenceDirectiveTrivia(Micr static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ReferenceDirectiveTrivia(Microsoft.CodeAnalysis.SyntaxToken hashToken, Microsoft.CodeAnalysis.SyntaxToken referenceKeyword, Microsoft.CodeAnalysis.SyntaxToken file, Microsoft.CodeAnalysis.SyntaxToken endOfDirectiveToken, bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.ReferenceDirectiveTriviaSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RefExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefExpressionSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RefExpression(Microsoft.CodeAnalysis.SyntaxToken refKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefExpressionSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RefStructConstraint() -> Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RefStructConstraint(Microsoft.CodeAnalysis.SyntaxToken refKeyword, Microsoft.CodeAnalysis.SyntaxToken structKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RefType(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! type) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RefType(Microsoft.CodeAnalysis.SyntaxToken refKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! type) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RefType(Microsoft.CodeAnalysis.SyntaxToken refKeyword, Microsoft.CodeAnalysis.SyntaxToken readOnlyKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! type) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax! @@ -5626,6 +5686,7 @@ virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.Visit(Microsoft.CodeAn virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitAccessorDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.AccessorDeclarationSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitAccessorList(Microsoft.CodeAnalysis.CSharp.Syntax.AccessorListSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitAliasQualifiedName(Microsoft.CodeAnalysis.CSharp.Syntax.AliasQualifiedNameSyntax! node) -> void +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitAllowsConstraintClause(Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitAnonymousMethodExpression(Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitAnonymousObjectCreationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousObjectCreationExpressionSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitAnonymousObjectMemberDeclarator(Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousObjectMemberDeclaratorSyntax! node) -> void @@ -5707,6 +5768,7 @@ virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExpressionElement virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExpressionStatement(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionStatementSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExternAliasDirective(Microsoft.CodeAnalysis.CSharp.Syntax.ExternAliasDirectiveSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFieldDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax! node) -> void +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFieldExpression(Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFileScopedNamespaceDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFinallyClause(Microsoft.CodeAnalysis.CSharp.Syntax.FinallyClauseSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFixedStatement(Microsoft.CodeAnalysis.CSharp.Syntax.FixedStatementSyntax! node) -> void @@ -5799,6 +5861,7 @@ virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitRecordDeclaration virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitRecursivePattern(Microsoft.CodeAnalysis.CSharp.Syntax.RecursivePatternSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitReferenceDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.ReferenceDirectiveTriviaSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitRefExpression(Microsoft.CodeAnalysis.CSharp.Syntax.RefExpressionSyntax! node) -> void +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitRefStructConstraint(Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitRefType(Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitRefTypeExpression(Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeExpressionSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitRefValueExpression(Microsoft.CodeAnalysis.CSharp.Syntax.RefValueExpressionSyntax! node) -> void @@ -5869,6 +5932,7 @@ virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.Visit(Microso virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitAccessorDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.AccessorDeclarationSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitAccessorList(Microsoft.CodeAnalysis.CSharp.Syntax.AccessorListSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitAliasQualifiedName(Microsoft.CodeAnalysis.CSharp.Syntax.AliasQualifiedNameSyntax! node) -> TResult? +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitAllowsConstraintClause(Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitAnonymousMethodExpression(Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitAnonymousObjectCreationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousObjectCreationExpressionSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitAnonymousObjectMemberDeclarator(Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousObjectMemberDeclaratorSyntax! node) -> TResult? @@ -5950,6 +6014,7 @@ virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExpressi virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExpressionStatement(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionStatementSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExternAliasDirective(Microsoft.CodeAnalysis.CSharp.Syntax.ExternAliasDirectiveSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFieldDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax! node) -> TResult? +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFieldExpression(Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFileScopedNamespaceDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFinallyClause(Microsoft.CodeAnalysis.CSharp.Syntax.FinallyClauseSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFixedStatement(Microsoft.CodeAnalysis.CSharp.Syntax.FixedStatementSyntax! node) -> TResult? @@ -6042,6 +6107,7 @@ virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitRecordDe virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitRecursivePattern(Microsoft.CodeAnalysis.CSharp.Syntax.RecursivePatternSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitReferenceDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.ReferenceDirectiveTriviaSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitRefExpression(Microsoft.CodeAnalysis.CSharp.Syntax.RefExpressionSyntax! node) -> TResult? +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitRefStructConstraint(Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitRefType(Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitRefTypeExpression(Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeExpressionSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitRefValueExpression(Microsoft.CodeAnalysis.CSharp.Syntax.RefValueExpressionSyntax! node) -> TResult? diff --git a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt index 0ebff1a371642..57a3f640e82e5 100644 --- a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt @@ -1,66 +1,43 @@ -Microsoft.CodeAnalysis.CSharp.Conversion.IsSpan.get -> bool -Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp13 = 1300 -> Microsoft.CodeAnalysis.CSharp.LanguageVersion -Microsoft.CodeAnalysis.CSharp.InterceptableLocation -abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.Data.get -> string! -abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.GetDisplayLocation() -> string! -abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.Version.get -> int -Microsoft.CodeAnalysis.CSharp.SyntaxKind.RazorContentToken = 8523 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind -override abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.Equals(object? obj) -> bool -override abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.GetHashCode() -> int -static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetInterceptableLocation(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.InvocationExpressionSyntax! node, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.CSharp.InterceptableLocation? -static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetInterceptsLocationAttributeSyntax(this Microsoft.CodeAnalysis.CSharp.InterceptableLocation! location) -> string! -[RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser -[RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.Dispose() -> void -[RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.ParseLeadingTrivia() -> Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.Result -[RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.ParseNextToken() -> Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.Result -[RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.ParseTrailingTrivia() -> Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.Result -[RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.ResetTo(Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.Result result) -> void -[RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.Result -[RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.Result.ContextualKind.get -> Microsoft.CodeAnalysis.CSharp.SyntaxKind -[RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.Result.Result() -> void -[RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.Result.Token.get -> Microsoft.CodeAnalysis.SyntaxToken -[RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.SkipForwardTo(int position) -> void -[RSEXPERIMENTAL003]static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.CreateTokenParser(Microsoft.CodeAnalysis.Text.SourceText! sourceText, Microsoft.CodeAnalysis.CSharp.CSharpParseOptions? options = null) -> Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser! -Microsoft.CodeAnalysis.CSharp.SyntaxKind.AllowsConstraintClause = 8879 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind -Microsoft.CodeAnalysis.CSharp.SyntaxKind.AllowsKeyword = 8450 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind -Microsoft.CodeAnalysis.CSharp.SyntaxKind.RefStructConstraint = 8880 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind -override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitAllowsConstraintClause(Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? -override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitRefStructConstraint(Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? -Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax -Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax.AddConstraints(params Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax.AllowsKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken -Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax.Constraints.get -> Microsoft.CodeAnalysis.SeparatedSyntaxList -Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken allowsKeyword, Microsoft.CodeAnalysis.SeparatedSyntaxList constraints) -> Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax.WithAllowsKeyword(Microsoft.CodeAnalysis.SyntaxToken allowsKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax.WithConstraints(Microsoft.CodeAnalysis.SeparatedSyntaxList constraints) -> Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax! -override Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void -override Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? -Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintSyntax -Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax -Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax.RefKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken -Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax.StructKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken -Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken refKeyword, Microsoft.CodeAnalysis.SyntaxToken structKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax.WithRefKeyword(Microsoft.CodeAnalysis.SyntaxToken refKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax.WithStructKeyword(Microsoft.CodeAnalysis.SyntaxToken structKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax! -override Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void -override Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.AllowsConstraintClause(Microsoft.CodeAnalysis.SeparatedSyntaxList constraints = default(Microsoft.CodeAnalysis.SeparatedSyntaxList)) -> Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.AllowsConstraintClause(Microsoft.CodeAnalysis.SyntaxToken allowsKeyword, Microsoft.CodeAnalysis.SeparatedSyntaxList constraints) -> Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RefStructConstraint() -> Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RefStructConstraint(Microsoft.CodeAnalysis.SyntaxToken refKeyword, Microsoft.CodeAnalysis.SyntaxToken structKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax! -virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitAllowsConstraintClause(Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax! node) -> void -virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitRefStructConstraint(Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax! node) -> void -virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitAllowsConstraintClause(Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax! node) -> TResult? -virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitRefStructConstraint(Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax! node) -> TResult? -Microsoft.CodeAnalysis.CSharp.SyntaxKind.FieldExpression = 8757 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind -Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax -virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFieldExpression(Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax! node) -> TResult? -override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitFieldExpression(Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? -virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFieldExpression(Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax! node) -> void -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FieldExpression() -> Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FieldExpression(Microsoft.CodeAnalysis.SyntaxToken token) -> Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax.Token.get -> Microsoft.CodeAnalysis.SyntaxToken -override Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void -override Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? -Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken token) -> Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax.WithToken(Microsoft.CodeAnalysis.SyntaxToken token) -> Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax! +abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.Equals(Microsoft.CodeAnalysis.CSharp.InterceptableLocation? other) -> bool + +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AddAttributeLists(params Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AddConstraintClauses(params Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterConstraintClauseSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AddMembers(params Microsoft.CodeAnalysis.CSharp.Syntax.MemberDeclarationSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AddModifiers(params Microsoft.CodeAnalysis.SyntaxToken[]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AddParameterListParameters(params Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AddTypeParameterListParameters(params Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.Update(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken keyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax? typeParameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax? parameterList, Microsoft.CodeAnalysis.SyntaxList constraintClauses, Microsoft.CodeAnalysis.SyntaxToken openBraceToken, Microsoft.CodeAnalysis.SyntaxList members, Microsoft.CodeAnalysis.SyntaxToken closeBraceToken, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithAttributeLists(Microsoft.CodeAnalysis.SyntaxList attributeLists) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithCloseBraceToken(Microsoft.CodeAnalysis.SyntaxToken closeBraceToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithConstraintClauses(Microsoft.CodeAnalysis.SyntaxList constraintClauses) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithKeyword(Microsoft.CodeAnalysis.SyntaxToken keyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithMembers(Microsoft.CodeAnalysis.SyntaxList members) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithModifiers(Microsoft.CodeAnalysis.SyntaxTokenList modifiers) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithOpenBraceToken(Microsoft.CodeAnalysis.SyntaxToken openBraceToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithParameterList(Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax? parameterList) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithSemicolonToken(Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithTypeParameterList(Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax? typeParameterList) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExtensionDeclaration = 9079 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExtensionKeyword = 8451 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitExtensionDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? +override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void +override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? +override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AttributeLists.get -> Microsoft.CodeAnalysis.SyntaxList +override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.BaseList.get -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseListSyntax? +override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.CloseBraceToken.get -> Microsoft.CodeAnalysis.SyntaxToken +override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.ConstraintClauses.get -> Microsoft.CodeAnalysis.SyntaxList +override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.Identifier.get -> Microsoft.CodeAnalysis.SyntaxToken +override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.Keyword.get -> Microsoft.CodeAnalysis.SyntaxToken +override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.Members.get -> Microsoft.CodeAnalysis.SyntaxList +override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.Modifiers.get -> Microsoft.CodeAnalysis.SyntaxTokenList +override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.OpenBraceToken.get -> Microsoft.CodeAnalysis.SyntaxToken +override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.ParameterList.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax? +override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.SemicolonToken.get -> Microsoft.CodeAnalysis.SyntaxToken +override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.TypeParameterList.get -> Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax? +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExtensionDeclaration() -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExtensionDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax? typeParameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax? parameterList, Microsoft.CodeAnalysis.SyntaxList constraintClauses, Microsoft.CodeAnalysis.SyntaxList members) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExtensionDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken keyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax? typeParameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax? parameterList, Microsoft.CodeAnalysis.SyntaxList constraintClauses, Microsoft.CodeAnalysis.SyntaxToken openBraceToken, Microsoft.CodeAnalysis.SyntaxList members, Microsoft.CodeAnalysis.SyntaxToken closeBraceToken, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExtensionDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! node) -> void +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExtensionDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! node) -> TResult? + diff --git a/src/Compilers/CSharp/Portable/SymbolDisplay/ObjectDisplay.cs b/src/Compilers/CSharp/Portable/SymbolDisplay/ObjectDisplay.cs index 68aae1cb8193a..760ef38769c3f 100644 --- a/src/Compilers/CSharp/Portable/SymbolDisplay/ObjectDisplay.cs +++ b/src/Compilers/CSharp/Portable/SymbolDisplay/ObjectDisplay.cs @@ -5,12 +5,9 @@ #nullable disable using System; -using System.Diagnostics; using System.Globalization; using System.Reflection; -using System.Text; using Microsoft.CodeAnalysis.PooledObjects; -using ExceptionUtilities = Roslyn.Utilities.ExceptionUtilities; namespace Microsoft.CodeAnalysis.CSharp { diff --git a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Members.cs b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Members.cs index 0fa99aec99b2f..60211bf6c0b21 100644 --- a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Members.cs +++ b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Members.cs @@ -470,9 +470,10 @@ public override void VisitMethod(IMethodSymbol symbol) // Note: we are using the metadata name also in the case that // symbol.containingType is null (which should never be the case here) or is an // anonymous type (which 'does not have a name'). - var name = Format.CompilerInternalOptions.IncludesOption(SymbolDisplayCompilerInternalOptions.UseMetadataMemberNames) || symbol.ContainingType == null || symbol.ContainingType.IsAnonymousType - ? symbol.Name - : symbol.ContainingType.Name; + bool useConstructorName = Format.CompilerInternalOptions.IncludesOption(SymbolDisplayCompilerInternalOptions.UseMetadataMemberNames) + || symbol.ContainingType == null || symbol.ContainingType.IsAnonymousType || symbol.ContainingType.IsExtension; + + var name = useConstructorName ? symbol.Name : symbol.ContainingType!.Name; var partKind = GetPartKindForConstructorOrDestructor(symbol); @@ -752,7 +753,7 @@ void addUserDefinedConversionName(IMethodSymbol symbol, SyntaxKind conversionKin private static SymbolDisplayPartKind GetPartKindForConstructorOrDestructor(IMethodSymbol symbol) { // In the case that symbol.containingType is null (which should never be the case here) we will fallback to the MethodName symbol part - if (symbol.ContainingType is null) + if (symbol.ContainingType is null || symbol.ContainingType.IsExtension) { return SymbolDisplayPartKind.MethodName; } @@ -810,42 +811,7 @@ public override void VisitParameter(IParameterSymbol symbol) if (includeType) { - if (Format.ParameterOptions.IncludesOption(SymbolDisplayParameterOptions.IncludeModifiers)) - { - // Add 'scoped' unless the parameter is an out parameter or - // 'this' since those cases are implicitly scoped. - if (symbol.ScopedKind == ScopedKind.ScopedRef && - symbol.RefKind != RefKind.Out && - !symbol.IsThis) - { - AddKeyword(SyntaxKind.ScopedKeyword); - AddSpace(); - } - - AddParameterRefKind(symbol.RefKind); - } - - AddCustomModifiersIfNeeded(symbol.RefCustomModifiers, leadingSpace: false, trailingSpace: true); - - if (Format.ParameterOptions.IncludesOption(SymbolDisplayParameterOptions.IncludeModifiers)) - { - if (symbol.IsParams) - { - AddKeyword(SyntaxKind.ParamsKeyword); - AddSpace(); - } - - if (symbol.ScopedKind == ScopedKind.ScopedValue && - symbol.RefKind == RefKind.None && - !(symbol.IsParams && symbol.Type is { IsRefLikeType: true } or ITypeParameterSymbol { AllowsRefLikeType: true })) - { - AddKeyword(SyntaxKind.ScopedKeyword); - AddSpace(); - } - } - - symbol.Type.Accept(this.NotFirstVisitor); - AddCustomModifiersIfNeeded(symbol.CustomModifiers, leadingSpace: true, trailingSpace: false); + AddParameterModifiersAndType(symbol); } if (includeName) @@ -876,6 +842,46 @@ public override void VisitParameter(IParameterSymbol symbol) } } + private void AddParameterModifiersAndType(IParameterSymbol symbol) + { + if (Format.ParameterOptions.IncludesOption(SymbolDisplayParameterOptions.IncludeModifiers)) + { + // Add 'scoped' unless the parameter is an out parameter or + // 'this' since those cases are implicitly scoped. + if (symbol.ScopedKind == ScopedKind.ScopedRef && + symbol.RefKind != RefKind.Out && + !symbol.IsThis) + { + AddKeyword(SyntaxKind.ScopedKeyword); + AddSpace(); + } + + AddParameterRefKind(symbol.RefKind); + } + + AddCustomModifiersIfNeeded(symbol.RefCustomModifiers, leadingSpace: false, trailingSpace: true); + + if (Format.ParameterOptions.IncludesOption(SymbolDisplayParameterOptions.IncludeModifiers)) + { + if (symbol.IsParams) + { + AddKeyword(SyntaxKind.ParamsKeyword); + AddSpace(); + } + + if (symbol.ScopedKind == ScopedKind.ScopedValue && + symbol.RefKind == RefKind.None && + !(symbol.IsParams && symbol.Type is { IsRefLikeType: true } or ITypeParameterSymbol { AllowsRefLikeType: true })) + { + AddKeyword(SyntaxKind.ScopedKeyword); + AddSpace(); + } + } + + symbol.Type.Accept(this.NotFirstVisitor); + AddCustomModifiersIfNeeded(symbol.CustomModifiers, leadingSpace: true, trailingSpace: false); + } + private static bool CanAddConstant(ITypeSymbol type, object? value) { if (type.TypeKind == TypeKind.Enum) diff --git a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs index 71fac01c8ba6c..02a0b61258d34 100644 --- a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs +++ b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs @@ -332,54 +332,69 @@ private void AddNameAndTypeArgumentsOrParameters(INamedTypeSymbol symbol) return; } - string? symbolName = null; - - // It would be nice to handle VB NoPia symbols too, but it's not worth the effort. - NamedTypeSymbol? underlyingTypeSymbol = (symbol as Symbols.PublicModel.NamedTypeSymbol)?.UnderlyingNamedTypeSymbol; - var illegalGenericInstantiationSymbol = underlyingTypeSymbol as NoPiaIllegalGenericInstantiationSymbol; - - if (illegalGenericInstantiationSymbol is not null) + if (symbol.IsExtension) { - symbol = illegalGenericInstantiationSymbol.UnderlyingSymbol.GetPublicSymbol(); + if (Format.CompilerInternalOptions.HasFlag(SymbolDisplayCompilerInternalOptions.UseMetadataMemberNames)) + { + var extensionIdentifier = underlyingTypeSymbol!.ExtensionName; // Tracked by https://github.com/dotnet/roslyn/issues/76130 : use public API once it's available + Builder.Add(CreatePart(SymbolDisplayPartKind.ClassName, symbol, extensionIdentifier)); + } + else + { + AddKeyword(SyntaxKind.ExtensionKeyword); + } } else { - var ambiguousCanonicalTypeSymbol = underlyingTypeSymbol as NoPiaAmbiguousCanonicalTypeSymbol; - if (ambiguousCanonicalTypeSymbol is not null) + string? symbolName = null; + + // It would be nice to handle VB NoPia symbols too, but it's not worth the effort. + + var illegalGenericInstantiationSymbol = underlyingTypeSymbol as NoPiaIllegalGenericInstantiationSymbol; + + if (illegalGenericInstantiationSymbol is not null) { - symbol = ambiguousCanonicalTypeSymbol.FirstCandidate.GetPublicSymbol(); + symbol = illegalGenericInstantiationSymbol.UnderlyingSymbol.GetPublicSymbol(); } else { - var missingCanonicalTypeSymbol = underlyingTypeSymbol as NoPiaMissingCanonicalTypeSymbol; - - if (missingCanonicalTypeSymbol is not null) + var ambiguousCanonicalTypeSymbol = underlyingTypeSymbol as NoPiaAmbiguousCanonicalTypeSymbol; + if (ambiguousCanonicalTypeSymbol is not null) { - symbolName = missingCanonicalTypeSymbol.FullTypeName; + symbol = ambiguousCanonicalTypeSymbol.FirstCandidate.GetPublicSymbol(); + } + else + { + var missingCanonicalTypeSymbol = underlyingTypeSymbol as NoPiaMissingCanonicalTypeSymbol; + + if (missingCanonicalTypeSymbol is not null) + { + symbolName = missingCanonicalTypeSymbol.FullTypeName; + } } } - } - if (symbolName is null && symbol.IsAnonymousType && symbol.TypeKind == TypeKind.Delegate) - { - symbolName = ""; - } + if (symbolName is null && symbol.IsAnonymousType && symbol.TypeKind == TypeKind.Delegate) + { + symbolName = ""; + } - var partKind = GetPartKind(symbol); + var partKind = GetPartKind(symbol); - symbolName ??= symbol.Name; + symbolName ??= symbol.Name; - if (Format.MiscellaneousOptions.IncludesOption(SymbolDisplayMiscellaneousOptions.UseErrorTypeSymbolName) && - partKind == SymbolDisplayPartKind.ErrorTypeName && - string.IsNullOrEmpty(symbolName)) - { - Builder.Add(CreatePart(partKind, symbol, "?")); - } - else - { - symbolName = RemoveAttributeSuffixIfNecessary(symbol, symbolName); - Builder.Add(CreatePart(partKind, symbol, symbolName)); + if (Format.MiscellaneousOptions.IncludesOption(SymbolDisplayMiscellaneousOptions.UseErrorTypeSymbolName) && + partKind == SymbolDisplayPartKind.ErrorTypeName && + string.IsNullOrEmpty(symbolName)) + { + Builder.Add(CreatePart(partKind, symbol, "?")); + } + else + { + symbolName = RemoveAttributeSuffixIfNecessary(symbol, symbolName); + Builder.Add(CreatePart(partKind, symbol, symbolName)); + } } if (Format.CompilerInternalOptions.IncludesOption(SymbolDisplayCompilerInternalOptions.UseArityForGenericTypes)) @@ -410,10 +425,19 @@ private void AddNameAndTypeArgumentsOrParameters(INamedTypeSymbol symbol) AddTypeArguments(symbol, GetTypeArgumentsModifiers(underlyingTypeSymbol)); AddDelegateParameters(symbol); + if (symbol.IsExtension) + { + addExtensionParameter(symbol); + } + // TODO: do we want to skip these if we're being visited as a containing type? AddTypeParameterConstraints(symbol.TypeArguments); } } + else if (symbol.IsExtension) + { + addExtensionParameter(symbol); + } else { AddDelegateParameters(symbol); @@ -428,6 +452,19 @@ private void AddNameAndTypeArgumentsOrParameters(INamedTypeSymbol symbol) Builder.Add(CreatePart(InternalSymbolDisplayPartKind.Other, symbol, "missing")); AddPunctuation(SyntaxKind.CloseBracketToken); } + + return; + + void addExtensionParameter(INamedTypeSymbol symbol) + { + if (!Format.CompilerInternalOptions.HasFlag(SymbolDisplayCompilerInternalOptions.UseMetadataMemberNames) + && symbol.ExtensionParameter is { } extensionParameter) + { + AddPunctuation(SyntaxKind.OpenParenToken); + AddParameterModifiersAndType(extensionParameter); + AddPunctuation(SyntaxKind.CloseParenToken); + } + } } private ImmutableArray> GetTypeArgumentsModifiers(NamedTypeSymbol? underlyingTypeSymbol) diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/PublicSymbols/AnonymousManager.TypeOrDelegatePublicSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/PublicSymbols/AnonymousManager.TypeOrDelegatePublicSymbol.cs index e2ed766e3be0e..7a7f6e03314f4 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/PublicSymbols/AnonymousManager.TypeOrDelegatePublicSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/PublicSymbols/AnonymousManager.TypeOrDelegatePublicSymbol.cs @@ -46,6 +46,8 @@ internal sealed override IEnumerable GetFieldsToEmit() internal sealed override bool IsInterpolatedStringHandlerType => false; + internal sealed override ParameterSymbol? ExtensionParameter => null; + internal sealed override ImmutableArray GetEarlyAttributeDecodingMembers() { return this.GetMembersUnordered(); @@ -79,6 +81,9 @@ internal sealed override bool MangleName internal sealed override bool IsFileLocal => false; internal sealed override FileIdentifier? AssociatedFileIdentifier => null; + internal override string ExtensionName + => throw ExceptionUtilities.Unreachable(); + public sealed override int Arity { get { return 0; } diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.SynthesizedMethodBase.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.SynthesizedMethodBase.cs index 425d6a2a363cd..24eb91b6f5f64 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.SynthesizedMethodBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.SynthesizedMethodBase.cs @@ -17,7 +17,7 @@ internal sealed partial class AnonymousTypeManager /// /// Represents a base implementation for anonymous type synthesized methods. /// - private abstract class SynthesizedMethodBase : SynthesizedInstanceMethodSymbol + private abstract class SynthesizedMethodBase : SynthesizedMethodSymbol { private readonly NamedTypeSymbol _containingType; private readonly string _name; diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TypeOrDelegateTemplateSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TypeOrDelegateTemplateSymbol.cs index 9d601bda14ded..2d5944bc713b5 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TypeOrDelegateTemplateSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TypeOrDelegateTemplateSymbol.cs @@ -124,6 +124,8 @@ internal override bool GetGuidString(out string? guidString) internal sealed override bool IsInterpolatedStringHandlerType => false; + internal sealed override ParameterSymbol? ExtensionParameter => null; + internal sealed override ImmutableArray GetEarlyAttributeDecodingMembers() { return this.GetMembersUnordered(); @@ -164,6 +166,9 @@ public sealed override bool IsRefLikeType get { return false; } } + internal override string ExtensionName + => throw ExceptionUtilities.Unreachable(); + public sealed override bool IsReadOnly { get { return false; } diff --git a/src/Compilers/CSharp/Portable/Symbols/ArrayTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ArrayTypeSymbol.cs index 3d4e09efc7be3..572ee0cc3442d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ArrayTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ArrayTypeSymbol.cs @@ -235,6 +235,8 @@ public override bool IsValueType } } + internal sealed override ParameterSymbol? ExtensionParameter => null; + internal sealed override ManagedKind GetManagedKind(ref CompoundUseSiteInfo useSiteInfo) => ManagedKind.Managed; public sealed override bool IsRefLikeType diff --git a/src/Compilers/CSharp/Portable/Symbols/ConversionSignatureComparer.cs b/src/Compilers/CSharp/Portable/Symbols/ConversionSignatureComparer.cs index 3281ec8457561..c3d66606f60d5 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ConversionSignatureComparer.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ConversionSignatureComparer.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols { - internal sealed class ConversionSignatureComparer : IEqualityComparer + internal sealed class ConversionSignatureComparer : IEqualityComparer { private static readonly ConversionSignatureComparer s_comparer = new ConversionSignatureComparer(); public static ConversionSignatureComparer Comparer @@ -24,7 +24,7 @@ private ConversionSignatureComparer() { } - public bool Equals(SourceUserDefinedConversionSymbol member1, SourceUserDefinedConversionSymbol member2) + public bool Equals(MethodSymbol member1, MethodSymbol member2) { if (ReferenceEquals(member1, member2)) { @@ -53,7 +53,7 @@ public bool Equals(SourceUserDefinedConversionSymbol member1, SourceUserDefinedC && (member1.Name == WellKnownMemberNames.ImplicitConversionName || member2.Name == WellKnownMemberNames.ImplicitConversionName || member1.Name == member2.Name); } - public int GetHashCode(SourceUserDefinedConversionSymbol member) + public int GetHashCode(MethodSymbol member) { if ((object)member == null) { diff --git a/src/Compilers/CSharp/Portable/Symbols/DynamicTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/DynamicTypeSymbol.cs index 627e2a4ef0069..305545280cf9e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/DynamicTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/DynamicTypeSymbol.cs @@ -106,6 +106,8 @@ public override bool IsValueType } } + internal sealed override ParameterSymbol? ExtensionParameter => null; + internal sealed override ManagedKind GetManagedKind(ref CompoundUseSiteInfo useSiteInfo) => ManagedKind.Managed; public sealed override bool IsRefLikeType diff --git a/src/Compilers/CSharp/Portable/Symbols/EnumConversions.cs b/src/Compilers/CSharp/Portable/Symbols/EnumConversions.cs index 4b439ae7fe27b..0d40d07e8360a 100644 --- a/src/Compilers/CSharp/Portable/Symbols/EnumConversions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/EnumConversions.cs @@ -36,6 +36,8 @@ internal static TypeKind ToTypeKind(this DeclarationKind kind) case DeclarationKind.RecordStruct: return TypeKind.Struct; + case DeclarationKind.Extension: + return TypeKind.Extension; default: throw ExceptionUtilities.UnexpectedValue(kind); } diff --git a/src/Compilers/CSharp/Portable/Symbols/ErrorTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ErrorTypeSymbol.cs index c6abc0310eddc..e1ce775921fb1 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ErrorTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ErrorTypeSymbol.cs @@ -105,6 +105,8 @@ public sealed override bool IsValueType get { return false; } } + internal sealed override ParameterSymbol? ExtensionParameter => null; + public sealed override bool IsRefLikeType { get @@ -113,6 +115,9 @@ public sealed override bool IsRefLikeType } } + internal override string ExtensionName + => throw ExceptionUtilities.Unreachable(); + public sealed override bool IsReadOnly { get diff --git a/src/Compilers/CSharp/Portable/Symbols/EventSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/EventSymbol.cs index 42664a4724719..9d20059ffcd53 100644 --- a/src/Compilers/CSharp/Portable/Symbols/EventSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/EventSymbol.cs @@ -228,6 +228,10 @@ internal virtual bool IsExplicitInterfaceImplementation /// public abstract ImmutableArray ExplicitInterfaceImplementations { get; } + internal virtual EventSymbol? PartialImplementationPart => null; + internal virtual EventSymbol? PartialDefinitionPart => null; + internal virtual bool IsPartialDefinition => false; + /// /// Gets the kind of this symbol. /// diff --git a/src/Compilers/CSharp/Portable/Symbols/Extensions/ReceiverParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Extensions/ReceiverParameterSymbol.cs new file mode 100644 index 0000000000000..ced078cec4bdc --- /dev/null +++ b/src/Compilers/CSharp/Portable/Symbols/Extensions/ReceiverParameterSymbol.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 Microsoft.CodeAnalysis.CSharp.Symbols +{ + internal sealed class ReceiverParameterSymbol : RewrittenParameterSymbol + { + private readonly NamedTypeSymbol _containingType; + + public ReceiverParameterSymbol(NamedTypeSymbol containingType, ParameterSymbol originalParameter) : + base(originalParameter) + { + _containingType = containingType; + } + + public override Symbol ContainingSymbol + { + get { return _containingType; } + } + } +} diff --git a/src/Compilers/CSharp/Portable/Symbols/Extensions/RewrittenLambdaOrLocalFunctionSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Extensions/RewrittenLambdaOrLocalFunctionSymbol.cs new file mode 100644 index 0000000000000..f20efc3f1f199 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Symbols/Extensions/RewrittenLambdaOrLocalFunctionSymbol.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.Collections.Immutable; +using System.Diagnostics; +using Microsoft.CodeAnalysis.PooledObjects; + +namespace Microsoft.CodeAnalysis.CSharp.Symbols +{ + internal sealed class RewrittenLambdaOrLocalFunctionSymbol : RewrittenMethodSymbol + { + private readonly RewrittenMethodSymbol _containingMethod; + + public RewrittenLambdaOrLocalFunctionSymbol(MethodSymbol lambdaOrLocalFunctionSymbol, RewrittenMethodSymbol containingMethod) + : base(lambdaOrLocalFunctionSymbol, containingMethod.TypeMap, lambdaOrLocalFunctionSymbol.TypeParameters) + { + Debug.Assert(lambdaOrLocalFunctionSymbol.AssociatedSymbol is null); + Debug.Assert(lambdaOrLocalFunctionSymbol.TryGetThisParameter(out var thisParameter) && thisParameter is null); + _containingMethod = containingMethod; + } + + public override Symbol? AssociatedSymbol => null; + + public override Symbol ContainingSymbol => _containingMethod; + + internal override bool TryGetThisParameter(out ParameterSymbol? thisParameter) + { + thisParameter = null; + return true; + } + + protected override ImmutableArray MakeParameters() + { + return ImmutableArray.CastUp(_originalMethod.Parameters.SelectAsArray(static (p, @this) => new RewrittenMethodParameterSymbol(@this, p), this)); + } + } +} diff --git a/src/Compilers/CSharp/Portable/Symbols/Extensions/RewrittenMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Extensions/RewrittenMethodSymbol.cs new file mode 100644 index 0000000000000..fd634a9e9edc3 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Symbols/Extensions/RewrittenMethodSymbol.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.Collections.Immutable; +using System.Diagnostics; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.Symbols +{ + internal abstract class RewrittenMethodSymbol : WrappedMethodSymbol + { + protected readonly MethodSymbol _originalMethod; + private readonly TypeMap _typeMap; + private readonly ImmutableArray _typeParameters; + private ImmutableArray _lazyParameters; + + protected RewrittenMethodSymbol(MethodSymbol originalMethod, TypeMap typeMap, ImmutableArray typeParametersToAlphaRename) + { + Debug.Assert(originalMethod.IsDefinition); + Debug.Assert(originalMethod.ExplicitInterfaceImplementations.IsEmpty); + + _originalMethod = originalMethod; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Are we creating type parameters with the right emit behavior? Attributes, etc. + _typeMap = typeMap.WithAlphaRename(typeParametersToAlphaRename, this, out _typeParameters); + } + + public TypeMap TypeMap => _typeMap; + + public sealed override MethodSymbol UnderlyingMethod => _originalMethod; + + public sealed override ImmutableArray TypeParameters + { + get { return _typeParameters; } + } + + public sealed override ImmutableArray TypeArgumentsWithAnnotations + { + get { return GetTypeParametersAsTypeArguments(); } + } + + public sealed override TypeWithAnnotations ReturnTypeWithAnnotations + { + get { return _typeMap.SubstituteType(_originalMethod.ReturnTypeWithAnnotations); } + } + + internal override TypeWithAnnotations IteratorElementTypeWithAnnotations + { + get + { + TypeWithAnnotations iteratorElementTypeWithAnnotations = _originalMethod.IteratorElementTypeWithAnnotations; + + if (iteratorElementTypeWithAnnotations.HasType) + { + return _typeMap.SubstituteType(iteratorElementTypeWithAnnotations); + } + + return iteratorElementTypeWithAnnotations; + } + } + + internal override bool IsIterator + { + get { return _originalMethod.IsIterator; } + } + + internal sealed override int CalculateLocalSyntaxOffset(int localPosition, SyntaxTree localTree) + { + return _originalMethod.CalculateLocalSyntaxOffset(localPosition, localTree); + } + + internal sealed override bool IsNullableAnalysisEnabled() => throw ExceptionUtilities.Unreachable(); + + public sealed override ImmutableArray ExplicitInterfaceImplementations => ImmutableArray.Empty; + + internal sealed override UnmanagedCallersOnlyAttributeData? GetUnmanagedCallersOnlyAttributeData(bool forceComplete) + => _originalMethod.GetUnmanagedCallersOnlyAttributeData(forceComplete); + + public sealed override ImmutableArray RefCustomModifiers + { + get { return _typeMap.SubstituteCustomModifiers(_originalMethod.RefCustomModifiers); } + } + + public sealed override ImmutableArray GetAttributes() + { + return _originalMethod.GetAttributes(); + } + + internal sealed override UseSiteInfo GetUseSiteInfo() + { + return _originalMethod.GetUseSiteInfo(); + } + + public sealed override ImmutableArray Parameters + { + get + { + if (_lazyParameters.IsDefault) + { + ImmutableInterlocked.InterlockedInitialize(ref _lazyParameters, this.MakeParameters()); + } + return _lazyParameters; + } + } + + protected abstract ImmutableArray MakeParameters(); + + internal sealed override bool HasAsyncMethodBuilderAttribute(out TypeSymbol? builderArgument) + { + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Test this code path + return _originalMethod.HasAsyncMethodBuilderAttribute(out builderArgument); + } + + protected class RewrittenMethodParameterSymbol : RewrittenParameterSymbol + { + protected readonly RewrittenMethodSymbol _containingMethod; + + public RewrittenMethodParameterSymbol(RewrittenMethodSymbol containingMethod, ParameterSymbol originalParameter) : + base(originalParameter) + { + _containingMethod = containingMethod; + } + + public sealed override Symbol ContainingSymbol + { + get { return _containingMethod; } + } + + public override TypeWithAnnotations TypeWithAnnotations + { + get { return _containingMethod._typeMap.SubstituteType(this._underlyingParameter.TypeWithAnnotations); } + } + + public override ImmutableArray RefCustomModifiers + { + get + { + return _containingMethod._typeMap.SubstituteCustomModifiers(this._underlyingParameter.RefCustomModifiers); + } + } + } + } +} diff --git a/src/Compilers/CSharp/Portable/Symbols/Extensions/RewrittenParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Extensions/RewrittenParameterSymbol.cs new file mode 100644 index 0000000000000..ccf32fb12c6d3 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Symbols/Extensions/RewrittenParameterSymbol.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.Collections.Immutable; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.Symbols +{ + internal abstract class RewrittenParameterSymbol : WrappedParameterSymbol + { + public RewrittenParameterSymbol(ParameterSymbol originalParameter) : + base(originalParameter) + { + } + + internal sealed override bool IsCallerLineNumber => _underlyingParameter.IsCallerLineNumber; + + internal sealed override bool IsCallerFilePath => _underlyingParameter.IsCallerFilePath; + + internal sealed override bool IsCallerMemberName => _underlyingParameter.IsCallerMemberName; + + internal sealed override int CallerArgumentExpressionParameterIndex => _underlyingParameter.CallerArgumentExpressionParameterIndex; + + internal sealed override ImmutableArray InterpolatedStringHandlerArgumentIndexes => throw ExceptionUtilities.Unreachable(); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Follow up + + internal sealed override bool HasInterpolatedStringHandlerArgumentError => throw ExceptionUtilities.Unreachable(); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Follow up + } +} diff --git a/src/Compilers/CSharp/Portable/Symbols/Extensions/SourceExtensionImplementationMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Extensions/SourceExtensionImplementationMethodSymbol.cs new file mode 100644 index 0000000000000..574b60f151077 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Symbols/Extensions/SourceExtensionImplementationMethodSymbol.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.Collections.Immutable; +using System.Diagnostics; +using Microsoft.CodeAnalysis.CSharp.Emit; +using Microsoft.CodeAnalysis.PooledObjects; + +namespace Microsoft.CodeAnalysis.CSharp.Symbols +{ + internal sealed class SourceExtensionImplementationMethodSymbol : RewrittenMethodSymbol // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Do we need to implement ISynthesizedMethodBodyImplementationSymbol? + { + public SourceExtensionImplementationMethodSymbol(MethodSymbol sourceMethod) + : base(sourceMethod, TypeMap.Empty, sourceMethod.ContainingType.TypeParameters.Concat(sourceMethod.TypeParameters)) + { + Debug.Assert(sourceMethod.GetIsNewExtensionMember()); + Debug.Assert(sourceMethod.IsStatic || sourceMethod.ContainingType.ExtensionParameter is not null); + Debug.Assert(!sourceMethod.IsExtern); + Debug.Assert(!sourceMethod.IsExternal); + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Are we creating type parameters with the right emit behavior? Attributes, etc. + // Also, they should be IsImplicitlyDeclared + } + + public override int Arity => TypeParameters.Length; + + public override bool IsGenericMethod => Arity != 0; + + public override MethodKind MethodKind => MethodKind.Ordinary; + public override bool IsImplicitlyDeclared => true; + + internal override bool HasSpecialName => true; // Tracked by https://github.com/dotnet/roslyn/issues/76130 : reconcile with spec + + internal override int ParameterCount + { + get + { + return _originalMethod.ParameterCount + (_originalMethod.IsStatic ? 0 : 1); + } + } + + public sealed override bool IsExtensionMethod => !_originalMethod.IsStatic && _originalMethod.MethodKind is MethodKind.Ordinary; + public sealed override bool IsVirtual => false; + + public sealed override bool IsOverride => false; + public sealed override bool IsAbstract => false; + public sealed override bool IsSealed => false; + + internal sealed override bool IsMetadataVirtual(IsMetadataVirtualOption option = IsMetadataVirtualOption.None) => false; + internal sealed override bool IsMetadataFinal => false; + internal sealed override bool IsMetadataNewSlot(bool ignoreInterfaceImplementationChanges = false) => false; + + internal sealed override bool IsAccessCheckedOnOverride => false; + + public sealed override bool IsExtern => false; + public sealed override DllImportData? GetDllImportData() => null; + internal sealed override bool IsExternal => false; + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : How doc comments are supposed to work? GetDocumentationCommentXml + + internal sealed override bool IsDeclaredReadOnly => false; + + public sealed override Symbol ContainingSymbol => _originalMethod.ContainingType.ContainingSymbol; + + internal sealed override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + { + base.AddSynthesizedAttributes(moduleBuilder, ref attributes); + SourceMethodSymbol.AddSynthesizedAttributes(this, moduleBuilder, ref attributes); + } + + public override bool IsStatic => true; + public override bool RequiresInstanceReceiver => false; + + internal override Microsoft.Cci.CallingConvention CallingConvention + { + get + { + return (_originalMethod.CallingConvention & (~Cci.CallingConvention.HasThis)) | + (Arity != 0 ? Cci.CallingConvention.Generic : 0); + } + } + + public override Symbol? AssociatedSymbol => null; + + protected override ImmutableArray MakeParameters() + { + var sourceParameters = _originalMethod.Parameters; + var parameters = ArrayBuilder.GetInstance(ParameterCount); + + if (!_originalMethod.IsStatic) + { + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Need to confirm if this rewrite going to break LocalStateTracingInstrumenter + // Specifically BoundParameterId, etc. + parameters.Add(new ExtensionMetadataMethodParameterSymbol(this, ((SourceNamedTypeSymbol)_originalMethod.ContainingType).ExtensionParameter!)); + } + + foreach (var parameter in sourceParameters) + { + parameters.Add(new ExtensionMetadataMethodParameterSymbol(this, parameter)); + } + + Debug.Assert(parameters.Count == ParameterCount); + return parameters.ToImmutableAndFree(); + } + + internal override bool TryGetThisParameter(out ParameterSymbol? thisParameter) + { + thisParameter = null; + return true; + } + + private sealed class ExtensionMetadataMethodParameterSymbol : RewrittenMethodParameterSymbol + { + public ExtensionMetadataMethodParameterSymbol(SourceExtensionImplementationMethodSymbol containingMethod, ParameterSymbol sourceParameter) : + base(containingMethod, sourceParameter) + { + } + + public override bool IsImplicitlyDeclared => true; + + public override int Ordinal + { + get + { + if (this._underlyingParameter.ContainingSymbol is NamedTypeSymbol) + { + return 0; + } + + var ordinal = this._underlyingParameter.Ordinal; + + if (this._underlyingParameter.ContainingSymbol.IsStatic) + { + return ordinal; + } + + return ordinal + 1; + } + } + } + } +} diff --git a/src/Compilers/CSharp/Portable/Symbols/Extensions/SynthesizedExtensionMarker.cs b/src/Compilers/CSharp/Portable/Symbols/Extensions/SynthesizedExtensionMarker.cs new file mode 100644 index 0000000000000..b342e1410381c --- /dev/null +++ b/src/Compilers/CSharp/Portable/Symbols/Extensions/SynthesizedExtensionMarker.cs @@ -0,0 +1,122 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.PooledObjects; + +namespace Microsoft.CodeAnalysis.CSharp.Symbols +{ + /// + /// This method encodes the information needed to round-trip extension types + /// through metadata. + /// + /// It encodes receiver parameter - the only parameter of the method + /// + internal sealed class SynthesizedExtensionMarker : SynthesizedSourceOrdinaryMethodSymbol + { + internal SynthesizedExtensionMarker(SourceMemberContainerTypeSymbol extensionType, ParameterListSyntax parameterList) + : base(extensionType, WellKnownMemberNames.ExtensionMarkerMethodName, parameterList.OpenParenToken.GetLocation(), parameterList, + (GetDeclarationModifiers(), MakeFlags( + MethodKind.Ordinary, RefKind.None, GetDeclarationModifiers(), returnsVoid: false, returnsVoidIsSet: false, + isExpressionBodied: false, isExtensionMethod: false, isNullableAnalysisEnabled: false, isVarArg: false, + isExplicitInterfaceImplementation: false, hasThisInitializer: false))) + { + Debug.Assert(extensionType.IsDefinition); + Debug.Assert(extensionType.IsExtension); + Debug.Assert(parameterList is not null); + + return; + } + + private static DeclarationModifiers GetDeclarationModifiers() => DeclarationModifiers.Private | DeclarationModifiers.Static; + + internal override bool HasSpecialName => true; // Tracked by https://github.com/dotnet/roslyn/issues/76130 : reconcile with spec + + internal override void GenerateMethodBody(TypeCompilationState compilationState, BindingDiagnosticBag diagnostics) + { + var F = new SyntheticBoundNodeFactory(this, ContainingType.GetNonNullSyntaxNode(), compilationState, diagnostics); + F.CloseMethod(F.Return()); + } + + protected override int GetParameterCountFromSyntax() + { + ParameterListSyntax parameterList = (ParameterListSyntax)syntaxReferenceOpt.GetSyntax(); + return parameterList.Parameters is [{ IsArgList: false }, ..] ? 1 : 0; + } + + protected override (TypeWithAnnotations ReturnType, ImmutableArray Parameters) MakeParametersAndBindReturnType(BindingDiagnosticBag diagnostics) + { + return (TypeWithAnnotations.Create(Binder.GetSpecialType(DeclaringCompilation, SpecialType.System_Void, GetFirstLocation(), diagnostics)), + makeExtensionParameter(diagnostics) is { } parameter ? [parameter] : []); + + ParameterSymbol? makeExtensionParameter(BindingDiagnosticBag diagnostics) + { + ParameterListSyntax parameterList = (ParameterListSyntax)syntaxReferenceOpt.GetSyntax(); + int count = parameterList.Parameters.Count; + + if (count == 0) + { + return null; + } + + BinderFactory binderFactory = this.DeclaringCompilation.GetBinderFactory(parameterList.SyntaxTree); + var withTypeParamsBinder = binderFactory.GetBinder(parameterList); + + // Constraints are checked later + var signatureBinder = withTypeParamsBinder.WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.SuppressConstraintChecks, this); + + for (int parameterIndex = 1; parameterIndex < count; parameterIndex++) + { + diagnostics.Add(ErrorCode.ERR_ReceiverParameterOnlyOne, parameterList.Parameters[parameterIndex].GetLocation()); + } + + ParameterSymbol? parameter = ParameterHelpers.MakeExtensionReceiverParameter(withTypeParametersBinder: signatureBinder, owner: this, parameterList, diagnostics); + + if (parameter is { }) + { + checkUnderspecifiedGenericExtension(parameter, ContainingType.TypeParameters, diagnostics); + } + + if (parameter is { Name: var name } && name != "" && + ContainingType.TypeParameters.Any(static (p, name) => p.Name == name, name)) + { + diagnostics.Add(ErrorCode.ERR_ReceiverParameterSameNameAsTypeParameter, parameter.GetFirstLocation(), name); + } + + return parameter; + } + + static void checkUnderspecifiedGenericExtension(ParameterSymbol parameter, ImmutableArray typeParameters, BindingDiagnosticBag diagnostics) + { + var underlyingType = parameter.Type; + var usedTypeParameters = PooledHashSet.GetInstance(); + underlyingType.VisitType(collectTypeParameters, arg: usedTypeParameters); + + foreach (var typeParameter in typeParameters) + { + if (!usedTypeParameters.Contains(typeParameter)) + { + diagnostics.Add(ErrorCode.ERR_UnderspecifiedExtension, parameter.GetFirstLocation(), underlyingType, typeParameter); + } + } + + usedTypeParameters.Free(); + } + + static bool collectTypeParameters(TypeSymbol type, PooledHashSet typeParameters, bool ignored) + { + if (type is TypeParameterSymbol typeParameter) + { + typeParameters.Add(typeParameter); + } + + return false; + } + + } + } +} + diff --git a/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerTypeSymbol.cs index 5db3fd3bd3a4e..0af58ff20b8fe 100644 --- a/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerTypeSymbol.cs @@ -72,6 +72,7 @@ private FunctionPointerTypeSymbol(FunctionPointerMethodSymbol signature) public override bool IsReferenceType => false; public override bool IsValueType => true; + internal sealed override ParameterSymbol? ExtensionParameter => null; public override TypeKind TypeKind => TypeKind.FunctionPointer; public override bool IsRefLikeType => false; public override bool IsReadOnly => false; diff --git a/src/Compilers/CSharp/Portable/Symbols/FunctionTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/FunctionTypeSymbol.cs index 0cbd87e3b03e4..1058dcf3aaa55 100644 --- a/src/Compilers/CSharp/Portable/Symbols/FunctionTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/FunctionTypeSymbol.cs @@ -99,6 +99,8 @@ internal void SetExpression(BoundExpression expression) public override bool IsValueType => false; + internal sealed override ParameterSymbol? ExtensionParameter => null; + public override TypeKind TypeKind => TypeKindInternal.FunctionType; public override bool IsRefLikeType => false; diff --git a/src/Compilers/CSharp/Portable/Symbols/MemberSignatureComparer.cs b/src/Compilers/CSharp/Portable/Symbols/MemberSignatureComparer.cs index 2ee050ccc2797..d70ecd4d63436 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MemberSignatureComparer.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MemberSignatureComparer.cs @@ -771,45 +771,59 @@ internal static bool HaveSameParameterTypes( for (int i = 0; i < numParams; i++) { - var param1 = params1[i]; - var param2 = params2[i]; - - var type1 = SubstituteType(typeMap1, param1.TypeWithAnnotations); - var type2 = SubstituteType(typeMap2, param2.TypeWithAnnotations); - - if (!type1.Equals(type2, typeComparison)) + if (!HaveSameParameterType(params1[i], typeMap1, params2[i], typeMap2, refKindCompareMode, considerDefaultValues, typeComparison)) { return false; } + } - if (considerDefaultValues && param1.ExplicitDefaultConstantValue != param2.ExplicitDefaultConstantValue) - { - return false; - } + return true; + } - if ((typeComparison & TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds) == 0 && - !HaveSameCustomModifiers(param1.RefCustomModifiers, typeMap1, param2.RefCustomModifiers, typeMap2)) - { - return false; - } + internal static bool HaveSameParameterType( + ParameterSymbol param1, + TypeMap? typeMap1, + ParameterSymbol param2, + TypeMap? typeMap2, + RefKindCompareMode refKindCompareMode, + bool considerDefaultValues, + TypeCompareKind typeComparison) + { + var type1 = SubstituteType(typeMap1, param1.TypeWithAnnotations); + var type2 = SubstituteType(typeMap2, param2.TypeWithAnnotations); - var refKind1 = param1.RefKind; - var refKind2 = param2.RefKind; + if (!type1.Equals(type2, typeComparison)) + { + return false; + } - // Metadata signatures don't distinguish ref/out, but C# does - even when comparing metadata method signatures. - if ((refKindCompareMode & RefKindCompareMode.ConsiderDifferences) != 0) + if (considerDefaultValues && param1.ExplicitDefaultConstantValue != param2.ExplicitDefaultConstantValue) + { + return false; + } + + if ((typeComparison & TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds) == 0 && + !HaveSameCustomModifiers(param1.RefCustomModifiers, typeMap1, param2.RefCustomModifiers, typeMap2)) + { + return false; + } + + var refKind1 = param1.RefKind; + var refKind2 = param2.RefKind; + + // Metadata signatures don't distinguish ref/out, but C# does - even when comparing metadata method signatures. + if ((refKindCompareMode & RefKindCompareMode.ConsiderDifferences) != 0) + { + if (!areRefKindsCompatible(refKindCompareMode, refKind1, refKind2)) { - if (!areRefKindsCompatible(refKindCompareMode, refKind1, refKind2)) - { - return false; - } + return false; } - else + } + else + { + if ((refKind1 == RefKind.None) != (refKind2 == RefKind.None)) { - if ((refKind1 == RefKind.None) != (refKind2 == RefKind.None)) - { - return false; - } + return false; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/MemberSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/MemberSymbolExtensions.cs index 638734bf2cdf4..775b8e8a39edd 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MemberSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MemberSymbolExtensions.cs @@ -11,6 +11,7 @@ using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -77,6 +78,166 @@ internal static bool GetIsVararg(this Symbol member) } } +#nullable enable + internal static bool GetIsNewExtensionMember(this Symbol member) + { + switch (member.Kind) + { + case SymbolKind.Method: + case SymbolKind.Property: + return member.ContainingSymbol is TypeSymbol { IsExtension: true }; + default: + return false; + } + } + + internal static bool GetIsNewExtensionMember(this MethodSymbol member) + { + return member.ContainingSymbol is TypeSymbol { IsExtension: true }; + } + + internal static bool GetIsNewExtensionMember(this PropertySymbol member) + { + return member.ContainingSymbol is TypeSymbol { IsExtension: true }; + } + + internal static int GetMemberArityIncludingExtension(this Symbol member) + { + if (member.GetIsNewExtensionMember()) + { + return member.ContainingType.Arity + member.GetMemberArity(); + } + + return member.GetMemberArity(); + } + + /// + /// For an extension member, we distribute the type arguments between the extension declaration and the member. + /// Otherwise, we just construct the member with the type arguments. + /// + internal static TMember ConstructIncludingExtension(this TMember member, ImmutableArray typeArguments) where TMember : Symbol + { + if (member is MethodSymbol method) + { + if (method.GetIsNewExtensionMember()) + { + NamedTypeSymbol extension = method.ContainingType; + if (extension.Arity > 0) + { + extension = extension.Construct(typeArguments[..extension.Arity]); + method = method.AsMember(extension); + } + + if (method.Arity > 0) + { + return (TMember)(Symbol)method.Construct(typeArguments[extension.Arity..]); + } + + return (TMember)(Symbol)method; + } + + return (TMember)(Symbol)method.Construct(typeArguments); + } + + if (member is PropertySymbol property) + { + Debug.Assert(property.GetIsNewExtensionMember()); + NamedTypeSymbol extension = property.ContainingType; + Debug.Assert(extension.Arity > 0); + Debug.Assert(extension.Arity == typeArguments.Length); + + extension = extension.Construct(typeArguments); + property = property.AsMember(extension); + + return (TMember)(Symbol)property; + } + + throw ExceptionUtilities.UnexpectedValue(member); + } + + // For lookup APIs in the semantic model, we can return symbols that aren't fully inferred. + // But for function type inference, if the symbol isn't fully inferred with the information we have (the receiver and any explicit type arguments) + // then we won't return it. + internal static Symbol? GetReducedAndFilteredSymbol(this Symbol member, ImmutableArray typeArguments, TypeSymbol receiverType, CSharpCompilation compilation, bool checkFullyInferred) + { + if (member is MethodSymbol method) + { + // 1. construct with explicit type arguments if provided + MethodSymbol? constructed; + if (!typeArguments.IsDefaultOrEmpty && method.GetMemberArityIncludingExtension() == typeArguments.Length) + { + constructed = method.ConstructIncludingExtension(typeArguments); + Debug.Assert((object)constructed != null); + + if (!checkConstraintsIncludingExtension(constructed, compilation, method.ContainingAssembly.CorLibrary.TypeConversions)) + { + return null; + } + } + else + { + constructed = method; + } + + // 2. infer type arguments based on the receiver type if needed, check applicability, reduce symbol (for classic extension methods), check whether fully inferred + if ((object)receiverType != null) + { + if (method.IsExtensionMethod) + { + constructed = constructed.ReduceExtensionMethod(receiverType, compilation, out bool wasFullyInferred); + + if (checkFullyInferred && !wasFullyInferred) + { + return null; + } + } + else + { + Debug.Assert(method.GetIsNewExtensionMember()); + constructed = (MethodSymbol?)SourceNamedTypeSymbol.GetCompatibleSubstitutedMember(compilation, constructed, receiverType); + + if (checkFullyInferred && constructed?.IsGenericMethod == true && typeArguments.IsDefaultOrEmpty) + { + return null; + } + } + } + + return constructed; + } + else if (member is PropertySymbol property) + { + // infer type arguments based off the receiver type if needed, check applicability + Debug.Assert(receiverType is not null); + Debug.Assert(property.GetIsNewExtensionMember()); + return (PropertySymbol?)SourceNamedTypeSymbol.GetCompatibleSubstitutedMember(compilation, property, receiverType); + } + + throw ExceptionUtilities.UnexpectedValue(member.Kind); + + static bool checkConstraintsIncludingExtension(MethodSymbol symbol, CSharpCompilation compilation, TypeConversions conversions) + { + var constraintArgs = new ConstraintsHelper.CheckConstraintsArgs(compilation, conversions, includeNullability: false, + NoLocation.Singleton, diagnostics: BindingDiagnosticBag.Discarded, template: CompoundUseSiteInfo.Discarded); + + bool success = true; + + if (symbol.GetIsNewExtensionMember()) + { + NamedTypeSymbol extensionDeclaration = symbol.ContainingType; + success = extensionDeclaration.CheckConstraints(constraintArgs); + } + + if (success) + { + success = symbol.CheckConstraints(constraintArgs); + } + + return success; + } + } +#nullable disable + /// /// Get the ref kinds of the parameters of a member symbol. Should be a method, property, or event. /// @@ -551,7 +712,10 @@ internal static bool IsPartialMember(this Symbol member) return member is SourceOrdinaryMethodSymbol { IsPartial: true } or SourcePropertySymbol { IsPartial: true } - or SourcePropertyAccessorSymbol { IsPartial: true }; + or SourcePropertyAccessorSymbol { IsPartial: true } + or SourceConstructorSymbol { IsPartial: true } + or SourceEventSymbol { IsPartial: true } + or SourceEventAccessorSymbol { IsPartial: true }; } internal static bool IsPartialImplementation(this Symbol member) @@ -560,7 +724,10 @@ internal static bool IsPartialImplementation(this Symbol member) return member is SourceOrdinaryMethodSymbol { IsPartialImplementation: true } or SourcePropertySymbol { IsPartialImplementation: true } - or SourcePropertyAccessorSymbol { IsPartialImplementation: true }; + or SourcePropertyAccessorSymbol { IsPartialImplementation: true } + or SourceConstructorSymbol { IsPartialImplementation: true } + or SourceEventSymbol { IsPartialImplementation: true } + or SourceEventAccessorSymbol { IsPartialImplementation: true }; } internal static bool IsPartialDefinition(this Symbol member) @@ -569,9 +736,38 @@ internal static bool IsPartialDefinition(this Symbol member) return member is SourceOrdinaryMethodSymbol { IsPartialDefinition: true } or SourcePropertySymbol { IsPartialDefinition: true } - or SourcePropertyAccessorSymbol { IsPartialDefinition: true }; + or SourcePropertyAccessorSymbol { IsPartialDefinition: true } + or SourceConstructorSymbol { IsPartialDefinition: true } + or SourceEventSymbol { IsPartialDefinition: true } + or SourceEventAccessorSymbol { IsPartialDefinition: true }; } +#nullable enable + internal static Symbol? GetPartialImplementationPart(this Symbol member) + { + Debug.Assert(member.IsDefinition); + return member switch + { + MethodSymbol method => method.PartialImplementationPart, + SourcePropertySymbol property => property.PartialImplementationPart, + SourceEventSymbol ev => ev.PartialImplementationPart, + _ => null, + }; + } + + internal static Symbol? GetPartialDefinitionPart(this Symbol member) + { + Debug.Assert(member.IsDefinition); + return member switch + { + MethodSymbol method => method.PartialDefinitionPart, + SourcePropertySymbol property => property.PartialDefinitionPart, + SourceEventSymbol ev => ev.PartialDefinitionPart, + _ => null, + }; + } +#nullable disable + internal static bool ContainsTupleNames(this Symbol member) { switch (member.Kind) diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs index 7858debda8da4..af21b24798582 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs @@ -1463,6 +1463,13 @@ internal override UseSiteInfo GetUseSiteInfo() MergeUseSiteDiagnostics(ref diagnosticInfo, DeriveCompilerFeatureRequiredDiagnostic()); EnsureTypeParametersAreLoaded(ref diagnosticInfo); + if (diagnosticInfo == null && _containingType.IsExtension && + TryGetCorrespondingExtensionImplementationMethod() is null) + { + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Test this code path + diagnosticInfo = new CSDiagnosticInfo(ErrorCode.ERR_BindToBogus, this); + } + if (diagnosticInfo == null && _containingType.ContainingPEModule.RefSafetyRulesVersion == PEModuleSymbol.RefSafetyRulesAttributeVersion.UnrecognizedAttribute) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs index 60d770d5ad6b8..6d4d4880c52b7 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs @@ -5,6 +5,7 @@ #nullable disable using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; @@ -13,6 +14,7 @@ using System.Reflection; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; using Microsoft.CodeAnalysis.Collections; @@ -117,7 +119,7 @@ private bool IsUncommon() return true; } - if (this.TypeKind == TypeKind.Enum) + if (this.TypeKind is TypeKind.Enum or TypeKind.Extension) { return true; } @@ -151,6 +153,7 @@ private sealed class UncommonProperties internal ImmutableArray lazyFilePathChecksum = default; internal string lazyDisplayFileName; + internal ExtensionInfo lazyExtensionInfo; #if DEBUG internal bool IsDefaultValue() @@ -169,11 +172,23 @@ internal bool IsDefaultValue() !lazyHasRequiredMembers.HasValue() && (object)lazyCollectionBuilderAttributeData == CollectionBuilderAttributeData.Uninitialized && lazyFilePathChecksum.IsDefault && - lazyDisplayFileName == null; + lazyDisplayFileName == null && + lazyExtensionInfo is null; } #endif } +#nullable enable + + private class ExtensionInfo(MethodDefinitionHandle markerMethod) + { + public readonly MethodDefinitionHandle MarkerMethod = markerMethod; + public StrongBox? LazyExtensionParameter; + public ConcurrentDictionary? LazyImplementationMap; + } + +#nullable disable + #endregion // Uncommon properties internal static PENamedTypeSymbol Create( @@ -366,6 +381,166 @@ public override ExtendedSpecialType ExtendedSpecialType } } +#nullable enable + + internal sealed override ParameterSymbol? ExtensionParameter + { + get + { + if (!IsExtension) + { + return null; + } + + var uncommon = GetUncommonProperties().lazyExtensionInfo; + + if (uncommon.LazyExtensionParameter is null) + { + var extensionParameter = makeExtensionParameter(this, uncommon); + Interlocked.CompareExchange(ref uncommon.LazyExtensionParameter, new StrongBox(extensionParameter), null); + } + + return uncommon.LazyExtensionParameter.Value; + + static ParameterSymbol? makeExtensionParameter(PENamedTypeSymbol @this, ExtensionInfo uncommon) + { + var methodSymbol = getMarkerMethodSymbol(@this, uncommon); + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : do we want to tighten the flags check further? (require that type be sealed?) + if (methodSymbol.DeclaredAccessibility != Accessibility.Private || + methodSymbol.IsGenericMethod || + !methodSymbol.IsStatic || + !methodSymbol.ReturnsVoid || + methodSymbol.ParameterCount != 1) // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Should we accept more than one parameter (in case new versions add more info)? + { + return null; // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Test this code path + } + + return new ReceiverParameterSymbol(@this, methodSymbol.Parameters[0]); + } + + static MethodSymbol getMarkerMethodSymbol(PENamedTypeSymbol @this, ExtensionInfo uncommon) + { + Debug.Assert(!uncommon.MarkerMethod.IsNil); + + foreach (var member in @this.GetMembers(WellKnownMemberNames.ExtensionMarkerMethodName)) + { + if (member is PEMethodSymbol candidate && candidate.Handle == uncommon.MarkerMethod) + { + return candidate; + } + } + + throw ExceptionUtilities.Unreachable(); + } + } + } + + public sealed override MethodSymbol? TryGetCorrespondingExtensionImplementationMethod(MethodSymbol method) + { + Debug.Assert(this.IsExtension); + Debug.Assert(method.IsDefinition); + Debug.Assert(method.ContainingType == (object)this); + + if (this.ContainingType is null) + { + return null; // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Test this code path + } + + if (!method.IsStatic && ExtensionParameter is null) + { + return null; // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Test this code path + } + + var uncommon = GetUncommonProperties().lazyExtensionInfo; + + if (uncommon.LazyImplementationMap is null) + { + Interlocked.CompareExchange(ref uncommon.LazyImplementationMap, new ConcurrentDictionary(Roslyn.Utilities.ReferenceEqualityComparer.Instance), null); + } + + return uncommon.LazyImplementationMap.GetOrAdd(method, findCorrespondingExtensionImplementationMethod, this); + + static MethodSymbol? findCorrespondingExtensionImplementationMethod(MethodSymbol method, PENamedTypeSymbol @this) + { + Debug.Assert(@this.ExtensionParameter is not null); + + foreach (var member in @this.ContainingType.GetMembers(method.Name)) + { + if (member is not MethodSymbol { HasSpecialName: true, IsStatic: true } candidate) + { + continue; // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Test this code path + } + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Consider comparing accessibility as well + + if (candidate.Arity != @this.Arity + method.Arity) + { + continue; // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Test this code path + } + + int additionalParameterCount = method.IsStatic ? 0 : 1; + if (additionalParameterCount + method.ParameterCount != candidate.ParameterCount) + { + continue; // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Test this code path + } + + ImmutableArray combinedTypeParameters = @this.TypeParameters.Concat(method.TypeParameters); + var typeMap = combinedTypeParameters.IsEmpty ? null : new TypeMap(combinedTypeParameters, candidate.TypeParameters); + + if (!MemberSignatureComparer.HaveSameReturnTypes( + candidate, + typeMap1: null, + method, + typeMap, + TypeCompareKind.CLRSignatureCompareOptions)) + { + continue; // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Test this code path + } + + if (!method.IsStatic && + !MemberSignatureComparer.HaveSameParameterType( + candidate.Parameters[0], + typeMap1: null, + @this.ExtensionParameter, + typeMap, + MemberSignatureComparer.RefKindCompareMode.ConsiderDifferences, + considerDefaultValues: false, + TypeCompareKind.CLRSignatureCompareOptions)) + { + continue; // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Test this code path + } + + if (!MemberSignatureComparer.HaveSameParameterTypes( + candidate.Parameters.AsSpan(additionalParameterCount, candidate.ParameterCount - additionalParameterCount), + typeMap1: null, + method.Parameters.AsSpan(), + typeMap, + MemberSignatureComparer.RefKindCompareMode.ConsiderDifferences, + considerDefaultValues: false, + TypeCompareKind.CLRSignatureCompareOptions)) + { + continue; // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Test this code path + } + + if (MemberSignatureComparer.HaveSameConstraints( + candidate.TypeParameters, + typeMap1: null, + combinedTypeParameters, + typeMap)) + { + return candidate; + } + + break; // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Test this code path + } + + return null; // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Test this code path + } + } + +#nullable disable + internal PEModuleSymbol ContainingPEModule { get @@ -1777,7 +1952,7 @@ public override TypeKind TypeKind { get { - TypeKind result = _lazyKind; + var result = (TypeKind)Volatile.Read(ref Unsafe.As(ref _lazyKind)); if (result == TypeKind.Unknown) { @@ -1815,6 +1990,21 @@ public override TypeKind TypeKind result = TypeKind.Struct; } break; + + default: + if (TryGetExtensionMarkerMethod() is { IsNil: false } markerHandle) + { + // Extension + result = TypeKind.Extension; + + if (_lazyUncommonProperties is null) + { + Interlocked.CompareExchange(ref _lazyUncommonProperties, new UncommonProperties(), null); + } + + Interlocked.CompareExchange(ref _lazyUncommonProperties.lazyExtensionInfo, new ExtensionInfo(markerHandle), null); + } + break; } } } @@ -1826,6 +2016,46 @@ public override TypeKind TypeKind } } + /// + /// Superficially checks whether this is a valid extension type + /// and returns the extension marker method (to be validated later) + /// if it is. + /// + private MethodDefinitionHandle TryGetExtensionMarkerMethod() + { + var moduleSymbol = this.ContainingPEModule; + var module = moduleSymbol.Module; + + try + { + // They must have a single marker method (to be validated later) + MethodDefinitionHandle foundMarkerMethod = default; + foreach (var methodHandle in module.GetMethodsOfTypeOrThrow(_handle)) + { + string methodName; + MethodAttributes flags; + module.GetMethodDefPropsOrThrow(methodHandle, out methodName, out _, out flags, out _); + + if ((flags & MethodAttributes.SpecialName) != 0 && methodName is WellKnownMemberNames.ExtensionMarkerMethodName) + { + if (!foundMarkerMethod.IsNil) + { + return default; // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Test this code path + } + + foundMarkerMethod = methodHandle; + } + } + + return foundMarkerMethod; + } + catch (BadImageFormatException) + { + } + + return default; + } + internal sealed override bool IsInterface { get @@ -2008,11 +2238,15 @@ private PooledDictionary CreateMethods(A // for ordinary embeddable struct types we import private members so that we can report appropriate errors if the structure is used var isOrdinaryEmbeddableStruct = (this.TypeKind == TypeKind.Struct) && (this.SpecialType == Microsoft.CodeAnalysis.SpecialType.None) && this.ContainingAssembly.IsLinked; + MethodDefinitionHandle? extensionMarkerMethod = _lazyUncommonProperties?.lazyExtensionInfo?.MarkerMethod; + Debug.Assert(extensionMarkerMethod is not null || this.TypeKind is not TypeKind.Extension); + try { foreach (var methodHandle in module.GetMethodsOfTypeOrThrow(_handle)) { - if (isOrdinaryEmbeddableStruct || module.ShouldImportMethod(_handle, methodHandle, moduleSymbol.ImportOptions)) + if (isOrdinaryEmbeddableStruct || module.ShouldImportMethod(_handle, methodHandle, moduleSymbol.ImportOptions) || + extensionMarkerMethod == methodHandle) { var method = new PEMethodSymbol(moduleSymbol, this, methodHandle); members.Add(method); @@ -2323,6 +2557,9 @@ public override bool IsRefLikeType } } + internal override string ExtensionName + => Name; // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Confirm implementation + public override bool IsReadOnly { get diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamespaceSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamespaceSymbol.cs index 8b7133a7843bf..9ec821ac724f4 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamespaceSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamespaceSymbol.cs @@ -2,12 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection.Metadata; using System.Threading; @@ -27,20 +26,20 @@ internal abstract class PENamespaceSymbol /// A map of namespaces immediately contained within this namespace /// mapped by their name (case-sensitively). /// - protected Dictionary, PENestedNamespaceSymbol> lazyNamespaces; + protected Dictionary, PENestedNamespaceSymbol>? lazyNamespaces; /// /// A map of types immediately contained within this namespace /// grouped by their name (case-sensitively). /// - protected Dictionary, ImmutableArray> lazyTypes; + protected Dictionary, ImmutableArray>? lazyTypes; /// /// A map of NoPia local types immediately contained in this assembly. /// Maps type name (non-qualified) to the row id. Note, for VB we should use /// full name. /// - private Dictionary _lazyNoPiaLocalTypes; + private Dictionary? _lazyNoPiaLocalTypes; /// /// All type members in a flat array @@ -98,6 +97,7 @@ private ImmutableArray GetMemberTypesPrivate() //assume that EnsureAllMembersLoaded() has initialize lazyTypes if (_lazyFlattenedTypes.IsDefault) { + Debug.Assert(lazyTypes != null); var flattened = lazyTypes.Flatten(); ImmutableInterlocked.InterlockedExchange(ref _lazyFlattenedTypes, flattened); } @@ -105,7 +105,7 @@ private ImmutableArray GetMemberTypesPrivate() return StaticCast.From(_lazyFlattenedTypes); } - internal override NamespaceSymbol GetNestedNamespace(ReadOnlyMemory name) + internal override NamespaceSymbol? GetNestedNamespace(ReadOnlyMemory name) { EnsureAllMembersLoaded(); @@ -121,7 +121,7 @@ public sealed override ImmutableArray GetMembers(ReadOnlyMemory na { EnsureAllMembersLoaded(); - PENestedNamespaceSymbol ns = null; + PENestedNamespaceSymbol? ns = null; ImmutableArray t; if (lazyNamespaces.TryGetValue(name, out ns)) @@ -189,6 +189,8 @@ public override ImmutableArray DeclaringSyntaxReferences /// PEModuleSymbol containing the namespace. internal abstract PEModuleSymbol ContainingPEModule { get; } + [MemberNotNull(nameof(lazyTypes))] + [MemberNotNull(nameof(lazyNamespaces))] protected abstract void EnsureAllMembersLoaded(); /// @@ -204,19 +206,21 @@ public override ImmutableArray DeclaringSyntaxReferences /// immediately contained within Global namespace. Therefore, all types in this namespace, if any, /// must be in several first IGroupings. /// + [MemberNotNull(nameof(lazyTypes))] + [MemberNotNull(nameof(lazyNamespaces))] protected void LoadAllMembers(IEnumerable> typesByNS) { Debug.Assert(typesByNS != null); // A sequence of groups of TypeDef row ids for types immediately contained within this namespace. - IEnumerable> nestedTypes = null; + IEnumerable>? nestedTypes = null; // A sequence with information about namespaces immediately contained within this namespace. // For each pair: // Key - contains simple name of a child namespace. // Value - contains a sequence similar to the one passed to this function, but // calculated for the child namespace. - IEnumerable>>> nestedNamespaces = null; + IEnumerable>>>? nestedNamespaces = null; bool isGlobalNamespace = this.IsGlobalNamespace; MetadataHelpers.GetInfoForImmediateNamespaceMembers( @@ -249,6 +253,7 @@ private int GetQualifiedNameLength() /// /// Create symbols for nested namespaces and initialize namespaces map. /// + [MemberNotNull(nameof(lazyNamespaces))] private void LazyInitializeNamespaces( IEnumerable>>> childNamespaces) { @@ -269,6 +274,7 @@ private void LazyInitializeNamespaces( /// /// Create symbols for nested types and initialize types map. /// + [MemberNotNull(nameof(lazyTypes))] private void LazyInitializeTypes(IEnumerable> typeGroups) { if (this.lazyTypes == null) @@ -277,7 +283,7 @@ private void LazyInitializeTypes(IEnumerable.GetInstance(); var skipCheckForPiaType = !moduleSymbol.Module.ContainsNoPiaLocalTypes(); - Dictionary noPiaLocalTypes = null; + Dictionary? noPiaLocalTypes = null; foreach (var g in typeGroups) { @@ -325,8 +331,6 @@ private void LazyInitializeTypes(IEnumerable methods, string n { var thisParam = method.Parameters.First(); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : we should use similar logic when looking up new extension members if ((thisParam.RefKind == RefKind.Ref && !thisParam.Type.IsValueType) || (thisParam.RefKind is RefKind.In or RefKind.RefReadOnlyParameter && thisParam.Type.TypeKind != TypeKind.Struct)) { @@ -369,6 +370,15 @@ internal void DoGetExtensionMethods(ArrayBuilder methods, string n } } +#nullable enable + + public virtual MethodSymbol? TryGetCorrespondingExtensionImplementationMethod(MethodSymbol method) + { + throw ExceptionUtilities.Unreachable(); + } + +#nullable disable + // TODO: Probably should provide similar accessors for static constructor, destructor, // TODO: operators, conversions. @@ -494,6 +504,10 @@ public override string MetadataName /// internal abstract FileIdentifier? AssociatedFileIdentifier { get; } + /// + /// For extensions, returns the synthesized identifier for the type: "<E>__N". + /// + internal abstract string ExtensionName { get; } #nullable disable /// diff --git a/src/Compilers/CSharp/Portable/Symbols/NamespaceSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/NamespaceSymbol.cs index e64a8c90a12e3..c5825a11647e6 100644 --- a/src/Compilers/CSharp/Portable/Symbols/NamespaceSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/NamespaceSymbol.cs @@ -236,6 +236,8 @@ internal NamedTypeSymbol ImplicitType } } +#nullable enable + /// /// Lookup a nested namespace. /// @@ -246,9 +248,9 @@ internal NamedTypeSymbol ImplicitType /// Symbol for the most nested namespace, if found. Nothing /// if namespace or any part of it can not be found. /// - internal NamespaceSymbol LookupNestedNamespace(ImmutableArray> names) + internal NamespaceSymbol? LookupNestedNamespace(ImmutableArray> names) { - NamespaceSymbol scope = this; + NamespaceSymbol? scope = this; foreach (ReadOnlyMemory name in names) { scope = scope.GetNestedNamespace(name); @@ -259,10 +261,10 @@ internal NamespaceSymbol LookupNestedNamespace(ImmutableArray GetNestedNamespace(name.AsMemory()); - internal virtual NamespaceSymbol GetNestedNamespace(ReadOnlyMemory name) + internal virtual NamespaceSymbol? GetNestedNamespace(ReadOnlyMemory name) { foreach (var sym in this.GetMembers(name)) { @@ -275,6 +277,8 @@ internal virtual NamespaceSymbol GetNestedNamespace(ReadOnlyMemory name) return null; } +#nullable disable + public abstract ImmutableArray GetMembers(ReadOnlyMemory name); public sealed override ImmutableArray GetMembers(string name) @@ -351,6 +355,22 @@ internal virtual void GetExtensionMethods(ArrayBuilder methods, st } } + internal void GetExtensionContainers(ArrayBuilder extensions) + { + foreach (var type in this.GetTypeMembersUnordered()) + { + if (!type.IsReferenceType || !type.IsStatic || type.IsGenericType || !type.MightContainExtensionMethods) continue; + + foreach (var nestedType in type.GetTypeMembersUnordered()) + { + if (nestedType.IsExtension) + { + extensions.Add(nestedType); + } + } + } + } + internal string QualifiedName { get diff --git a/src/Compilers/CSharp/Portable/Symbols/NativeIntegerTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/NativeIntegerTypeSymbol.cs index b805e7b0319fb..a7b187f9a54da 100644 --- a/src/Compilers/CSharp/Portable/Symbols/NativeIntegerTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/NativeIntegerTypeSymbol.cs @@ -184,6 +184,8 @@ internal override UseSiteInfo GetUseSiteInfo() internal sealed override bool IsRecordStruct => false; internal sealed override bool HasPossibleWellKnownCloneMethod() => false; + internal sealed override ParameterSymbol? ExtensionParameter => null; + internal override bool Equals(TypeSymbol? other, TypeCompareKind comparison) { if (other is null) diff --git a/src/Compilers/CSharp/Portable/Symbols/PointerTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PointerTypeSymbol.cs index aaff1d36f2138..11cd05b0834c3 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PointerTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PointerTypeSymbol.cs @@ -106,6 +106,8 @@ public override bool IsValueType } } + internal sealed override ParameterSymbol? ExtensionParameter => null; + internal sealed override ManagedKind GetManagedKind(ref CompoundUseSiteInfo useSiteInfo) => ManagedKind.Unmanaged; public sealed override bool IsRefLikeType diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/EventSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/EventSymbol.cs index 9bf557e085674..957ed5fe60608 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/EventSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/EventSymbol.cs @@ -88,6 +88,12 @@ ImmutableArray IEventSymbol.ExplicitInterfaceImplementations bool IEventSymbol.IsWindowsRuntimeEvent => _underlying.IsWindowsRuntimeEvent; + IEventSymbol? IEventSymbol.PartialDefinitionPart => _underlying.PartialDefinitionPart.GetPublicSymbol(); + + IEventSymbol? IEventSymbol.PartialImplementationPart => _underlying.PartialImplementationPart.GetPublicSymbol(); + + bool IEventSymbol.IsPartialDefinition => _underlying.IsPartialDefinition; + #region ISymbol Members protected override void Accept(SymbolVisitor visitor) diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/TypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/TypeSymbol.cs index 476a5444dc0df..57d245f2ef045 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/TypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/TypeSymbol.cs @@ -26,6 +26,11 @@ protected TypeSymbol(CodeAnalysis.NullableAnnotation nullableAnnotation) ITypeSymbol ITypeSymbol.WithNullableAnnotation(CodeAnalysis.NullableAnnotation nullableAnnotation) { + if (UnderlyingTypeSymbol.IsExtension) + { + throw new System.NotSupportedException(); + } + if (NullableAnnotation == nullableAnnotation) { return this; @@ -144,6 +149,12 @@ TypeKind ITypeSymbol.TypeKind bool ITypeSymbol.IsNativeIntegerType => UnderlyingTypeSymbol.IsNativeIntegerType; +#nullable enable + bool ITypeSymbol.IsExtension => UnderlyingTypeSymbol.IsExtension; + + IParameterSymbol? ITypeSymbol.ExtensionParameter => UnderlyingTypeSymbol.ExtensionParameter?.GetPublicSymbol(); +#nullable disable + string ITypeSymbol.ToDisplayString(CodeAnalysis.NullableFlowState topLevelNullability, SymbolDisplayFormat format) { return SymbolDisplay.ToDisplayString(this, topLevelNullability, format); diff --git a/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingNamedTypeSymbol.cs index 32a375a6e2eed..daf7f50ddcbde 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingNamedTypeSymbol.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using System.Runtime.CompilerServices; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Emit; using Roslyn.Utilities; @@ -38,6 +39,8 @@ internal sealed class RetargetingNamedTypeSymbol : WrappedNamedTypeSymbol private CachedUseSiteInfo _lazyCachedUseSiteInfo = CachedUseSiteInfo.Uninitialized; + private StrongBox _lazyExtensionParameter; + public RetargetingNamedTypeSymbol(RetargetingModuleSymbol retargetingModule, NamedTypeSymbol underlyingType, TupleExtraData tupleData = null) : base(underlyingType, tupleData) { @@ -90,6 +93,40 @@ internal override ImmutableArray TypeArgumentsWithAnnotatio } } + internal sealed override ParameterSymbol ExtensionParameter + { + get + { + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Test this method + + if (_lazyExtensionParameter is null) + { + var extensionParameter = _underlyingType.ExtensionParameter is { } receiverParameter ? new RetargetingExtensionReceiverParameterSymbol(this, receiverParameter) : null; + Interlocked.CompareExchange(ref _lazyExtensionParameter, new StrongBox(extensionParameter), null); + } + + return _lazyExtensionParameter.Value; + } + } + + public override MethodSymbol TryGetCorrespondingExtensionImplementationMethod(MethodSymbol method) + { + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Test this method + + Debug.Assert(this.IsExtension); + Debug.Assert(method.IsDefinition); + Debug.Assert(method.ContainingType == (object)this); + + var underlyingImplementation = _underlyingType.TryGetCorrespondingExtensionImplementationMethod(((RetargetingMethodSymbol)method).UnderlyingMethod); + + if (underlyingImplementation is null) + { + return null; + } + + return RetargetingTranslator.Retarget(underlyingImplementation); + } + public override NamedTypeSymbol ConstructedFrom { get diff --git a/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingParameterSymbol.cs index 36b791724d1b6..a175d4d218c30 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingParameterSymbol.cs @@ -60,13 +60,7 @@ public sealed override ImmutableArray RefCustomModifiers } } - public sealed override Symbol ContainingSymbol - { - get - { - return this.RetargetingModule.RetargetingTranslator.Retarget(_underlyingParameter.ContainingSymbol); - } - } + public abstract override Symbol ContainingSymbol { get; } public sealed override ImmutableArray GetAttributes() { @@ -142,7 +136,27 @@ internal sealed override CSharpCompilation? DeclaringCompilation internal sealed override ImmutableArray InterpolatedStringHandlerArgumentIndexes => _underlyingParameter.InterpolatedStringHandlerArgumentIndexes; - internal override bool HasInterpolatedStringHandlerArgumentError => _underlyingParameter.HasInterpolatedStringHandlerArgumentError; + internal sealed override bool HasInterpolatedStringHandlerArgumentError => _underlyingParameter.HasInterpolatedStringHandlerArgumentError; + + internal sealed override bool IsCallerLineNumber + { + get { return _underlyingParameter.IsCallerLineNumber; } + } + + internal sealed override bool IsCallerFilePath + { + get { return _underlyingParameter.IsCallerFilePath; } + } + + internal sealed override bool IsCallerMemberName + { + get { return _underlyingParameter.IsCallerMemberName; } + } + + internal sealed override int CallerArgumentExpressionParameterIndex + { + get { return _underlyingParameter.CallerArgumentExpressionParameterIndex; } + } } internal sealed class RetargetingMethodParameterSymbol : RetargetingParameterSymbol @@ -164,25 +178,7 @@ protected override RetargetingModuleSymbol RetargetingModule get { return _retargetingMethod.RetargetingModule; } } - internal override bool IsCallerLineNumber - { - get { return _underlyingParameter.IsCallerLineNumber; } - } - - internal override bool IsCallerFilePath - { - get { return _underlyingParameter.IsCallerFilePath; } - } - - internal override bool IsCallerMemberName - { - get { return _underlyingParameter.IsCallerMemberName; } - } - - internal override int CallerArgumentExpressionParameterIndex - { - get { return _underlyingParameter.CallerArgumentExpressionParameterIndex; } - } + public override Symbol ContainingSymbol => _retargetingMethod; } internal sealed class RetargetingPropertyParameterSymbol : RetargetingParameterSymbol @@ -204,24 +200,28 @@ protected override RetargetingModuleSymbol RetargetingModule get { return _retargetingProperty.RetargetingModule; } } - internal override bool IsCallerLineNumber - { - get { return _underlyingParameter.IsCallerLineNumber; } - } + public override Symbol ContainingSymbol => _retargetingProperty; + } - internal override bool IsCallerFilePath - { - get { return _underlyingParameter.IsCallerFilePath; } - } + internal sealed class RetargetingExtensionReceiverParameterSymbol : RetargetingParameterSymbol + { + /// + /// Owning RetargetingNamedTypeSymbol. + /// + private readonly RetargetingNamedTypeSymbol _retargetingType; - internal override bool IsCallerMemberName + public RetargetingExtensionReceiverParameterSymbol(RetargetingNamedTypeSymbol retargetingType, ParameterSymbol underlyingParameter) + : base(underlyingParameter) { - get { return _underlyingParameter.IsCallerMemberName; } + Debug.Assert((object)retargetingType != null); + _retargetingType = retargetingType; } - internal override int CallerArgumentExpressionParameterIndex + protected override RetargetingModuleSymbol RetargetingModule { - get { return _underlyingParameter.CallerArgumentExpressionParameterIndex; } + get { return (RetargetingModuleSymbol)_retargetingType.ContainingModule; } } + + public override Symbol ContainingSymbol => _retargetingType; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/ImplicitNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/ImplicitNamedTypeSymbol.cs index b370e6423052a..c60c6ac95843e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/ImplicitNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/ImplicitNamedTypeSymbol.cs @@ -175,6 +175,8 @@ internal override ObsoleteAttributeData ObsoleteAttributeData internal override bool IsInterpolatedStringHandlerType => false; + internal sealed override ParameterSymbol ExtensionParameter => null; + internal sealed override NamedTypeSymbol AsNativeInteger() => throw ExceptionUtilities.Unreachable(); internal sealed override NamedTypeSymbol NativeIntegerUnderlyingType => null; @@ -192,5 +194,8 @@ internal sealed override bool HasCollectionBuilderAttribute(out TypeSymbol? buil methodName = null; return false; } + + internal override string ExtensionName + => throw ExceptionUtilities.Unreachable(); } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/ModifierUtils.cs b/src/Compilers/CSharp/Portable/Symbols/Source/ModifierUtils.cs index efbe13b19594e..175403675a328 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/ModifierUtils.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/ModifierUtils.cs @@ -20,7 +20,8 @@ internal static DeclarationModifiers MakeAndCheckNonTypeMemberModifiers( DeclarationModifiers allowedModifiers, Location errorLocation, BindingDiagnosticBag diagnostics, - out bool modifierErrors) + out bool modifierErrors, + out bool hasExplicitAccessModifier) { var result = modifiers.ToDeclarationModifiers(isForTypeDeclaration: false, diagnostics.DiagnosticBag ?? new DiagnosticBag(), isOrdinaryMethod: isOrdinaryMethod); result = CheckModifiers(isForTypeDeclaration: false, isForInterfaceMember, result, allowedModifiers, errorLocation, diagnostics, modifiers, out modifierErrors); @@ -29,7 +30,8 @@ internal static DeclarationModifiers MakeAndCheckNonTypeMemberModifiers( if (readonlyToken.Parent is MethodDeclarationSyntax or AccessorDeclarationSyntax or BasePropertyDeclarationSyntax or EventDeclarationSyntax) modifierErrors |= !MessageID.IDS_FeatureReadOnlyMembers.CheckFeatureAvailability(diagnostics, readonlyToken); - if ((result & DeclarationModifiers.AccessibilityMask) == 0) + hasExplicitAccessModifier = (result & DeclarationModifiers.AccessibilityMask) != 0; + if (!hasExplicitAccessModifier) result |= defaultAccess; return result; @@ -223,6 +225,26 @@ internal static void CheckFeatureAvailabilityForStaticAbstractMembersInInterface } } +#nullable enable + internal static void CheckFeatureAvailabilityForPartialEventsAndConstructors(Location location, BindingDiagnosticBag diagnostics) + { + Debug.Assert(location.SourceTree is not null); + + LanguageVersion availableVersion = ((CSharpParseOptions)location.SourceTree.Options).LanguageVersion; + LanguageVersion requiredVersion = MessageID.IDS_FeaturePartialEventsAndConstructors.RequiredVersion(); + if (availableVersion < requiredVersion) + { + ReportUnsupportedModifiersForLanguageVersion( + DeclarationModifiers.Partial, + DeclarationModifiers.Partial, + location, + diagnostics, + availableVersion, + requiredVersion); + } + } +#nullable disable + internal static DeclarationModifiers AdjustModifiersForAnInterfaceMember(DeclarationModifiers mods, bool hasBody, bool isExplicitInterfaceImplementation) { if (isExplicitInterfaceImplementation) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs b/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs index 06f45033425c7..79b0a9bc5c6d2 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs @@ -38,7 +38,7 @@ public static ImmutableArray MakeParameters( addRefReadOnlyModifier, suppressUseSiteDiagnostics: false, lastIndex: syntax.Parameters.Count - 1, - parameterCreationFunc: (Binder context, Symbol owner, TypeWithAnnotations parameterType, + parameterCreationFunc: static (Binder context, Symbol owner, TypeWithAnnotations parameterType, ParameterSyntax syntax, RefKind refKind, int ordinal, SyntaxToken paramsKeyword, SyntaxToken thisKeyword, bool addRefReadOnlyModifier, ScopedKind scope, @@ -60,6 +60,58 @@ public static ImmutableArray MakeParameters( }); } +#nullable enable + public static SourceParameterSymbol? MakeExtensionReceiverParameter( + Binder withTypeParametersBinder, + Symbol owner, + ParameterListSyntax syntax, + BindingDiagnosticBag diagnostics) + { + var parameterCreationFunc = static (Binder context, Symbol owner, TypeWithAnnotations parameterType, + ParameterSyntax syntax, RefKind refKind, int ordinal, + SyntaxToken paramsKeyword, SyntaxToken thisKeyword, bool addRefReadOnlyModifier, + ScopedKind scope, + BindingDiagnosticBag declarationDiagnostics) => + { + Debug.Assert(ordinal == 0); + Debug.Assert(paramsKeyword.Kind() == SyntaxKind.None); + + return SourceParameterSymbol.Create( + context, + owner, + parameterType, + syntax, + refKind, + syntax.Identifier, + ordinal, + hasParamsModifier: false, + isExtensionMethodThis: false, + addRefReadOnlyModifier, + scope, + declarationDiagnostics); + }; + + SyntaxToken arglistToken = default; + int firstDefault = -1; + + return MakeParameter( + withTypeParametersBinder, + owner, + syntax.Parameters[0], + ref arglistToken, + diagnostics, + allowRefOrOut: true, + allowThis: false, + addRefReadOnlyModifier: false, + suppressUseSiteDiagnostics: false, + lastIndex: syntax.Parameters.Count - 1, + parameterCreationFunc: parameterCreationFunc, + parameterIndex: 0, + firstDefault: ref firstDefault, + ParameterContext.ExtensionReceiverParameter); + } +#nullable disable + public static ImmutableArray MakeFunctionPointerParameters( Binder binder, FunctionPointerMethodSymbol owner, @@ -78,7 +130,7 @@ public static ImmutableArray MakeFunctionPointer addRefReadOnlyModifier: true, suppressUseSiteDiagnostics, parametersList.Count - 2, - parameterCreationFunc: (Binder binder, FunctionPointerMethodSymbol owner, TypeWithAnnotations parameterType, + parameterCreationFunc: static (Binder binder, FunctionPointerMethodSymbol owner, TypeWithAnnotations parameterType, FunctionPointerParameterSyntax syntax, RefKind refKind, int ordinal, SyntaxToken paramsKeyword, SyntaxToken thisKeyword, bool addRefReadOnlyModifier, ScopedKind scope, @@ -110,6 +162,7 @@ public static ImmutableArray MakeFunctionPointer parsingFunctionPointer: true); } +#nullable enable private static ImmutableArray MakeParameters( Binder withTypeParametersBinder, TOwningSymbol owner, @@ -134,91 +187,143 @@ private static ImmutableArray MakeParameters.GetInstance(); + var parameterContext = parsingFunctionPointer ? ParameterContext.FunctionPointer : ParameterContext.Default; foreach (var parameterSyntax in parametersList) { if (parameterIndex > lastIndex) break; - CheckParameterModifiers(parameterSyntax, diagnostics, parsingFunctionPointer, parsingLambdaParams: false, parsingAnonymousMethodParams: false); + TParameterSymbol? parameter = MakeParameter(withTypeParametersBinder, owner, parameterSyntax, ref arglistToken, diagnostics, + allowRefOrOut, allowThis, addRefReadOnlyModifier, suppressUseSiteDiagnostics, lastIndex, parameterCreationFunc, + parameterIndex, ref firstDefault, parameterContext); - var refKind = GetModifiers(parameterSyntax.Modifiers, out SyntaxToken refnessKeyword, out SyntaxToken paramsKeyword, out SyntaxToken thisKeyword, out ScopedKind scope); - if (thisKeyword.Kind() != SyntaxKind.None && !allowThis) - { - diagnostics.Add(ErrorCode.ERR_ThisInBadContext, thisKeyword.GetLocation()); - } + if (parameter is null) continue; - if (parameterSyntax is ParameterSyntax concreteParam) - { - if (concreteParam.IsArgList) - { - arglistToken = concreteParam.Identifier; - // The native compiler produces "Expected type" here, in the parser. Roslyn produces - // the somewhat more informative "arglist not valid" error. - if (paramsKeyword.Kind() != SyntaxKind.None - || refnessKeyword.Kind() != SyntaxKind.None - || thisKeyword.Kind() != SyntaxKind.None) - { - // CS1669: __arglist is not valid in this context - diagnostics.Add(ErrorCode.ERR_IllegalVarArgs, arglistToken.GetLocation()); - } + builder.Add(parameter); + ++parameterIndex; + } - if (parameterIndex != lastIndex) - { - // CS0257: An __arglist parameter must be the last parameter in a parameter list - diagnostics.Add(ErrorCode.ERR_VarargsLast, concreteParam.GetLocation()); - } + ImmutableArray parameters = builder.ToImmutableAndFree(); - continue; - } + if (!parsingFunctionPointer) + { + var methodOwner = owner as MethodSymbol; + var typeParameters = (object?)methodOwner != null ? + methodOwner.TypeParameters : + []; + + ImmutableArray parametersForNameConflict = parameters.Cast(); - if (concreteParam.Default != null && firstDefault == -1) + if (owner.GetIsNewExtensionMember()) + { + typeParameters = owner.ContainingType.TypeParameters.Concat(typeParameters); + + if (owner.ContainingType.ExtensionParameter is { Name: not "" } receiver) { - firstDefault = parameterIndex; + parametersForNameConflict = parametersForNameConflict.Insert(0, receiver); } } - Debug.Assert(parameterSyntax.Type != null); - var parameterType = withTypeParametersBinder.BindType(parameterSyntax.Type, diagnostics, suppressUseSiteDiagnostics: suppressUseSiteDiagnostics); + Debug.Assert(methodOwner?.MethodKind != MethodKind.LambdaMethod); + bool allowShadowingNames = withTypeParametersBinder.Compilation.IsFeatureEnabled(MessageID.IDS_FeatureNameShadowingInNestedFunctions) && + methodOwner?.MethodKind == MethodKind.LocalFunction; - if (!allowRefOrOut && (refKind == RefKind.Ref || refKind == RefKind.Out)) - { - Debug.Assert(refnessKeyword.Kind() != SyntaxKind.None); + withTypeParametersBinder.ValidateParameterNameConflicts(typeParameters, parametersForNameConflict, allowShadowingNames, diagnostics); + } - // error CS0631: ref and out are not valid in this context - diagnostics.Add(ErrorCode.ERR_IllegalRefParam, refnessKeyword.GetLocation()); - } + return parameters; + } + + internal enum ParameterContext + { + Default, + FunctionPointer, + Lambda, + AnonymousMethod, + ExtensionReceiverParameter + } - TParameterSymbol parameter = parameterCreationFunc(withTypeParametersBinder, owner, parameterType, parameterSyntax, refKind, parameterIndex, paramsKeyword, thisKeyword, addRefReadOnlyModifier, scope, diagnostics); + private static TParameterSymbol? MakeParameter( + Binder withTypeParametersBinder, + TOwningSymbol owner, + TParameterSyntax parameterSyntax, + ref SyntaxToken arglistToken, + BindingDiagnosticBag diagnostics, + bool allowRefOrOut, + bool allowThis, + bool addRefReadOnlyModifier, + bool suppressUseSiteDiagnostics, + int lastIndex, + Func parameterCreationFunc, + int parameterIndex, + ref int firstDefault, + ParameterContext parameterContext) + where TParameterSyntax : BaseParameterSyntax + where TParameterSymbol : ParameterSymbol + where TOwningSymbol : Symbol + { + Debug.Assert(parameterContext is ParameterContext.Default or ParameterContext.FunctionPointer or ParameterContext.ExtensionReceiverParameter); + CheckParameterModifiers(parameterSyntax, diagnostics, parameterContext); - Debug.Assert(parameter is SourceComplexParameterSymbolBase || !parameter.IsParams); // Only SourceComplexParameterSymbolBase validates 'params' type. - Debug.Assert(parameter is SourceComplexParameterSymbolBase || parameter is not SourceParameterSymbol s || s.DeclaredScope == ScopedKind.None); // Only SourceComplexParameterSymbolBase validates 'scope'. - ReportParameterErrors(owner, parameterSyntax, parameter.Ordinal, lastParameterIndex: lastIndex, parameter.IsParams, parameter.TypeWithAnnotations, - parameter.RefKind, parameter.ContainingSymbol, thisKeyword, paramsKeyword, firstDefault, diagnostics); + bool inExtension = parameterContext is ParameterContext.ExtensionReceiverParameter; + var refKind = GetModifiers(parameterSyntax.Modifiers, ignoreParams: inExtension, out SyntaxToken refnessKeyword, out SyntaxToken paramsKeyword, out SyntaxToken thisKeyword, out ScopedKind scope); - builder.Add(parameter); - ++parameterIndex; + if (thisKeyword.Kind() != SyntaxKind.None && !allowThis) + { + diagnostics.Add(ErrorCode.ERR_ThisInBadContext, thisKeyword.GetLocation()); } - ImmutableArray parameters = builder.ToImmutableAndFree(); - - if (!parsingFunctionPointer) + if (parameterSyntax is ParameterSyntax concreteParam) { - var methodOwner = owner as MethodSymbol; - var typeParameters = (object)methodOwner != null ? - methodOwner.TypeParameters : - default(ImmutableArray); + if (concreteParam.IsArgList) + { + arglistToken = concreteParam.Identifier; + // The native compiler produces "Expected type" here, in the parser. Roslyn produces + // the somewhat more informative "arglist not valid" error. + if (paramsKeyword.Kind() != SyntaxKind.None + || refnessKeyword.Kind() != SyntaxKind.None + || thisKeyword.Kind() != SyntaxKind.None + || inExtension) + { + // CS1669: __arglist is not valid in this context + diagnostics.Add(ErrorCode.ERR_IllegalVarArgs, arglistToken.GetLocation()); + } - Debug.Assert(methodOwner?.MethodKind != MethodKind.LambdaMethod); - bool allowShadowingNames = withTypeParametersBinder.Compilation.IsFeatureEnabled(MessageID.IDS_FeatureNameShadowingInNestedFunctions) && - methodOwner?.MethodKind == MethodKind.LocalFunction; + if (parameterIndex != lastIndex && !inExtension) + { + // CS0257: An __arglist parameter must be the last parameter in a parameter list + diagnostics.Add(ErrorCode.ERR_VarargsLast, concreteParam.GetLocation()); + } + + return null; + } - withTypeParametersBinder.ValidateParameterNameConflicts(typeParameters, parameters.Cast(), allowShadowingNames, diagnostics); + if (concreteParam.Default != null && firstDefault == -1) + { + firstDefault = parameterIndex; + } } - return parameters; + Debug.Assert(parameterSyntax.Type != null); + var parameterType = withTypeParametersBinder.BindType(parameterSyntax.Type, diagnostics, suppressUseSiteDiagnostics: suppressUseSiteDiagnostics); + + if (!allowRefOrOut && (refKind == RefKind.Ref || refKind == RefKind.Out)) + { + Debug.Assert(refnessKeyword.Kind() != SyntaxKind.None); + + // error CS0631: ref and out are not valid in this context + diagnostics.Add(ErrorCode.ERR_IllegalRefParam, refnessKeyword.GetLocation()); + } + + TParameterSymbol parameter = parameterCreationFunc(withTypeParametersBinder, owner, parameterType, parameterSyntax, refKind, parameterIndex, paramsKeyword, thisKeyword, addRefReadOnlyModifier, scope, diagnostics); + + Debug.Assert(parameter is SourceComplexParameterSymbolBase || !parameter.IsParams); // Only SourceComplexParameterSymbolBase validates 'params' type. + Debug.Assert(parameter is SourceComplexParameterSymbolBase || parameter is not SourceParameterSymbol s || s.DeclaredScope == ScopedKind.None); // Only SourceComplexParameterSymbolBase validates 'scope'. + ReportParameterErrors(owner, parameterSyntax, parameter.Ordinal, lastParameterIndex: lastIndex, isParams: parameter.IsParams, typeWithAnnotations: parameter.TypeWithAnnotations, + refKind: parameter.RefKind, containingSymbol: parameter.ContainingSymbol, thisKeyword: thisKeyword, paramsKeyword: paramsKeyword, firstDefault: firstDefault, diagnostics: diagnostics); + return parameter; } -#nullable enable internal static void EnsureRefKindAttributesExist(PEModuleBuilder moduleBuilder, ImmutableArray parameters) { EnsureRefKindAttributesExist(moduleBuilder.Compilation, parameters, diagnostics: null, modifyCompilation: false, moduleBuilder); @@ -419,12 +524,8 @@ private static void EnsureNullableAttributeExists(CSharpCompilation compilation, internal static void CheckParameterModifiers( BaseParameterSyntax parameter, BindingDiagnosticBag diagnostics, - bool parsingFunctionPointerParams, - bool parsingLambdaParams, - bool parsingAnonymousMethodParams) + ParameterContext parameterContext) { - Debug.Assert(!parsingLambdaParams || !parsingAnonymousMethodParams); - var seenThis = false; var seenRef = false; var seenOut = false; @@ -446,7 +547,8 @@ internal static void CheckParameterModifiers( Binder.CheckFeatureAvailability(modifier, MessageID.IDS_FeatureRefExtensionMethods, diagnostics); } - if (parsingLambdaParams || parsingAnonymousMethodParams) + // `this` on extension parameters was already reported elsewhere + if (parameterContext is ParameterContext.Lambda or ParameterContext.AnonymousMethod) { diagnostics.Add(ErrorCode.ERR_ThisInBadContext, modifier.GetLocation()); } @@ -505,6 +607,10 @@ internal static void CheckParameterModifiers( { addERR_BadParameterModifiers(diagnostics, modifier, SyntaxKind.ThisKeyword); } + else if (parameterContext is ParameterContext.ExtensionReceiverParameter) + { + addERR_BadParameterModifiers(diagnostics, modifier, SyntaxKind.ExtensionKeyword); + } else if (seenParams) { addERR_ParamsCantBeWithModifier(diagnostics, modifier, SyntaxKind.OutKeyword); @@ -523,8 +629,8 @@ internal static void CheckParameterModifiers( } break; - case SyntaxKind.ParamsKeyword when !parsingFunctionPointerParams: - if (parsingAnonymousMethodParams) + case SyntaxKind.ParamsKeyword when parameterContext is not ParameterContext.FunctionPointer: + if (parameterContext is ParameterContext.AnonymousMethod or ParameterContext.ExtensionReceiverParameter) { diagnostics.Add(ErrorCode.ERR_IllegalParams, modifier.GetLocation()); } @@ -553,7 +659,7 @@ internal static void CheckParameterModifiers( seenParams = true; } - if (parsingLambdaParams) + if (parameterContext is ParameterContext.Lambda) { MessageID.IDS_FeatureLambdaParamsArray.CheckFeatureAvailability(diagnostics, modifier); @@ -594,7 +700,7 @@ internal static void CheckParameterModifiers( } break; - case SyntaxKind.ScopedKeyword when !parsingFunctionPointerParams: + case SyntaxKind.ScopedKeyword when parameterContext is not ParameterContext.FunctionPointer: ModifierUtils.CheckScopedModifierAvailability(parameter, modifier, diagnostics); Debug.Assert(!seenIn); Debug.Assert(!seenOut); @@ -620,8 +726,8 @@ internal static void CheckParameterModifiers( } break; - case SyntaxKind.ParamsKeyword when parsingFunctionPointerParams: - case SyntaxKind.ScopedKeyword when parsingFunctionPointerParams: + case SyntaxKind.ParamsKeyword when parameterContext is ParameterContext.FunctionPointer: + case SyntaxKind.ScopedKeyword when parameterContext is ParameterContext.FunctionPointer: diagnostics.Add(ErrorCode.ERR_BadFuncPointerParamModifier, modifier.GetLocation(), SyntaxFacts.GetText(modifier.Kind())); break; @@ -682,12 +788,21 @@ public static void ReportParameterErrors( } else if (!typeWithAnnotations.IsDefault && typeWithAnnotations.IsStatic) { - Debug.Assert(containingSymbol is null || (containingSymbol is FunctionPointerMethodSymbol or { ContainingType: not null })); - // error CS0721: '{0}': static types cannot be used as parameters - diagnostics.Add( - ErrorFacts.GetStaticClassParameterCode(containingSymbol?.ContainingType?.IsInterfaceType() ?? false), - syntax.Type?.Location ?? syntax.GetLocation(), - typeWithAnnotations.Type); + bool inExtension = owner is SynthesizedExtensionMarker; + bool isNamed = syntax is ParameterSyntax parameterSyntax && parameterSyntax.Identifier.Kind() != SyntaxKind.None; + + Debug.Assert(containingSymbol is null + || (containingSymbol is FunctionPointerMethodSymbol or { ContainingType: not null }) + || inExtension); + + if (!inExtension || isNamed) + { + // error CS0721: '{0}': static types cannot be used as parameters + diagnostics.Add( + ErrorFacts.GetStaticClassParameterCode(containingSymbol?.ContainingType?.IsInterfaceType() ?? false), + syntax.Type?.Location ?? syntax.GetLocation(), + typeWithAnnotations.Type); + } } else if (firstDefault != -1 && parameterIndex > firstDefault && !isDefault && !isParams) { @@ -740,12 +855,19 @@ internal static bool ReportDefaultParameterErrors( // stick it in the parameter because we want to be able to analyze it for // IntelliSense purposes. + bool inExtension = parameter.ContainingSymbol is SynthesizedExtensionMarker; + if (inExtension) + { + diagnostics.Add(ErrorCode.ERR_ExtensionParameterDisallowsDefaultValue, parameterSyntax.GetLocation()); + return true; + } + TypeSymbol parameterType = parameter.Type; CompoundUseSiteInfo useSiteInfo = binder.GetNewCompoundUseSiteInfo(diagnostics); Conversion conversion = binder.Conversions.ClassifyImplicitConversionFromExpression(defaultExpression, parameterType, ref useSiteInfo); diagnostics.Add(defaultExpression.Syntax, useSiteInfo); - var refKind = GetModifiers(parameterSyntax.Modifiers, out SyntaxToken refnessKeyword, out SyntaxToken paramsKeyword, out SyntaxToken thisKeyword, out _); + var refKind = GetModifiers(parameterSyntax.Modifiers, ignoreParams: inExtension, out SyntaxToken refnessKeyword, out SyntaxToken paramsKeyword, out SyntaxToken thisKeyword, out _); // CONSIDER: We are inconsistent here regarding where the error is reported; is it // CONSIDER: reported on the parameter name, or on the value of the initializer? @@ -926,7 +1048,7 @@ internal static MethodSymbol FindContainingGenericMethod(Symbol symbol) return null; } - internal static RefKind GetModifiers(SyntaxTokenList modifiers, out SyntaxToken refnessKeyword, out SyntaxToken paramsKeyword, out SyntaxToken thisKeyword, out ScopedKind scope) + internal static RefKind GetModifiers(SyntaxTokenList modifiers, bool ignoreParams, out SyntaxToken refnessKeyword, out SyntaxToken paramsKeyword, out SyntaxToken thisKeyword, out ScopedKind scope) { var refKind = RefKind.None; bool isScoped = false; @@ -961,7 +1083,10 @@ internal static RefKind GetModifiers(SyntaxTokenList modifiers, out SyntaxToken } break; case SyntaxKind.ParamsKeyword: - paramsKeyword = modifier; + if (!ignoreParams) + { + paramsKeyword = modifier; + } break; case SyntaxKind.ThisKeyword: thisKeyword = modifier; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/QuickAttributeChecker.cs b/src/Compilers/CSharp/Portable/Symbols/Source/QuickAttributeChecker.cs index 96aeb91c91d15..de44539ca6d5e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/QuickAttributeChecker.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/QuickAttributeChecker.cs @@ -48,6 +48,7 @@ private static QuickAttributeChecker CreatePredefinedQuickAttributeChecker() var result = new QuickAttributeChecker(); result.AddName(AttributeDescription.TypeIdentifierAttribute.Name, QuickAttributes.TypeIdentifier); result.AddName(AttributeDescription.TypeForwardedToAttribute.Name, QuickAttributes.TypeForwardedTo); + result.AddName(AttributeDescription.IndexerNameAttribute.Name, QuickAttributes.IndexerName); result.AddName(AttributeDescription.AssemblyKeyNameAttribute.Name, QuickAttributes.AssemblyKeyName); result.AddName(AttributeDescription.AssemblyKeyFileAttribute.Name, QuickAttributes.AssemblyKeyFile); result.AddName(AttributeDescription.AssemblySignatureKeyAttribute.Name, QuickAttributes.AssemblySignatureKey); @@ -144,9 +145,10 @@ internal enum QuickAttributes : byte None = 0, TypeIdentifier = 1 << 0, TypeForwardedTo = 1 << 1, - AssemblyKeyName = 1 << 2, - AssemblyKeyFile = 1 << 3, - AssemblySignatureKey = 1 << 4, + IndexerName = 1 << 2, + AssemblyKeyName = 1 << 3, + AssemblyKeyFile = 1 << 4, + AssemblySignatureKey = 1 << 5, Last = AssemblySignatureKey, } @@ -171,6 +173,10 @@ public static QuickAttributes GetQuickAttributes(string name, bool inAttribute) { result |= QuickAttributes.TypeForwardedTo; } + else if (matches(AttributeDescription.IndexerNameAttribute)) + { + result |= QuickAttributes.IndexerName; + } else if (matches(AttributeDescription.AssemblyKeyNameAttribute)) { result |= QuickAttributes.AssemblyKeyName; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs index b6c467e7338a2..90d064f042a7f 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs @@ -1666,7 +1666,7 @@ internal CommonAssemblyWellKnownAttributeData GetSourceDecodedWellKnownAttribute } attributesBag = null; - Func attributeMatches = attribute switch + Func attributeMatches = attribute switch { QuickAttributes.AssemblySignatureKey => isPossibleAssemblySignatureKeyAttribute, QuickAttributes.AssemblyKeyName => isPossibleAssemblyKeyNameAttribute, @@ -1678,19 +1678,19 @@ internal CommonAssemblyWellKnownAttributeData GetSourceDecodedWellKnownAttribute return (CommonAssemblyWellKnownAttributeData?)attributesBag?.DecodedWellKnownAttributeData; - bool isPossibleAssemblySignatureKeyAttribute(AttributeSyntax node) + bool isPossibleAssemblySignatureKeyAttribute(AttributeSyntax node, Binder? rootBinderOpt) { QuickAttributeChecker checker = this.DeclaringCompilation.GetBinderFactory(node.SyntaxTree).GetBinder(node).QuickAttributeChecker; return checker.IsPossibleMatch(node, QuickAttributes.AssemblySignatureKey); } - bool isPossibleAssemblyKeyNameAttribute(AttributeSyntax node) + bool isPossibleAssemblyKeyNameAttribute(AttributeSyntax node, Binder? rootBinderOpt) { QuickAttributeChecker checker = this.DeclaringCompilation.GetBinderFactory(node.SyntaxTree).GetBinder(node).QuickAttributeChecker; return checker.IsPossibleMatch(node, QuickAttributes.AssemblyKeyName); } - bool isPossibleAssemblyKeyFileAttribute(AttributeSyntax node) + bool isPossibleAssemblyKeyFileAttribute(AttributeSyntax node, Binder? rootBinderOpt) { QuickAttributeChecker checker = this.DeclaringCompilation.GetBinderFactory(node.SyntaxTree).GetBinder(node).QuickAttributeChecker; return checker.IsPossibleMatch(node, QuickAttributes.AssemblyKeyFile); @@ -1756,7 +1756,7 @@ private static void AfterPossibleForwardedTypesAttributePartBound(AttributeSynta Debug.Assert(removed); } - private bool IsPossibleForwardedTypesAttribute(AttributeSyntax node) + private bool IsPossibleForwardedTypesAttribute(AttributeSyntax node, Binder rootBinderOpt) { QuickAttributeChecker checker = this.DeclaringCompilation.GetBinderFactory(node.SyntaxTree).GetBinder(node).QuickAttributeChecker; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs index cb35f330c2699..6bbab27a68ff2 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs @@ -471,12 +471,7 @@ protected SourceParameterSymbol? PartialImplementationPart { get { - ImmutableArray implParameters = this.ContainingSymbol switch - { - SourceMemberMethodSymbol { PartialImplementationPart.Parameters: { } parameters } => parameters, - SourcePropertySymbol { PartialImplementationPart.Parameters: { } parameters } => parameters, - _ => default - }; + ImmutableArray implParameters = this.ContainingSymbol.GetPartialImplementationPart()?.GetParameters() ?? default; if (implParameters.IsDefault) { @@ -492,12 +487,7 @@ protected SourceParameterSymbol? PartialDefinitionPart { get { - ImmutableArray defParameters = this.ContainingSymbol switch - { - SourceMemberMethodSymbol { PartialDefinitionPart.Parameters: { } parameters } => parameters, - SourcePropertySymbol { PartialDefinitionPart.Parameters: { } parameters } => parameters, - _ => default - }; + ImmutableArray defParameters = this.ContainingSymbol.GetPartialDefinitionPart()?.GetParameters() ?? default; if (defParameters.IsDefault) { @@ -1598,9 +1588,8 @@ void validateParamsType(BindingDiagnosticBag diagnostics) Debug.Assert(!addMethods.IsDefaultOrEmpty); - if (addMethods[0].IsStatic) // No need to check other methods, extensions are never mixed with instance methods + if (addMethods[0].IsExtensionMethod || addMethods[0].GetIsNewExtensionMember()) // No need to check other methods, extensions are never mixed with instance methods { - Debug.Assert(addMethods[0].IsExtensionMethod); diagnostics.Add(ErrorCode.ERR_ParamsCollectionExtensionAddMethod, syntax, Type); return; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbol.cs index 512755dd22f60..a570212d8250e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbol.cs @@ -2,9 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - +using System; using System.Diagnostics; +using System.Linq; +using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; using Roslyn.Utilities; @@ -12,6 +13,9 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols { internal sealed class SourceConstructorSymbol : SourceConstructorSymbolBase { + private SourceConstructorSymbol? _otherPartOfPartial; + +#nullable disable public static SourceConstructorSymbol CreateConstructorSymbol( SourceMemberContainerTypeSymbol containingType, ConstructorDeclarationSyntax syntax, @@ -61,6 +65,11 @@ private SourceConstructorSymbol( } } + if (IsPartialDefinition && syntax.Initializer is { } initializer) + { + diagnostics.Add(ErrorCode.ERR_PartialConstructorInitializer, initializer, this); + } + if (methodKind == MethodKind.StaticConstructor) { CheckFeatureAvailabilityAndRuntimeSupport(syntax, location, hasAnyBody, diagnostics); @@ -88,12 +97,13 @@ private static (DeclarationModifiers, Flags) MakeModifiersAndFlags( out bool modifierErrors, out bool report_ERR_StaticConstructorWithAccessModifiers) { - DeclarationModifiers declarationModifiers = MakeModifiers(containingType, syntax, methodKind, syntax.HasAnyBody(), location, diagnostics, out modifierErrors, out report_ERR_StaticConstructorWithAccessModifiers); - Flags flags = MakeFlags( - methodKind, RefKind.None, declarationModifiers, returnsVoid: true, returnsVoidIsSet: true, - isExpressionBodied: syntax.IsExpressionBodied(), isExtensionMethod: false, isVarArg: syntax.IsVarArg(), + bool hasAnyBody = syntax.HasAnyBody(); + DeclarationModifiers declarationModifiers = MakeModifiers(containingType, syntax, methodKind, hasAnyBody, location, diagnostics, out modifierErrors, out bool hasExplicitAccessModifier, out report_ERR_StaticConstructorWithAccessModifiers); + Flags flags = new Flags( + methodKind, RefKind.None, declarationModifiers, returnsVoid: true, returnsVoidIsSet: true, hasAnyBody: hasAnyBody, + isExpressionBodied: syntax.IsExpressionBodied(), isExtensionMethod: false, isVararg: syntax.IsVarArg(), isNullableAnalysisEnabled: isNullableAnalysisEnabled, isExplicitInterfaceImplementation: false, - hasThisInitializer: hasThisInitializer); + hasThisInitializer: hasThisInitializer, hasExplicitAccessModifier: hasExplicitAccessModifier); return (declarationModifiers, flags); } @@ -121,19 +131,24 @@ protected override CSharpSyntaxNode GetInitializer() private static DeclarationModifiers MakeModifiers( NamedTypeSymbol containingType, ConstructorDeclarationSyntax syntax, MethodKind methodKind, bool hasBody, Location location, BindingDiagnosticBag diagnostics, - out bool modifierErrors, out bool report_ERR_StaticConstructorWithAccessModifiers) + out bool modifierErrors, out bool hasExplicitAccessModifier, out bool report_ERR_StaticConstructorWithAccessModifiers) { var defaultAccess = (methodKind == MethodKind.StaticConstructor) ? DeclarationModifiers.None : DeclarationModifiers.Private; // Check that the set of modifiers is allowed - const DeclarationModifiers allowedModifiers = + DeclarationModifiers allowedModifiers = DeclarationModifiers.AccessibilityMask | DeclarationModifiers.Static | DeclarationModifiers.Extern | DeclarationModifiers.Unsafe; + if (methodKind == MethodKind.Constructor) + { + allowedModifiers |= DeclarationModifiers.Partial; + } + bool isInterface = containingType.IsInterface; - var mods = ModifierUtils.MakeAndCheckNonTypeMemberModifiers(isOrdinaryMethod: false, isForInterfaceMember: isInterface, syntax.Modifiers, defaultAccess, allowedModifiers, location, diagnostics, out modifierErrors); + var mods = ModifierUtils.MakeAndCheckNonTypeMemberModifiers(isOrdinaryMethod: false, isForInterfaceMember: isInterface, syntax.Modifiers, defaultAccess, allowedModifiers, location, diagnostics, out modifierErrors, out hasExplicitAccessModifier); report_ERR_StaticConstructorWithAccessModifiers = false; if (methodKind == MethodKind.StaticConstructor) @@ -164,7 +179,7 @@ private static DeclarationModifiers MakeModifiers( private void CheckModifiers(MethodKind methodKind, bool hasBody, Location location, BindingDiagnosticBag diagnostics) { - if (!hasBody && !IsExtern) + if (!hasBody && !IsExtern && !IsPartial) { diagnostics.Add(ErrorCode.ERR_ConcreteMissingBody, location, this); } @@ -176,13 +191,45 @@ private void CheckModifiers(MethodKind methodKind, bool hasBody, Location locati { diagnostics.Add(ErrorCode.ERR_ConstructorInStaticClass, location); } + else if (IsPartial && !ContainingType.IsPartial()) + { + diagnostics.Add(ErrorCode.ERR_PartialMemberOnlyInPartialClass, location); + } } +#nullable enable internal override OneOrMany> GetAttributeDeclarations() { - return OneOrMany.Create(((ConstructorDeclarationSyntax)this.SyntaxNode).AttributeLists); + // Attributes on partial constructors are owned by the definition part. + // If this symbol has a non-null PartialDefinitionPart, we should have accessed this method through that definition symbol instead. + Debug.Assert(PartialDefinitionPart is null); + + if (SourcePartialImplementationPart is { } implementationPart) + { + return OneOrMany.Create( + this.AttributeDeclarationSyntaxList, + implementationPart.AttributeDeclarationSyntaxList); + } + + return OneOrMany.Create(this.AttributeDeclarationSyntaxList); } + private SyntaxList AttributeDeclarationSyntaxList + { + get + { + if (this.ContainingType is SourceMemberContainerTypeSymbol { AnyMemberHasAttributes: true }) + { + return this.GetSyntax().AttributeLists; + } + + return default; + } + } + + protected override SourceMemberMethodSymbol? BoundAttributesSource => SourcePartialDefinitionPart; +#nullable disable + internal override bool IsNullableAnalysisEnabled() => flags.HasThisInitializer ? flags.IsNullableAnalysisEnabled @@ -213,5 +260,103 @@ protected override bool IsWithinExpressionOrBlockBody(int position, out int offs offset = -1; return false; } + +#nullable enable + internal sealed override void ForceComplete(SourceLocation? locationOpt, Predicate? filter, CancellationToken cancellationToken) + { + SourcePartialImplementationPart?.ForceComplete(locationOpt, filter, cancellationToken); + base.ForceComplete(locationOpt, filter, cancellationToken); + } + + protected override void PartialConstructorChecks(BindingDiagnosticBag diagnostics) + { + if (SourcePartialImplementationPart is { } implementation) + { + PartialConstructorChecks(implementation, diagnostics); + } + } + + private void PartialConstructorChecks(SourceConstructorSymbol implementation, BindingDiagnosticBag diagnostics) + { + Debug.Assert(this.IsPartialDefinition); + Debug.Assert(!ReferenceEquals(this, implementation)); + Debug.Assert(ReferenceEquals(this.OtherPartOfPartial, implementation)); + + if (MemberSignatureComparer.ConsideringTupleNamesCreatesDifference(this, implementation)) + { + diagnostics.Add(ErrorCode.ERR_PartialMemberInconsistentTupleNames, implementation.GetFirstLocation(), this, implementation); + } + else if (!MemberSignatureComparer.PartialMethodsStrictComparer.Equals(this, implementation) + || !Parameters.SequenceEqual(implementation.Parameters, static (a, b) => a.Name == b.Name)) + { + diagnostics.Add(ErrorCode.WRN_PartialMemberSignatureDifference, implementation.GetFirstLocation(), + new FormattedSymbol(this, SymbolDisplayFormat.MinimallyQualifiedFormat), + new FormattedSymbol(implementation, SymbolDisplayFormat.MinimallyQualifiedFormat)); + } + + if (IsUnsafe != implementation.IsUnsafe && this.CompilationAllowsUnsafe()) + { + diagnostics.Add(ErrorCode.ERR_PartialMemberUnsafeDifference, implementation.GetFirstLocation()); + } + + if (this.IsParams() != implementation.IsParams()) + { + diagnostics.Add(ErrorCode.ERR_PartialMemberParamsDifference, implementation.GetFirstLocation()); + } + + if (DeclaredAccessibility != implementation.DeclaredAccessibility + || HasExplicitAccessModifier != implementation.HasExplicitAccessModifier) + { + diagnostics.Add(ErrorCode.ERR_PartialMemberAccessibilityDifference, implementation.GetFirstLocation()); + } + + Debug.Assert(this.ParameterCount == implementation.ParameterCount); + for (var i = 0; i < this.ParameterCount; i++) + { + // An error is only reported for a modifier difference here, regardless of whether the difference is safe or not. + // Presence of UnscopedRefAttribute is also not considered when checking partial signatures, because when the attribute is used, it will affect both parts the same way. + var definitionParameter = (SourceParameterSymbol)this.Parameters[i]; + var implementationParameter = (SourceParameterSymbol)implementation.Parameters[i]; + if (definitionParameter.DeclaredScope != implementationParameter.DeclaredScope) + { + diagnostics.Add(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, implementation.GetFirstLocation(), new FormattedSymbol(implementation.Parameters[i], SymbolDisplayFormat.ShortFormat)); + } + } + } + + public sealed override bool IsExtern => PartialImplementationPart is { } implementation ? implementation.IsExtern : HasExternModifier; + + private bool HasAnyBody => flags.HasAnyBody; + + private bool HasExplicitAccessModifier => flags.HasExplicitAccessModifier; + + internal bool IsPartialDefinition => IsPartial && !HasAnyBody && !HasExternModifier; + + internal bool IsPartialImplementation => IsPartial && (HasAnyBody || HasExternModifier); + + internal SourceConstructorSymbol? OtherPartOfPartial => _otherPartOfPartial; + + internal SourceConstructorSymbol? SourcePartialDefinitionPart => IsPartialImplementation ? OtherPartOfPartial : null; + + internal SourceConstructorSymbol? SourcePartialImplementationPart => IsPartialDefinition ? OtherPartOfPartial : null; + + public sealed override MethodSymbol? PartialDefinitionPart => SourcePartialDefinitionPart; + + public sealed override MethodSymbol? PartialImplementationPart => SourcePartialImplementationPart; + + internal static void InitializePartialConstructorParts(SourceConstructorSymbol definition, SourceConstructorSymbol implementation) + { + Debug.Assert(definition.IsPartialDefinition); + Debug.Assert(implementation.IsPartialImplementation); + + Debug.Assert(definition._otherPartOfPartial is not { } alreadySetImplPart || ReferenceEquals(alreadySetImplPart, implementation)); + Debug.Assert(implementation._otherPartOfPartial is not { } alreadySetDefPart || ReferenceEquals(alreadySetDefPart, definition)); + + definition._otherPartOfPartial = implementation; + implementation._otherPartOfPartial = definition; + + Debug.Assert(ReferenceEquals(definition._otherPartOfPartial, implementation)); + Debug.Assert(ReferenceEquals(implementation._otherPartOfPartial, definition)); + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs index 246b307c70ef8..8b2f328bc6ae7 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs @@ -97,6 +97,13 @@ internal sealed override void AfterAddingTypeMembersChecks(ConversionsBase conve { parameter.Type.CheckAllConstraints(compilation, conversions, parameter.GetFirstLocation(), diagnostics); } + + PartialConstructorChecks(diagnostics); + } + + protected virtual void PartialConstructorChecks(BindingDiagnosticBag diagnostics) + { + Debug.Assert(!IsPartial); } public sealed override bool IsImplicitlyDeclared @@ -259,11 +266,5 @@ internal override (CSharpAttributeData?, BoundAttribute?) EarlyDecodeWellKnownAt return base.EarlyDecodeWellKnownAttribute(ref arguments); } - - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) - { - base.AddSynthesizedAttributes(moduleBuilder, ref attributes); - AddRequiredMembersMarkerAttributes(ref attributes, this); - } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceCustomEventAccessorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceCustomEventAccessorSymbol.cs index 7ffd478df9134..8ffcd5b794056 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceCustomEventAccessorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceCustomEventAccessorSymbol.cs @@ -77,9 +77,32 @@ public override Accessibility DeclaredAccessibility } } +#nullable enable + protected override SourceMemberMethodSymbol? BoundAttributesSource => (SourceMemberMethodSymbol?)PartialDefinitionPart; + internal override OneOrMany> GetAttributeDeclarations() { - return OneOrMany.Create(GetSyntax().AttributeLists); + Debug.Assert(PartialImplementationPart is null); + + // If this is a partial event, the corresponding partial definition cannot have any accessor attributes + // (there are no explicit accessors in source on the definition part - it has a field-like syntax). + Debug.Assert(PartialDefinitionPart is null + or SourceEventAccessorSymbol { AssociatedEvent.MemberSyntax: EventFieldDeclarationSyntax }); + + return OneOrMany.Create(this.AttributeDeclarationSyntaxList); + } + + internal SyntaxList AttributeDeclarationSyntaxList + { + get + { + if (this.AssociatedEvent.containingType.AnyMemberHasAttributes) + { + return this.GetSyntax().AttributeLists; + } + + return default; + } } public override bool IsImplicitlyDeclared diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceCustomEventSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceCustomEventSymbol.cs index cc0b0475d0b68..b5faa9b49e15d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceCustomEventSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceCustomEventSymbol.cs @@ -170,6 +170,8 @@ internal SourceCustomEventSymbol(SourceMemberContainerTypeSymbol containingType, ImmutableArray.Create(explicitlyImplementedEvent); } + protected override bool AccessorsHaveImplementation => true; + public override TypeWithAnnotations TypeWithAnnotations { get { return _type; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceDestructorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceDestructorSymbol.cs index 5e6846f3883b4..1252f9f3d5e83 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceDestructorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceDestructorSymbol.cs @@ -28,7 +28,7 @@ internal SourceDestructorSymbol( bool hasBlockBody = syntax.Body != null; bool isExpressionBodied = IsExpressionBodied; - if (syntax.Identifier.ValueText != containingType.Name) + if (syntax.Identifier.ValueText != containingType.Name && !containingType.IsExtension) { diagnostics.Add(ErrorCode.ERR_BadDestructorName, syntax.Identifier.GetLocation()); } @@ -130,7 +130,7 @@ private static DeclarationModifiers MakeModifiers(NamedTypeSymbol containingType { // Check that the set of modifiers is allowed const DeclarationModifiers allowedModifiers = DeclarationModifiers.Extern | DeclarationModifiers.Unsafe; - var mods = ModifierUtils.MakeAndCheckNonTypeMemberModifiers(isOrdinaryMethod: false, isForInterfaceMember: containingType.IsInterface, modifiers, DeclarationModifiers.None, allowedModifiers, location, diagnostics, out modifierErrors); + var mods = ModifierUtils.MakeAndCheckNonTypeMemberModifiers(isOrdinaryMethod: false, isForInterfaceMember: containingType.IsInterface, modifiers, DeclarationModifiers.None, allowedModifiers, location, diagnostics, out modifierErrors, out _); mods = (mods & ~DeclarationModifiers.AccessibilityMask) | DeclarationModifiers.Protected; // we mark destructors protected in the symbol table diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventAccessorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventAccessorSymbol.cs index 7a3aa3b89b479..8cc0635837f60 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventAccessorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventAccessorSymbol.cs @@ -233,5 +233,22 @@ internal sealed override int TryGetOverloadResolutionPriority() { return 0; } + +#nullable enable + protected abstract override SourceMemberMethodSymbol? BoundAttributesSource { get; } + + public sealed override MethodSymbol? PartialImplementationPart => _event is { IsPartialDefinition: true, OtherPartOfPartial: { } other } + ? (MethodKind == MethodKind.EventAdd ? other.AddMethod : other.RemoveMethod) + : null; + + public sealed override MethodSymbol? PartialDefinitionPart => _event is { IsPartialImplementation: true, OtherPartOfPartial: { } other } + ? (MethodKind == MethodKind.EventAdd ? other.AddMethod : other.RemoveMethod) + : null; + + internal bool IsPartialDefinition => _event.IsPartialDefinition; + + internal bool IsPartialImplementation => _event.IsPartialImplementation; + + public sealed override bool IsExtern => PartialImplementationPart is { } implementation ? implementation.IsExtern : base.IsExtern; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventSymbol.cs index f59aa15ba20fc..7487788040b59 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventSymbol.cs @@ -22,9 +22,12 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols /// internal abstract class SourceEventSymbol : EventSymbol, IAttributeTargetSymbol { + private SourceEventSymbol? _otherPartOfPartial; + private readonly Location _location; private readonly SyntaxReference _syntaxRef; private readonly DeclarationModifiers _modifiers; + private readonly bool _hasExplicitAccessModifier; internal readonly SourceMemberContainerTypeSymbol containingType; private SymbolCompletionState _state; @@ -52,8 +55,7 @@ internal SourceEventSymbol( _syntaxRef = syntax.GetReference(); var isExplicitInterfaceImplementation = interfaceSpecifierSyntaxOpt != null; - bool modifierErrors; - _modifiers = MakeModifiers(modifiers, isExplicitInterfaceImplementation, isFieldLike, _location, diagnostics, out modifierErrors); + _modifiers = MakeModifiers(modifiers, isExplicitInterfaceImplementation, isFieldLike, _location, diagnostics, out _, out _hasExplicitAccessModifier); this.CheckAccessibility(_location, diagnostics, isExplicitInterfaceImplementation); } @@ -72,6 +74,8 @@ internal sealed override bool HasComplete(CompletionPart part) internal override void ForceComplete(SourceLocation? locationOpt, Predicate? filter, CancellationToken cancellationToken) { + SourcePartialImplementationPart?.ForceComplete(locationOpt, filter, cancellationToken); + if (filter?.Invoke(this) == false) { return; @@ -137,25 +141,34 @@ internal SyntaxList AttributeDeclarationSyntaxList { get { - if (this.containingType.AnyMemberHasAttributes) + if (this.containingType.AnyMemberHasAttributes && MemberSyntax is { } memberSyntax) + { + return memberSyntax.AttributeLists; + } + + return default; + } + } + + internal MemberDeclarationSyntax? MemberSyntax + { + get + { + if (this.CSharpSyntaxNode is { } syntax) { - var syntax = this.CSharpSyntaxNode; - if (syntax != null) + switch (syntax.Kind()) { - switch (syntax.Kind()) - { - case SyntaxKind.EventDeclaration: - return ((EventDeclarationSyntax)syntax).AttributeLists; - case SyntaxKind.VariableDeclarator: - Debug.Assert(syntax.Parent!.Parent is object); - return ((EventFieldDeclarationSyntax)syntax.Parent.Parent).AttributeLists; - default: - throw ExceptionUtilities.UnexpectedValue(syntax.Kind()); - } + case SyntaxKind.EventDeclaration: + return (EventDeclarationSyntax)syntax; + case SyntaxKind.VariableDeclarator: + Debug.Assert(syntax.Parent?.Parent is not null); + return (EventFieldDeclarationSyntax)syntax.Parent.Parent; + default: + throw ExceptionUtilities.UnexpectedValue(syntax.Kind()); } } - return default; + return null; } } @@ -190,8 +203,26 @@ protected abstract AttributeLocation AllowedAttributeLocations /// private CustomAttributesBag GetAttributesBag() { - if ((_lazyCustomAttributesBag == null || !_lazyCustomAttributesBag.IsSealed) && - LoadAndValidateAttributes(OneOrMany.Create(this.AttributeDeclarationSyntaxList), ref _lazyCustomAttributesBag)) + var bag = _lazyCustomAttributesBag; + if (bag != null && bag.IsSealed) + { + return bag; + } + + bool bagCreatedOnThisThread; + + if (SourcePartialDefinitionPart is { } definitionPart) + { + Debug.Assert(!ReferenceEquals(definitionPart, this)); + bag = definitionPart.GetAttributesBag(); + bagCreatedOnThisThread = Interlocked.CompareExchange(ref _lazyCustomAttributesBag, bag, null) == null; + } + else + { + bagCreatedOnThisThread = LoadAndValidateAttributes(this.GetAttributeDeclarations(), ref _lazyCustomAttributesBag); + } + + if (bagCreatedOnThisThread) { DeclaringCompilation.SymbolDeclaredEvent(this); var wasCompletedThisThread = _state.NotePartComplete(CompletionPart.Attributes); @@ -202,6 +233,20 @@ private CustomAttributesBag GetAttributesBag() return _lazyCustomAttributesBag; } + private OneOrMany> GetAttributeDeclarations() + { + // Attributes on partial events are owned by the definition part. + // If this symbol has a non-null PartialDefinitionPart, we should have accessed this method through that definition symbol instead. + Debug.Assert(PartialDefinitionPart is null); + + if (SourcePartialImplementationPart is { } implementationPart) + { + return OneOrMany.Create(this.AttributeDeclarationSyntaxList, implementationPart.AttributeDeclarationSyntaxList); + } + + return OneOrMany.Create(this.AttributeDeclarationSyntaxList); + } + /// /// Gets the attributes applied on this symbol. /// Returns an empty array if there are no attributes. @@ -370,11 +415,13 @@ public sealed override bool IsAbstract get { return (_modifiers & DeclarationModifiers.Abstract) != 0; } } - public sealed override bool IsExtern + private bool HasExternModifier { get { return (_modifiers & DeclarationModifiers.Extern) != 0; } } + public sealed override bool IsExtern => PartialImplementationPart is { } implementation ? implementation.IsExtern : HasExternModifier; + public sealed override bool IsStatic { get { return (_modifiers & DeclarationModifiers.Static) != 0; } @@ -400,6 +447,11 @@ internal bool IsReadOnly get { return (_modifiers & DeclarationModifiers.ReadOnly) != 0; } } + private bool IsUnsafe + { + get { return (_modifiers & DeclarationModifiers.Unsafe) != 0; } + } + public sealed override Accessibility DeclaredAccessibility { get { return ModifierUtils.EffectiveAccessibility(_modifiers); } @@ -442,14 +494,15 @@ private void CheckAccessibility(Location location, BindingDiagnosticBag diagnost private DeclarationModifiers MakeModifiers(SyntaxTokenList modifiers, bool explicitInterfaceImplementation, bool isFieldLike, Location location, - BindingDiagnosticBag diagnostics, out bool modifierErrors) + BindingDiagnosticBag diagnostics, out bool modifierErrors, + out bool hasExplicitAccessModifier) { bool isInterface = this.ContainingType.IsInterface; var defaultAccess = isInterface && !explicitInterfaceImplementation ? DeclarationModifiers.Public : DeclarationModifiers.Private; var defaultInterfaceImplementationModifiers = DeclarationModifiers.None; // Check that the set of modifiers is allowed - var allowedModifiers = DeclarationModifiers.Unsafe; + var allowedModifiers = DeclarationModifiers.Partial | DeclarationModifiers.Unsafe; if (!explicitInterfaceImplementation) { allowedModifiers |= DeclarationModifiers.New | @@ -501,7 +554,8 @@ private DeclarationModifiers MakeModifiers(SyntaxTokenList modifiers, bool expli } var mods = ModifierUtils.MakeAndCheckNonTypeMemberModifiers(isOrdinaryMethod: false, isForInterfaceMember: isInterface, - modifiers, defaultAccess, allowedModifiers, location, diagnostics, out modifierErrors); + modifiers, defaultAccess, allowedModifiers, location, diagnostics, out modifierErrors, + out hasExplicitAccessModifier); ModifierUtils.CheckFeatureAvailabilityForStaticAbstractMembersInInterfacesIfNeeded(mods, explicitInterfaceImplementation, location, diagnostics); @@ -554,6 +608,18 @@ protected void CheckModifiersAndType(BindingDiagnosticBag diagnostics) // '{0}' cannot be sealed because it is not an override diagnostics.Add(ErrorCode.ERR_SealedNonOverride, location, this); } + else if (IsPartial && !ContainingType.IsPartial()) + { + diagnostics.Add(ErrorCode.ERR_PartialMemberOnlyInPartialClass, location); + } + else if (IsPartial && IsExplicitInterfaceImplementation) + { + diagnostics.Add(ErrorCode.ERR_PartialMemberNotExplicit, location); + } + else if (IsPartial && IsAbstract) + { + diagnostics.Add(ErrorCode.ERR_PartialMemberCannotBeAbstract, location); + } else if (IsAbstract && ContainingType.TypeKind == TypeKind.Struct) { // The modifier '{0}' is not valid for this item @@ -611,6 +677,11 @@ protected void CheckModifiersAndType(BindingDiagnosticBag diagnostics) diagnostics.Add(ErrorCode.ERR_NewVirtualInSealed, location, this, ContainingType); } + if (IsPartial) + { + ModifierUtils.CheckFeatureAvailabilityForPartialEventsAndConstructors(_location, diagnostics); + } + diagnostics.Add(location, useSiteInfo); } @@ -771,6 +842,11 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, CheckExplicitImplementationAccessor(AddMethod, explicitlyImplementedEvent.AddMethod, explicitlyImplementedEvent, diagnostics); CheckExplicitImplementationAccessor(RemoveMethod, explicitlyImplementedEvent.RemoveMethod, explicitlyImplementedEvent, diagnostics); } + + if (IsPartialDefinition && OtherPartOfPartial is { } implementation) + { + PartialEventChecks(implementation, diagnostics); + } } private void CheckExplicitImplementationAccessor(MethodSymbol? thisAccessor, MethodSymbol? otherAccessor, EventSymbol explicitlyImplementedEvent, BindingDiagnosticBag diagnostics) @@ -780,5 +856,88 @@ private void CheckExplicitImplementationAccessor(MethodSymbol? thisAccessor, Met diagnostics.Add(ErrorCode.ERR_ExplicitPropertyAddingAccessor, thisAccessor.GetFirstLocation(), thisAccessor, explicitlyImplementedEvent); } } + + private void PartialEventChecks(SourceEventSymbol implementation, BindingDiagnosticBag diagnostics) + { + Debug.Assert(this.IsPartialDefinition); + Debug.Assert(!ReferenceEquals(this, implementation)); + Debug.Assert(ReferenceEquals(this.OtherPartOfPartial, implementation)); + + if (!TypeWithAnnotations.Equals(implementation.TypeWithAnnotations, TypeCompareKind.AllIgnoreOptions)) + { + diagnostics.Add(ErrorCode.ERR_PartialMemberTypeDifference, implementation.GetFirstLocation()); + } + else if (MemberSignatureComparer.ConsideringTupleNamesCreatesDifference(this, implementation)) + { + diagnostics.Add(ErrorCode.ERR_PartialMemberInconsistentTupleNames, implementation.GetFirstLocation(), this, implementation); + } + else if (!MemberSignatureComparer.PartialMethodsStrictComparer.Equals(this, implementation)) + { + diagnostics.Add(ErrorCode.WRN_PartialMemberSignatureDifference, implementation.GetFirstLocation(), + new FormattedSymbol(this, SymbolDisplayFormat.MinimallyQualifiedFormat), + new FormattedSymbol(implementation, SymbolDisplayFormat.MinimallyQualifiedFormat)); + } + + if (IsStatic != implementation.IsStatic) + { + diagnostics.Add(ErrorCode.ERR_PartialMemberStaticDifference, implementation.GetFirstLocation()); + } + + if (IsUnsafe != implementation.IsUnsafe && this.CompilationAllowsUnsafe()) + { + diagnostics.Add(ErrorCode.ERR_PartialMemberUnsafeDifference, implementation.GetFirstLocation()); + } + + if (DeclaredAccessibility != implementation.DeclaredAccessibility + || _hasExplicitAccessModifier != implementation._hasExplicitAccessModifier) + { + diagnostics.Add(ErrorCode.ERR_PartialMemberAccessibilityDifference, implementation.GetFirstLocation()); + } + + if (IsVirtual != implementation.IsVirtual + || IsOverride != implementation.IsOverride + || IsSealed != implementation.IsSealed + || IsNew != implementation.IsNew) + { + diagnostics.Add(ErrorCode.ERR_PartialMemberExtendedModDifference, implementation.GetFirstLocation()); + } + } + + internal bool IsPartial => (this.Modifiers & DeclarationModifiers.Partial) != 0; + + /// + /// if this symbol corresponds to a semi-colon body declaration. + /// if this symbol corresponds to a declaration with custom and accessors. + /// + protected abstract bool AccessorsHaveImplementation { get; } + + internal sealed override bool IsPartialDefinition => IsPartial && !AccessorsHaveImplementation && !HasExternModifier; + + internal bool IsPartialImplementation => IsPartial && (AccessorsHaveImplementation || HasExternModifier); + + internal SourceEventSymbol? OtherPartOfPartial => _otherPartOfPartial; + + internal SourceEventSymbol? SourcePartialDefinitionPart => IsPartialImplementation ? OtherPartOfPartial : null; + + internal SourceEventSymbol? SourcePartialImplementationPart => IsPartialDefinition ? OtherPartOfPartial : null; + + internal sealed override EventSymbol? PartialDefinitionPart => SourcePartialDefinitionPart; + + internal sealed override EventSymbol? PartialImplementationPart => SourcePartialImplementationPart; + + internal static void InitializePartialEventParts(SourceEventSymbol definition, SourceEventSymbol implementation) + { + Debug.Assert(definition.IsPartialDefinition); + Debug.Assert(implementation.IsPartialImplementation); + + Debug.Assert(definition._otherPartOfPartial is not { } alreadySetImplPart || ReferenceEquals(alreadySetImplPart, implementation)); + Debug.Assert(implementation._otherPartOfPartial is not { } alreadySetDefPart || ReferenceEquals(alreadySetDefPart, definition)); + + definition._otherPartOfPartial = implementation; + implementation._otherPartOfPartial = definition; + + Debug.Assert(ReferenceEquals(definition._otherPartOfPartial, implementation)); + Debug.Assert(ReferenceEquals(implementation._otherPartOfPartial, definition)); + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceFieldLikeEventSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceFieldLikeEventSymbol.cs index be6a53393884a..3148d00a9ad3e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceFieldLikeEventSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceFieldLikeEventSymbol.cs @@ -5,25 +5,27 @@ using System; using System.Collections.Immutable; using System.Diagnostics; +using System.Reflection; using System.Threading; -using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Symbols { /// /// This class represents an event declared in source without explicit accessors. /// It implicitly has thread safe accessors and an associated field (of the same - /// name), unless it does not have an initializer and is either extern or inside + /// name), unless it does not have an initializer and is extern, partial, or inside /// an interface, in which case it only has accessors. /// internal sealed class SourceFieldLikeEventSymbol : SourceEventSymbol { private readonly string _name; private readonly TypeWithAnnotations _type; - private readonly SynthesizedEventAccessorSymbol _addMethod; - private readonly SynthesizedEventAccessorSymbol _removeMethod; + private readonly SourceEventAccessorSymbol _addMethod; + private readonly SourceEventAccessorSymbol _removeMethod; internal SourceFieldLikeEventSymbol(SourceMemberContainerTypeSymbol containingType, Binder binder, SyntaxTokenList modifiers, VariableDeclaratorSyntax declaratorSyntax, BindingDiagnosticBag diagnostics) : base(containingType, declaratorSyntax, modifiers, isFieldLike: true, interfaceSpecifierSyntaxOpt: null, @@ -77,11 +79,15 @@ internal SourceFieldLikeEventSymbol(SourceMemberContainerTypeSymbol containingTy { diagnostics.Add(ErrorCode.ERR_ExternEventInitializer, this.GetFirstLocation(), this); } + else if (this.IsPartial) + { + diagnostics.Add(ErrorCode.ERR_PartialEventInitializer, this.GetFirstLocation(), this); + } } // NOTE: if there's an initializer in source, we'd better create a backing field, regardless of // whether or not the initializer is legal. - if (hasInitializer || !(this.IsExtern || this.IsAbstract)) + if (hasInitializer || !(this.IsExtern || this.IsAbstract || this.IsPartial)) { AssociatedEventField = MakeAssociatedField(declaratorSyntax); // Don't initialize this.type - we'll just use the type of the field (which is lazy and handles var) @@ -108,14 +114,22 @@ internal SourceFieldLikeEventSymbol(SourceMemberContainerTypeSymbol containingTy diagnostics.Add(ErrorCode.ERR_RuntimeDoesNotSupportDefaultInterfaceImplementation, this.GetFirstLocation()); } } - else if (!this.IsAbstract) + else if (!this.IsAbstract && !this.IsPartialDefinition) { diagnostics.Add(ErrorCode.ERR_EventNeedsBothAccessors, this.GetFirstLocation(), this); } } - _addMethod = new SynthesizedEventAccessorSymbol(this, isAdder: true, isExpressionBodied: false); - _removeMethod = new SynthesizedEventAccessorSymbol(this, isAdder: false, isExpressionBodied: false); + if (this.IsPartialDefinition) + { + _addMethod = new SourceEventDefinitionAccessorSymbol(this, isAdder: true, diagnostics); + _removeMethod = new SourceEventDefinitionAccessorSymbol(this, isAdder: false, diagnostics); + } + else + { + _addMethod = new SynthesizedEventAccessorSymbol(this, isAdder: true, isExpressionBodied: false); + _removeMethod = new SynthesizedEventAccessorSymbol(this, isAdder: false, isExpressionBodied: false); + } if (declarationSyntax.Variables[0] == declaratorSyntax) { @@ -126,6 +140,8 @@ internal SourceFieldLikeEventSymbol(SourceMemberContainerTypeSymbol containingTy declaratorDiagnostics.Free(); } + protected override bool AccessorsHaveImplementation => false; + /// /// Backing field for field-like event. Will be null if the event /// has no initializer and is either extern or inside an interface. @@ -163,9 +179,19 @@ protected override AttributeLocation AllowedAttributeLocations { get { - return (object?)AssociatedEventField != null ? - AttributeLocation.Event | AttributeLocation.Method | AttributeLocation.Field : - AttributeLocation.Event | AttributeLocation.Method; + var result = AttributeLocation.Event; + + if (!IsPartial || IsExtern) + { + result |= AttributeLocation.Method; + } + + if (AssociatedEventField is not null) + { + result |= AttributeLocation.Field; + } + + return result; } } @@ -191,5 +217,122 @@ internal override void ForceComplete(SourceLocation? locationOpt, Predicate + /// Accessor of a which is a partial definition. + /// + internal sealed class SourceEventDefinitionAccessorSymbol : SourceEventAccessorSymbol + { + internal SourceEventDefinitionAccessorSymbol( + SourceFieldLikeEventSymbol ev, + bool isAdder, + BindingDiagnosticBag diagnostics) + : base( + @event: ev, + syntaxReference: ev.SyntaxReference, + location: ev.Location, + explicitlyImplementedEventOpt: null, + aliasQualifierOpt: null, + isAdder: isAdder, + isIterator: false, + isNullableAnalysisEnabled: ev.DeclaringCompilation.IsNullableAnalysisEnabledIn(ev.CSharpSyntaxNode), + isExpressionBodied: false) + { + Debug.Assert(ev.IsPartialDefinition); + + CheckFeatureAvailabilityAndRuntimeSupport(ev.CSharpSyntaxNode, ev.Location, hasBody: false, diagnostics: diagnostics); + } + + public override Accessibility DeclaredAccessibility => AssociatedEvent.DeclaredAccessibility; + + public override bool IsImplicitlyDeclared => true; + + internal override bool GenerateDebugInfo => true; + + internal override ExecutableCodeBinder? TryGetBodyBinder(BinderFactory? binderFactoryOpt = null, bool ignoreAccessibility = false) + { + return null; + } + + protected override SourceMemberMethodSymbol? BoundAttributesSource + { + get + { + return IsExtern && this.MethodKind == MethodKind.EventAdd + ? (SourceMemberMethodSymbol?)this.AssociatedEvent.RemoveMethod + : null; + } + } + + protected override IAttributeTargetSymbol AttributeOwner + { + get + { + Debug.Assert(IsPartialDefinition); + + switch (PartialImplementationPart) + { + case SourceCustomEventAccessorSymbol: + return this; + + case SynthesizedEventAccessorSymbol: + Debug.Assert(IsExtern); + return AssociatedEvent; + + case null: + // Might happen in error scenarios. + return this; + + default: + Debug.Assert(false); + return this; + } + } + } + + internal override OneOrMany> GetAttributeDeclarations() + { + Debug.Assert(IsPartialDefinition); + + switch (PartialImplementationPart) + { + case SourceCustomEventAccessorSymbol customImplementationPart: + return OneOrMany.Create(customImplementationPart.AttributeDeclarationSyntaxList); + + case SynthesizedEventAccessorSymbol synthesizedImplementationPart: + Debug.Assert(IsExtern); + return OneOrMany.Create( + AssociatedEvent.AttributeDeclarationSyntaxList, + synthesizedImplementationPart.AssociatedEvent.AttributeDeclarationSyntaxList); + + case null: + // Might happen in error scenarios. + return OneOrMany>.Empty; + + default: + Debug.Assert(false); + return OneOrMany>.Empty; + } + } + + internal override MethodImplAttributes ImplementationAttributes + { + get + { + Debug.Assert(IsPartialDefinition); + + if (PartialImplementationPart is { } implementationPart) + { + return implementationPart.ImplementationAttributes; + } + + // This could happen in error scenarios (when the implementation part of a partial event is missing), + // but then we should not get to the emit stage and call this property. + Debug.Assert(false); + + return base.ImplementationAttributes; + } + } + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs index 4c7d1716afb69..de8b927b16b00 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs @@ -292,54 +292,63 @@ private DeclarationModifiers MakeModifiers(TypeKind typeKind, BindingDiagnosticB DeclarationModifiers defaultAccess; // note: we give a specific diagnostic when a file-local type is nested - var allowedModifiers = DeclarationModifiers.AccessibilityMask | DeclarationModifiers.File; - - if (containingSymbol.Kind == SymbolKind.Namespace) + DeclarationModifiers allowedModifiers; + if (typeKind == TypeKind.Extension) { - defaultAccess = DeclarationModifiers.Internal; + allowedModifiers = DeclarationModifiers.None; + defaultAccess = DeclarationModifiers.Public; } else { - allowedModifiers |= DeclarationModifiers.New; + allowedModifiers = DeclarationModifiers.AccessibilityMask | DeclarationModifiers.File; - if (((NamedTypeSymbol)containingSymbol).IsInterface) + if (containingSymbol.Kind == SymbolKind.Namespace) { - defaultAccess = DeclarationModifiers.Public; + defaultAccess = DeclarationModifiers.Internal; } else { - defaultAccess = DeclarationModifiers.Private; - } - } + allowedModifiers |= DeclarationModifiers.New; - switch (typeKind) - { - case TypeKind.Class: - case TypeKind.Submission: - allowedModifiers |= DeclarationModifiers.Partial | DeclarationModifiers.Sealed | DeclarationModifiers.Abstract - | DeclarationModifiers.Unsafe; - - if (!this.IsRecord) + if (((NamedTypeSymbol)containingSymbol).IsInterface) { - allowedModifiers |= DeclarationModifiers.Static; + defaultAccess = DeclarationModifiers.Public; } - - break; - case TypeKind.Struct: - allowedModifiers |= DeclarationModifiers.Partial | DeclarationModifiers.ReadOnly | DeclarationModifiers.Unsafe; - - if (!this.IsRecordStruct) + else { - allowedModifiers |= DeclarationModifiers.Ref; + defaultAccess = DeclarationModifiers.Private; } + } - break; - case TypeKind.Interface: - allowedModifiers |= DeclarationModifiers.Partial | DeclarationModifiers.Unsafe; - break; - case TypeKind.Delegate: - allowedModifiers |= DeclarationModifiers.Unsafe; - break; + switch (typeKind) + { + case TypeKind.Class: + case TypeKind.Submission: + allowedModifiers |= DeclarationModifiers.Partial | DeclarationModifiers.Sealed | DeclarationModifiers.Abstract + | DeclarationModifiers.Unsafe; + + if (!this.IsRecord) + { + allowedModifiers |= DeclarationModifiers.Static; + } + + break; + case TypeKind.Struct: + allowedModifiers |= DeclarationModifiers.Partial | DeclarationModifiers.ReadOnly | DeclarationModifiers.Unsafe; + + if (!this.IsRecordStruct) + { + allowedModifiers |= DeclarationModifiers.Ref; + } + + break; + case TypeKind.Interface: + allowedModifiers |= DeclarationModifiers.Partial | DeclarationModifiers.Unsafe; + break; + case TypeKind.Delegate: + allowedModifiers |= DeclarationModifiers.Unsafe; + break; + } } bool modifierErrors; @@ -371,9 +380,8 @@ private DeclarationModifiers MakeModifiers(TypeKind typeKind, BindingDiagnosticB break; case TypeKind.Struct: case TypeKind.Enum: - mods |= DeclarationModifiers.Sealed; - break; case TypeKind.Delegate: + case TypeKind.Extension: mods |= DeclarationModifiers.Sealed; break; } @@ -1267,7 +1275,7 @@ public override IEnumerable MemberNames { get { - return (IsTupleType || IsRecord || IsRecordStruct) ? GetMembers().Select(m => m.Name) : this.declaration.MemberNames; + return (IsTupleType || IsRecord || IsRecordStruct || this.declaration.ContainsExtensionDeclarations) ? GetMembers().Select(m => m.Name) : this.declaration.MemberNames; } } @@ -1329,27 +1337,30 @@ private Dictionary, ImmutableArray> MakeTy foreach (var childDeclaration in declaration.Children) { var t = new SourceNamedTypeSymbol(this, childDeclaration, diagnostics); - this.CheckMemberNameDistinctFromType(t, diagnostics); - - var key = (t.Name, t.Arity, t.AssociatedSyntaxTree); - SourceNamedTypeSymbol? other; - if (conflictDict.TryGetValue(key, out other)) + if (!t.IsExtension) { - if (Locations.Length == 1 || IsPartial) + this.CheckMemberNameDistinctFromType(t, diagnostics); + + var key = (t.Name, t.Arity, t.AssociatedSyntaxTree); + SourceNamedTypeSymbol? other; + if (conflictDict.TryGetValue(key, out other)) { - if (t.IsPartial && other.IsPartial) + if (Locations.Length == 1 || IsPartial) { - diagnostics.Add(ErrorCode.ERR_PartialTypeKindConflict, t.GetFirstLocation(), t); - } - else - { - diagnostics.Add(ErrorCode.ERR_DuplicateNameInClass, t.GetFirstLocation(), this, t.Name); + if (t.IsPartial && other.IsPartial) + { + diagnostics.Add(ErrorCode.ERR_PartialTypeKindConflict, t.GetFirstLocation(), t); + } + else + { + diagnostics.Add(ErrorCode.ERR_DuplicateNameInClass, t.GetFirstLocation(), this, t.Name); + } } } - } - else - { - conflictDict.Add(key, t); + else + { + conflictDict.Add(key, t); + } } symbols.Add(t); @@ -1497,7 +1508,7 @@ internal override bool HasPossibleWellKnownCloneMethod() internal override ImmutableArray GetSimpleNonTypeMembers(string name) { - if (_lazyMembersDictionary != null || declaration.MemberNames.Contains(name) || declaration.Kind is DeclarationKind.Record or DeclarationKind.RecordStruct) + if (_lazyMembersDictionary != null || declaration.ContainsExtensionDeclarations || declaration.MemberNames.Contains(name) || declaration.Kind is DeclarationKind.Record or DeclarationKind.RecordStruct) { return GetMembers(name); } @@ -1700,6 +1711,10 @@ internal void AssertMemberExposure(Symbol member, bool forDiagnostics = false) { member = implementation; // This is a workaround for https://github.com/dotnet/roslyn/issues/76870, remove once the issue is addressed. } + else if (member is SynthesizedExtensionMarker) + { + return; + } var membersAndInitializers = Volatile.Read(ref _lazyMembersAndInitializers); @@ -1743,16 +1758,7 @@ internal void AssertMemberExposure(Symbol member, bool forDiagnostics = false) static bool isMemberInCompleteMemberList(MembersAndInitializers? membersAndInitializers, Symbol member) { - switch (member) - { - case MethodSymbol method: - member = method.PartialDefinitionPart ?? method; - break; - case PropertySymbol property: - member = property.PartialDefinitionPart ?? property; - break; - } - + member = member.GetPartialDefinitionPart() ?? member; return membersAndInitializers?.NonTypeMembers.Contains(m => m == (object)member) == true; } } @@ -1796,17 +1802,21 @@ internal override IEnumerable GetInstanceFieldsAndEvents() protected void AfterMembersChecks(BindingDiagnosticBag diagnostics) { + var compilation = DeclaringCompilation; if (IsInterface) { CheckInterfaceMembers(this.GetMembersAndInitializers().NonTypeMembers, diagnostics); } + else if (IsExtension) + { + CheckExtensionMembers(this.GetMembers(), diagnostics); + } - CheckMemberNamesDistinctFromType(diagnostics); + CheckMemberNamesDistinctFromType(diagnostics); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Should this check "see through" extensions? CheckMemberNameConflicts(diagnostics); CheckRecordMemberNames(diagnostics); CheckSpecialMemberErrors(diagnostics); CheckTypeParameterNameConflicts(diagnostics); - CheckAccessorNameConflicts(diagnostics); bool unused = KnownCircularStruct; @@ -1821,7 +1831,6 @@ protected void AfterMembersChecks(BindingDiagnosticBag diagnostics) } var location = GetFirstLocation(); - var compilation = DeclaringCompilation; if (this.IsRefLikeType) { @@ -1900,6 +1909,12 @@ protected void AfterMembersChecks(BindingDiagnosticBag diagnostics) } } + if (IsExtension) + { + // Verify ExtensionAttribute is available. + SourceOrdinaryMethodSymbol.CheckExtensionAttributeAvailability(DeclaringCompilation, location, diagnostics); + } + return; bool hasBaseTypeOrInterface(Func predicate) @@ -1948,17 +1963,21 @@ private void CheckRecordMemberNames(BindingDiagnosticBag diagnostics) } } - private void CheckMemberNameConflicts(BindingDiagnosticBag diagnostics) + private static void CheckMemberNameConflicts( + SourceMemberContainerTypeSymbol containerForDiagnostics, + bool mightHaveMembersFromDistinctNonPartialDeclarations, + Dictionary, ImmutableArray>? typesByName, + Dictionary, ImmutableArray> membersByName, + BindingDiagnosticBag diagnostics) { - Dictionary, ImmutableArray> membersByName = GetMembersByName(); // Collisions involving indexers are handled specially. - CheckIndexerNameConflicts(diagnostics, membersByName); + CheckIndexerNameConflicts(containerForDiagnostics, mightHaveMembersFromDistinctNonPartialDeclarations, diagnostics, membersByName); // key and value will be the same object in these dictionaries. - var methodsBySignature = new Dictionary(MemberSignatureComparer.DuplicateSourceComparer); - var conversionsAsMethods = new Dictionary(MemberSignatureComparer.DuplicateSourceComparer); - var conversionsAsConversions = new HashSet(ConversionSignatureComparer.Comparer); + var methodsBySignature = new Dictionary(MemberSignatureComparer.DuplicateSourceComparer); + var conversionsAsMethods = new Dictionary(MemberSignatureComparer.DuplicateSourceComparer); + var conversionsAsConversions = new HashSet(ConversionSignatureComparer.Comparer); // SPEC: The signature of an operator must differ from the signatures of all other // SPEC: operators declared in the same class. @@ -1997,7 +2016,7 @@ private void CheckMemberNameConflicts(BindingDiagnosticBag diagnostics) foreach (var pair in membersByName) { var name = pair.Key; - Symbol? lastSym = GetTypeMembers(name).FirstOrDefault(); + Symbol? lastSym = typesByName?.TryGetValue(name, out var types) == true ? types.FirstOrDefault() : null; methodsBySignature.Clear(); // Conversion collisions do not consider the name of the conversion, // so do not clear that dictionary. @@ -2005,7 +2024,8 @@ private void CheckMemberNameConflicts(BindingDiagnosticBag diagnostics) { if (symbol.Kind == SymbolKind.NamedType || symbol.IsAccessor() || - symbol.IsIndexer()) + symbol.IsIndexer() || + symbol.OriginalDefinition is SynthesizedExtensionMarker) { continue; } @@ -2051,9 +2071,9 @@ private void CheckMemberNameConflicts(BindingDiagnosticBag diagnostics) if (symbol.Kind != SymbolKind.Field || !symbol.IsImplicitlyDeclared) { // The type '{0}' already contains a definition for '{1}' - if (Locations.Length == 1 || IsPartial) + if (!mightHaveMembersFromDistinctNonPartialDeclarations) { - diagnostics.Add(ErrorCode.ERR_DuplicateNameInClass, symbol.GetFirstLocation(), this, symbol.Name); + diagnostics.Add(ErrorCode.ERR_DuplicateNameInClass, symbol.GetFirstLocation(), containerForDiagnostics, symbol.Name); } } @@ -2071,11 +2091,8 @@ private void CheckMemberNameConflicts(BindingDiagnosticBag diagnostics) // That takes care of the first category of conflict; we detect the // second and third categories as follows: - var conversion = symbol as SourceUserDefinedConversionSymbol; - var method = symbol as SourceMemberMethodSymbol; - // We don't want to consider explicit interface implementations - if (conversion is { MethodKind: MethodKind.Conversion }) + if (symbol is MethodSymbol { MethodKind: MethodKind.Conversion } conversion) { // Does this conversion collide *as a conversion* with any previously-seen // conversion? @@ -2083,7 +2100,7 @@ private void CheckMemberNameConflicts(BindingDiagnosticBag diagnostics) if (!conversionsAsConversions.Add(conversion)) { // CS0557: Duplicate user-defined conversion in type 'C' - diagnostics.Add(ErrorCode.ERR_DuplicateConversionInClass, conversion.GetFirstLocation(), this); + diagnostics.Add(ErrorCode.ERR_DuplicateConversionInClass, conversion.GetFirstLocation(), containerForDiagnostics); } else { @@ -2100,19 +2117,19 @@ private void CheckMemberNameConflicts(BindingDiagnosticBag diagnostics) if (methodsBySignature.TryGetValue(conversion, out var previousMethod)) { - ReportMethodSignatureCollision(diagnostics, conversion, previousMethod); + ReportMethodSignatureCollision(containerForDiagnostics, diagnostics, conversion, previousMethod); } // Do not add the conversion to the set of previously-seen methods; that set // is only non-conversion methods. } - else if (!(method is null)) + else if (symbol is MethodSymbol method) { // Does this method collide *as a method* with any previously-seen // conversion? if (conversionsAsMethods.TryGetValue(method, out var previousConversion)) { - ReportMethodSignatureCollision(diagnostics, method, previousConversion); + ReportMethodSignatureCollision(containerForDiagnostics, diagnostics, method, previousConversion); } // Do not add the method to the set of previously-seen conversions. @@ -2121,7 +2138,7 @@ private void CheckMemberNameConflicts(BindingDiagnosticBag diagnostics) if (methodsBySignature.TryGetValue(method, out var previousMethod)) { - ReportMethodSignatureCollision(diagnostics, method, previousMethod); + ReportMethodSignatureCollision(containerForDiagnostics, diagnostics, method, previousMethod); } else { @@ -2136,7 +2153,7 @@ private void CheckMemberNameConflicts(BindingDiagnosticBag diagnostics) // Report a name conflict; the error is reported on the location of method1. // UNDONE: Consider adding a secondary location pointing to the second method. - private void ReportMethodSignatureCollision(BindingDiagnosticBag diagnostics, SourceMemberMethodSymbol method1, SourceMemberMethodSymbol method2) + private static void ReportMethodSignatureCollision(SourceMemberContainerTypeSymbol containerForDiagnostics, BindingDiagnosticBag diagnostics, MethodSymbol method1, MethodSymbol method2) { switch (method1, method2) { @@ -2152,12 +2169,28 @@ private void ReportMethodSignatureCollision(BindingDiagnosticBag diagnostics, So // If method1 is a constructor only because its return type is missing, then // we've already produced a diagnostic for the missing return type and we suppress the // diagnostic about duplicate signature. - if (method1.MethodKind == MethodKind.Constructor && - ((ConstructorDeclarationSyntax)method1.SyntaxRef.GetSyntax()).Identifier.ValueText != this.Name) + if (method1.OriginalDefinition is SourceMemberMethodSymbol { MethodKind: MethodKind.Constructor } constructor && + ((ConstructorDeclarationSyntax)constructor.SyntaxRef.GetSyntax()).Identifier.ValueText != method1.ContainingType.Name) { return; } + if (method1 is SourceExtensionImplementationMethodSymbol { UnderlyingMethod: var underlying1 } && + method2 is SourceExtensionImplementationMethodSymbol { UnderlyingMethod: var underlying2 } && + underlying1.IsStatic == underlying2.IsStatic && + ((object)underlying1.ContainingType == underlying2.ContainingType || + new ExtensionGroupingKey(underlying1.ContainingType).Equals(new ExtensionGroupingKey(underlying2.ContainingType))) && + diagnostics.DiagnosticBag?.AsEnumerableWithoutResolution().Any( + static (d, arg) => + (d.Code is (int)ErrorCode.ERR_OverloadRefKind or (int)ErrorCode.ERR_MemberAlreadyExists or + (int)ErrorCode.ERR_DuplicateNameInClass or (int)ErrorCode.ERR_MemberReserved) && + (d.Location == arg.method1.GetFirstLocation() || d.Location == arg.underlying1.AssociatedSymbol?.TryGetFirstLocation() || + d.Location == arg.method2.GetFirstLocation() || d.Location == arg.underlying2.AssociatedSymbol?.TryGetFirstLocation()), + (method1, underlying1, method2, underlying2)) == true) + { + return; // The conflict is reported in context of extension declaration + } + Debug.Assert(method1.ParameterCount == method2.ParameterCount); for (int i = 0; i < method1.ParameterCount; i++) @@ -2169,32 +2202,33 @@ private void ReportMethodSignatureCollision(BindingDiagnosticBag diagnostics, So { // '{0}' cannot define an overloaded {1} that differs only on parameter modifiers '{2}' and '{3}' var methodKind = method1.MethodKind == MethodKind.Constructor ? MessageID.IDS_SK_CONSTRUCTOR : MessageID.IDS_SK_METHOD; - diagnostics.Add(ErrorCode.ERR_OverloadRefKind, method1.GetFirstLocation(), this, methodKind.Localize(), refKind1.ToParameterDisplayString(), refKind2.ToParameterDisplayString()); + diagnostics.Add(ErrorCode.ERR_OverloadRefKind, method1.GetFirstLocation(), containerForDiagnostics, methodKind.Localize(), refKind1.ToParameterDisplayString(), refKind2.ToParameterDisplayString()); return; } } + if (method1 is SourceExtensionImplementationMethodSymbol extensionImplementation) + { + method1 = extensionImplementation.UnderlyingMethod; + } + // Special case: if there are two destructors, use the destructor syntax instead of "Finalize" var methodName = (method1.MethodKind == MethodKind.Destructor && method2.MethodKind == MethodKind.Destructor) ? - "~" + this.Name : - (method1.IsConstructor() ? this.Name : method1.Name); + "~" + method1.ContainingType.Name : + (method1.IsConstructor() ? method1.ContainingType.Name : method1.Name); // Type '{1}' already defines a member called '{0}' with the same parameter types - diagnostics.Add(ErrorCode.ERR_MemberAlreadyExists, method1.GetFirstLocation(), methodName, this); + diagnostics.Add(ErrorCode.ERR_MemberAlreadyExists, method1.GetFirstLocation(), methodName, containerForDiagnostics); } - private void CheckIndexerNameConflicts(BindingDiagnosticBag diagnostics, Dictionary, ImmutableArray> membersByName) + private static void CheckIndexerNameConflicts( + SourceMemberContainerTypeSymbol containerForDiagnostics, + bool mightHaveMembersFromDistinctNonPartialDeclarations, + BindingDiagnosticBag diagnostics, Dictionary, ImmutableArray> membersByName) { PooledHashSet? typeParameterNames = null; - if (this.Arity > 0) - { - typeParameterNames = PooledHashSet.GetInstance(); - foreach (TypeParameterSymbol typeParameter in this.TypeParameters) - { - typeParameterNames.Add(typeParameter.Name); - } - } + bool checkCollisionWithTypeParameters = true; var indexersBySignature = new Dictionary(MemberSignatureComparer.DuplicateSourceComparer); @@ -2210,6 +2244,8 @@ private void CheckIndexerNameConflicts(BindingDiagnosticBag diagnostics, Diction { PropertySymbol indexer = (PropertySymbol)symbol; CheckIndexerSignatureCollisions( + containerForDiagnostics, + mightHaveMembersFromDistinctNonPartialDeclarations, indexer, diagnostics, membersByName, @@ -2218,12 +2254,31 @@ private void CheckIndexerNameConflicts(BindingDiagnosticBag diagnostics, Diction // Also check for collisions with type parameters, which aren't in the member map. // NOTE: Accessors have normal names and are handled in CheckTypeParameterNameConflicts. + + if (checkCollisionWithTypeParameters && typeParameterNames == null) + { + if (!indexer.GetIsNewExtensionMember() && indexer.ContainingType.Arity > 0) + { + typeParameterNames = PooledHashSet.GetInstance(); + foreach (TypeParameterSymbol typeParameter in indexer.ContainingType.TypeParameters) + { + typeParameterNames.Add(typeParameter.Name); + } + } + else + { + checkCollisionWithTypeParameters = false; + } + } + + Debug.Assert(checkCollisionWithTypeParameters || typeParameterNames == null); + if (typeParameterNames != null) { string indexerName = indexer.MetadataName; if (typeParameterNames.Contains(indexerName)) { - diagnostics.Add(ErrorCode.ERR_DuplicateNameInClass, indexer.GetFirstLocation(), this, indexerName); + diagnostics.Add(ErrorCode.ERR_DuplicateNameInClass, indexer.GetFirstLocation(), containerForDiagnostics, indexerName); continue; } } @@ -2234,7 +2289,9 @@ private void CheckIndexerNameConflicts(BindingDiagnosticBag diagnostics, Diction typeParameterNames?.Free(); } - private void CheckIndexerSignatureCollisions( + private static void CheckIndexerSignatureCollisions( + SourceMemberContainerTypeSymbol containerForDiagnostics, + bool mightHaveMembersFromDistinctNonPartialDeclarations, PropertySymbol indexer, BindingDiagnosticBag diagnostics, Dictionary, ImmutableArray> membersByName, @@ -2259,7 +2316,7 @@ private void CheckIndexerSignatureCollisions( lastIndexerName = indexerName; - if (Locations.Length == 1 || IsPartial) + if (!mightHaveMembersFromDistinctNonPartialDeclarations) { #pragma warning disable CA1854 //Prefer a 'TryGetValue' call over a Dictionary indexer access guarded by a 'ContainsKey' check to avoid double lookup if (membersByName.ContainsKey(indexerName.AsMemory())) @@ -2267,7 +2324,7 @@ private void CheckIndexerSignatureCollisions( { // The name of the indexer is reserved - it can only be used by other indexers. Debug.Assert(!membersByName[indexerName.AsMemory()].Any(SymbolExtensions.IsIndexer)); - diagnostics.Add(ErrorCode.ERR_DuplicateNameInClass, indexer.GetFirstLocation(), this, indexerName); + diagnostics.Add(ErrorCode.ERR_DuplicateNameInClass, indexer.GetFirstLocation(), containerForDiagnostics, indexerName); } } } @@ -2276,7 +2333,7 @@ private void CheckIndexerSignatureCollisions( { // Type '{1}' already defines a member called '{0}' with the same parameter types // NOTE: Dev10 prints "this" as the name of the indexer. - diagnostics.Add(ErrorCode.ERR_MemberAlreadyExists, indexer.GetFirstLocation(), SyntaxFacts.GetText(SyntaxKind.ThisKeyword), this); + diagnostics.Add(ErrorCode.ERR_MemberAlreadyExists, indexer.GetFirstLocation(), SyntaxFacts.GetText(SyntaxKind.ThisKeyword), containerForDiagnostics); } else { @@ -2284,6 +2341,181 @@ private void CheckIndexerSignatureCollisions( } } + private void CheckMemberNameConflicts(BindingDiagnosticBag diagnostics) + { + if (IsExtension) + { + return; // Conflicts are checked in context of the enclosing type + } + + if (this.declaration.ContainsExtensionDeclarations) + { + checkMemberNameConflictsInExtensions(diagnostics); + } + + checkMemberNameConflicts(GetMembersByName(), GetTypeMembersDictionary(), GetMembersUnordered(), diagnostics); + return; + + void checkMemberNameConflicts( + Dictionary, ImmutableArray> membersByName, + Dictionary, ImmutableArray>? typesByName, + ImmutableArray membersUnordered, + BindingDiagnosticBag diagnostics) + { + bool mightHaveMembersFromDistinctNonPartialDeclarations = !(Locations.Length == 1 || IsPartial); + CheckMemberNameConflicts(this, mightHaveMembersFromDistinctNonPartialDeclarations, typesByName, membersByName, diagnostics); + CheckAccessorNameConflicts(this, mightHaveMembersFromDistinctNonPartialDeclarations, membersByName, membersUnordered, diagnostics); + } + + void checkMemberNameConflictsInExtensions(BindingDiagnosticBag diagnostics) + { + IEnumerable> extensionsByReceiverType = GetTypeMembers("").Where(static t => t.IsExtension).GroupBy(static t => new ExtensionGroupingKey(t)); + + foreach (var grouping in extensionsByReceiverType) + { + Dictionary, ImmutableArray>? membersByName; + ImmutableArray membersUnordered; + + (membersByName, membersUnordered) = mergeMembersInGroup(grouping); + + if (membersByName is not null) + { + checkMemberNameConflicts(membersByName, typesByName: null /* nested types not supported */, membersUnordered, diagnostics); + } + } + } + + static (Dictionary, ImmutableArray>? membersByName, ImmutableArray membersUnordered) mergeMembersInGroup(IGrouping grouping) + { + Dictionary, ImmutableArray>? membersByName = null; + ImmutableArray membersUnordered = []; + NamedTypeSymbol? masterExtension = null; + bool cloneMembersByName = true; + + foreach (NamedTypeSymbol item in grouping) + { + var extension = item; + Dictionary, ImmutableArray> membersByNameToMerge = ((SourceMemberContainerTypeSymbol)extension).GetMembersByName(); + + if (membersByNameToMerge.Count == 0 || + (membersByNameToMerge.Count == 1 && membersByNameToMerge.Values.Single() is [SynthesizedExtensionMarker])) + { + continue; // This is an optimization + } + + if (membersByName == null) + { + membersByName = membersByNameToMerge; + membersUnordered = extension.GetMembersUnordered(); + masterExtension = extension; + Debug.Assert(cloneMembersByName); + } + else + { + Debug.Assert(masterExtension is not null); + + if (cloneMembersByName) + { + membersByName = new Dictionary, ImmutableArray>(membersByName, ReadOnlyMemoryOfCharComparer.Instance); + cloneMembersByName = false; + } + + if (extension.Arity != 0) + { + extension = extension.Construct(masterExtension.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics); + } + else + { + membersUnordered = membersUnordered.Concat(extension.GetMembersUnordered()); + } + + foreach (var pair in membersByNameToMerge) + { + if (membersByName.TryGetValue(pair.Key, out var members)) + { + membersByName[pair.Key] = concatMembers(members, extension, pair.Value, ref membersUnordered); + } + else + { + membersByName.Add(pair.Key, concatMembers([], extension, pair.Value, ref membersUnordered)); + } + } + } + } + + return (membersByName, membersUnordered); + } + + static ImmutableArray concatMembers(ImmutableArray existingMembers, NamedTypeSymbol extension, ImmutableArray newMembers, ref ImmutableArray membersUnordered) + { + Debug.Assert(!newMembers.IsEmpty); + + if (extension.IsDefinition) + { + Debug.Assert(newMembers.All(static (m, membersUnordered) => membersUnordered.Contains(m), membersUnordered)); + return existingMembers.Concat(newMembers); + } + + var membersBuilder = ArrayBuilder.GetInstance(existingMembers.Length + newMembers.Length); + var membersUnorderedBuilder = ArrayBuilder.GetInstance(membersUnordered.Length + newMembers.Length); + + membersBuilder.AddRange(existingMembers); + membersUnorderedBuilder.AddRange(membersUnordered); + + foreach (var member in newMembers) + { + Symbol toAdd = member.SymbolAsMember(extension); + membersBuilder.Add(toAdd); + membersUnorderedBuilder.Add(toAdd); + } + + membersUnordered = membersUnorderedBuilder.ToImmutableAndFree(); + return membersBuilder.ToImmutableAndFree(); + } + } + + private readonly struct ExtensionGroupingKey : IEquatable + { + public readonly int ExtensionArity; + public readonly TypeSymbol ReceiverType; + + public ExtensionGroupingKey(NamedTypeSymbol extension) + { + ExtensionArity = extension.Arity; + + if (extension.Arity != 0) + { + extension = extension.Construct(IndexedTypeParameterSymbol.Take(extension.Arity)); + } + + if (extension.ExtensionParameter is { } receiverParameter) + { + ReceiverType = receiverParameter.Type; + } + else + { + ReceiverType = ErrorTypeSymbol.UnknownResultType; + } + } + + public bool Equals(ExtensionGroupingKey other) + { + return ExtensionArity == other.ExtensionArity && + ReceiverType.Equals(other.ReceiverType, TypeCompareKind.AllIgnoreOptions); + } + + public override bool Equals([NotNullWhen(true)] object? obj) + { + Debug.Assert(false); // Usage of this method is unexpected + return Equals((ExtensionGroupingKey)obj!); + } + + public override int GetHashCode() + { + return ReceiverType.GetHashCode(); + } + } + private void CheckSpecialMemberErrors(BindingDiagnosticBag diagnostics) { var conversions = this.ContainingAssembly.CorLibrary.TypeConversions; @@ -2295,9 +2527,9 @@ private void CheckSpecialMemberErrors(BindingDiagnosticBag diagnostics) private void CheckTypeParameterNameConflicts(BindingDiagnosticBag diagnostics) { - if (this.TypeKind == TypeKind.Delegate) + if (this.TypeKind is TypeKind.Delegate or TypeKind.Extension) { - // Delegates do not have conflicts between their type parameter + // Delegates and extensions do not have conflicts between their type parameter // names and their methods; it is legal (though odd) to say // delegate void D(Invoke x); @@ -2316,11 +2548,16 @@ private void CheckTypeParameterNameConflicts(BindingDiagnosticBag diagnostics) } } - private void CheckAccessorNameConflicts(BindingDiagnosticBag diagnostics) + private static void CheckAccessorNameConflicts( + SourceMemberContainerTypeSymbol containerForDiagnostics, + bool mightHaveMembersFromDistinctNonPartialDeclarations, + Dictionary, ImmutableArray> membersByName, + ImmutableArray membersUnordered, + BindingDiagnosticBag diagnostics) { // Report errors where property and event accessors // conflict with other members of the same name. - foreach (Symbol symbol in this.GetMembersUnordered()) + foreach (Symbol symbol in membersUnordered) { if (symbol.IsExplicitInterfaceImplementation()) { @@ -2333,15 +2570,15 @@ private void CheckAccessorNameConflicts(BindingDiagnosticBag diagnostics) case SymbolKind.Property: { var propertySymbol = (PropertySymbol)symbol; - this.CheckForMemberConflictWithPropertyAccessor(propertySymbol, getNotSet: true, diagnostics: diagnostics); - this.CheckForMemberConflictWithPropertyAccessor(propertySymbol, getNotSet: false, diagnostics: diagnostics); + CheckForMemberConflictWithPropertyAccessor(containerForDiagnostics, mightHaveMembersFromDistinctNonPartialDeclarations, membersByName, propertySymbol, getNotSet: true, diagnostics: diagnostics); + CheckForMemberConflictWithPropertyAccessor(containerForDiagnostics, mightHaveMembersFromDistinctNonPartialDeclarations, membersByName, propertySymbol, getNotSet: false, diagnostics: diagnostics); break; } case SymbolKind.Event: { var eventSymbol = (EventSymbol)symbol; - this.CheckForMemberConflictWithEventAccessor(eventSymbol, isAdder: true, diagnostics: diagnostics); - this.CheckForMemberConflictWithEventAccessor(eventSymbol, isAdder: false, diagnostics: diagnostics); + CheckForMemberConflictWithEventAccessor(containerForDiagnostics, mightHaveMembersFromDistinctNonPartialDeclarations, membersByName, eventSymbol, isAdder: true, diagnostics: diagnostics); + CheckForMemberConflictWithEventAccessor(containerForDiagnostics, mightHaveMembersFromDistinctNonPartialDeclarations, membersByName, eventSymbol, isAdder: false, diagnostics: diagnostics); break; } } @@ -2454,7 +2691,7 @@ private void CheckForProtectedInStaticClass(BindingDiagnosticBag diagnostics) continue; } - if (member.DeclaredAccessibility.HasProtected()) + if (member.DeclaredAccessibility.HasProtected() && member is not SourceExtensionImplementationMethodSymbol) { if (member.Kind != SymbolKind.Method || ((MethodSymbol)member).MethodKind != MethodKind.Destructor) { @@ -2846,13 +3083,13 @@ static bool hasInstanceData(MemberDeclarationSyntax m) private static bool All(SyntaxList list, Func predicate) where T : CSharpSyntaxNode { - foreach (var t in list) { if (predicate(t)) return true; }; + foreach (var t in list) { if (predicate(t)) return true; } return false; } private static bool ContainsModifier(SyntaxTokenList modifiers, SyntaxKind modifier) { - foreach (var m in modifiers) { if (m.IsKind(modifier)) return true; }; + foreach (var m in modifiers) { if (m.IsKind(modifier)) return true; } return false; } @@ -3444,9 +3681,9 @@ internal IEnumerable GetMethodsPossiblyCapturingPrimar } else { - var membersAndInituializers = GetMembersAndInitializers(); - nonTypeMembersToCheck = membersAndInituializers.NonTypeMembers; - primaryConstructor = membersAndInituializers.PrimaryConstructor; + var membersAndInitializers = GetMembersAndInitializers(); + nonTypeMembersToCheck = membersAndInitializers.NonTypeMembers; + primaryConstructor = membersAndInitializers.PrimaryConstructor; } Debug.Assert(primaryConstructor is not null); @@ -3489,9 +3726,9 @@ internal ImmutableArray GetMembersToMatchAgainstDeclarationSpan() } else { - var membersAndInituializers = GetMembersAndInitializers(); - Debug.Assert(membersAndInituializers.PrimaryConstructor is not null); - return membersAndInituializers.NonTypeMembers; + var membersAndInitializers = GetMembersAndInitializers(); + Debug.Assert(membersAndInitializers.PrimaryConstructor is not null); + return membersAndInitializers.NonTypeMembers; } } @@ -3514,9 +3751,9 @@ internal ImmutableArray GetCandidateMembersForLookup(string name) } else { - var membersAndInituializers = GetMembersAndInitializers(); - nonTypeMembersToCheck = membersAndInituializers.NonTypeMembers; - primaryConstructor = membersAndInituializers.PrimaryConstructor; + var membersAndInitializers = GetMembersAndInitializers(); + nonTypeMembersToCheck = membersAndInitializers.NonTypeMembers; + primaryConstructor = membersAndInitializers.PrimaryConstructor; } Debug.Assert(primaryConstructor is not null); @@ -3568,6 +3805,15 @@ private void AddSynthesizedMembers(MembersAndInitializersBuilder builder, Declar case TypeKind.Submission: AddSynthesizedTypeMembersIfNecessary(builder, declaredMembersAndInitializers, diagnostics); AddSynthesizedConstructorsIfNecessary(builder, declaredMembersAndInitializers, diagnostics); + + if (TypeKind == TypeKind.Class) // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Consider tightening this check to only top-level non-generic static classes, however optimizing for error scenarios is usually not a goal. + { + AddSynthesizedExtensionImplementationsIfNecessary(builder, declaredMembersAndInitializers); + } + break; + + case TypeKind.Extension: + AddSynthesizedExtensionMarker(builder, declaredMembersAndInitializers); break; default: @@ -3577,6 +3823,38 @@ private void AddSynthesizedMembers(MembersAndInitializersBuilder builder, Declar AddSynthesizedTupleMembersIfNecessary(builder, declaredMembersAndInitializers); } + private void AddSynthesizedExtensionImplementationsIfNecessary(MembersAndInitializersBuilder builder, DeclaredMembersAndInitializers declaredMembersAndInitializers) + { + foreach (var type in GetTypeMembers("")) + { + if (type.TypeKind == TypeKind.Extension) + { + foreach (var member in type.GetMembers()) + { + if (member is MethodSymbol { IsImplicitlyDeclared: false, MethodKind: not (MethodKind.Constructor or MethodKind.StaticConstructor or MethodKind.Destructor or MethodKind.ExplicitInterfaceImplementation) } method && + (method.IsStatic || type.ExtensionParameter is not null)) + { + builder.AddNonTypeMember(this, new SourceExtensionImplementationMethodSymbol(method), declaredMembersAndInitializers); + } + } + } + } + } + + private void AddSynthesizedExtensionMarker(MembersAndInitializersBuilder builder, DeclaredMembersAndInitializers declaredMembersAndInitializers) + { + var marker = CreateSynthesizedExtensionMarker(); + if (marker is not null) + { + builder.AddNonTypeMember(this, marker, declaredMembersAndInitializers); + } + } + + protected virtual MethodSymbol? CreateSynthesizedExtensionMarker() + { + throw ExceptionUtilities.Unreachable(); + } + private void AddDeclaredNontypeMembers(DeclaredMembersAndInitializersBuilder builder, BindingDiagnosticBag diagnostics) { foreach (var decl in this.declaration.Declarations) @@ -3622,6 +3900,7 @@ private void AddDeclaredNontypeMembers(DeclaredMembersAndInitializersBuilder bui case SyntaxKind.StructDeclaration: case SyntaxKind.RecordDeclaration: case SyntaxKind.RecordStructDeclaration: + case SyntaxKind.ExtensionDeclaration: var typeDecl = (TypeDeclarationSyntax)syntax; noteTypeParameters(typeDecl, builder, diagnostics); AddNonTypeMembers(builder, typeDecl.Members, diagnostics); @@ -3641,29 +3920,32 @@ void noteTypeParameters(TypeDeclarationSyntax syntax, DeclaredMembersAndInitiali return; } - if (builder.DeclarationWithParameters is null) + if (!this.IsExtension) { - builder.DeclarationWithParameters = syntax; - var ctor = new SynthesizedPrimaryConstructor(this, syntax); - - if (this.IsStatic) + if (builder.DeclarationWithParameters is null) { - diagnostics.Add(ErrorCode.ERR_ConstructorInStaticClass, syntax.Identifier.GetLocation()); - } + builder.DeclarationWithParameters = syntax; + var ctor = new SynthesizedPrimaryConstructor(this, syntax); - builder.PrimaryConstructor = ctor; + if (this.IsStatic) + { + diagnostics.Add(ErrorCode.ERR_ConstructorInStaticClass, syntax.Identifier.GetLocation()); + } - var compilation = DeclaringCompilation; - builder.UpdateIsNullableEnabledForConstructorsAndFields(ctor.IsStatic, compilation, parameterList); - if (syntax is { PrimaryConstructorBaseTypeIfClass: { ArgumentList: { } baseParamList } }) + builder.PrimaryConstructor = ctor; + + var compilation = DeclaringCompilation; + builder.UpdateIsNullableEnabledForConstructorsAndFields(ctor.IsStatic, compilation, parameterList); + if (syntax is { PrimaryConstructorBaseTypeIfClass: { ArgumentList: { } baseParamList } }) + { + builder.UpdateIsNullableEnabledForConstructorsAndFields(ctor.IsStatic, compilation, baseParamList); + } + } + else { - builder.UpdateIsNullableEnabledForConstructorsAndFields(ctor.IsStatic, compilation, baseParamList); + diagnostics.Add(ErrorCode.ERR_MultipleRecordParameterLists, parameterList.Location); } } - else - { - diagnostics.Add(ErrorCode.ERR_MultipleRecordParameterLists, parameterList.Location); - } } } @@ -3706,14 +3988,24 @@ private static void MergePartialMembers( mergePartialProperties(nonTypeMembers, currentProperty, prevProperty, diagnostics); break; + case (SourceConstructorSymbol { IsStatic: false } currentConstructor, SourceConstructorSymbol { IsStatic: false } prevConstructor): + Debug.Assert(pair.Key.Equals(WellKnownMemberNames.InstanceConstructorName.AsMemory())); + mergePartialConstructors(nonTypeMembers, currentConstructor, prevConstructor, diagnostics); + break; + + case (SourceEventSymbol currentEvent, SourceEventSymbol prevEvent): + mergePartialEvents(nonTypeMembers, currentEvent, prevEvent, diagnostics); + break; + case (SourcePropertyAccessorSymbol, SourcePropertyAccessorSymbol): - break; // accessor symbols and their diagnostics are handled by processing the associated property + case (SourceEventAccessorSymbol, SourceEventAccessorSymbol): + break; // accessor symbols and their diagnostics are handled by processing the associated member default: // This is an error scenario. We simply don't merge the symbols in this case and a duplicate name diagnostic is reported separately. - // One way this case can be reached is if type contains both `public partial int P { get; }` and `public partial int P_get();`. - Debug.Assert(symbol is SourceOrdinaryMethodSymbol or SourcePropertySymbol or SourcePropertyAccessorSymbol); - Debug.Assert(prev is SourceOrdinaryMethodSymbol or SourcePropertySymbol or SourcePropertyAccessorSymbol); + // One way this case can be reached is if type contains both `public partial int P { get; }` and `public partial int get_P();`. + Debug.Assert(symbol is SourceOrdinaryMethodSymbol or SourcePropertySymbol or SourcePropertyAccessorSymbol or SourceEventAccessorSymbol); + Debug.Assert(prev is SourceOrdinaryMethodSymbol or SourcePropertySymbol or SourcePropertyAccessorSymbol or SourceEventAccessorSymbol); break; } } @@ -3751,8 +4043,29 @@ private static void MergePartialMembers( } break; + case SourceConstructorSymbol constructor: + if (constructor.OtherPartOfPartial is null) + { + diagnostics.Add( + constructor.IsPartialDefinition ? ErrorCode.ERR_PartialMemberMissingImplementation : ErrorCode.ERR_PartialMemberMissingDefinition, + constructor.GetFirstLocation(), + constructor); + } + break; + + case SourceEventSymbol ev: + if (ev.OtherPartOfPartial is null) + { + diagnostics.Add( + ev.IsPartialDefinition ? ErrorCode.ERR_PartialMemberMissingImplementation : ErrorCode.ERR_PartialMemberMissingDefinition, + ev.GetFirstLocation(), + ev); + } + break; + + case SourceEventAccessorSymbol: case SourcePropertyAccessorSymbol: - break; // diagnostics for missing partial accessors are handled in 'mergePartialProperties'. + break; // diagnostics for missing partial accessors are handled in 'mergePartialProperties'/'mergePartialEvents'. default: throw ExceptionUtilities.UnexpectedValue(symbol); @@ -3852,6 +4165,60 @@ static bool hasInitializer(SourcePropertySymbol property) return property.DeclaredBackingField?.HasInitializer == true; } } + + static void mergePartialConstructors(ArrayBuilder nonTypeMembers, SourceConstructorSymbol currentConstructor, SourceConstructorSymbol prevConstructor, BindingDiagnosticBag diagnostics) + { + if (currentConstructor.IsPartialImplementation && + (prevConstructor.IsPartialImplementation || (prevConstructor.OtherPartOfPartial is { } otherImplementation && !ReferenceEquals(otherImplementation, currentConstructor)))) + { + // A partial constructor may not have multiple implementing declarations + diagnostics.Add(ErrorCode.ERR_PartialMemberDuplicateImplementation, currentConstructor.GetFirstLocation(), currentConstructor); + } + else if (currentConstructor.IsPartialDefinition && + (prevConstructor.IsPartialDefinition || (prevConstructor.OtherPartOfPartial is { } otherDefinition && !ReferenceEquals(otherDefinition, currentConstructor)))) + { + // A partial constructor may not have multiple defining declarations + diagnostics.Add(ErrorCode.ERR_PartialMemberDuplicateDefinition, currentConstructor.GetFirstLocation(), currentConstructor); + } + else + { + FixPartialConstructor(nonTypeMembers, prevConstructor, currentConstructor); + } + } + + static void mergePartialEvents(ArrayBuilder nonTypeMembers, SourceEventSymbol currentEvent, SourceEventSymbol prevEvent, BindingDiagnosticBag diagnostics) + { + if (currentEvent.IsPartialImplementation && + (prevEvent.IsPartialImplementation || (prevEvent.OtherPartOfPartial is { } otherImplementation && !ReferenceEquals(otherImplementation, currentEvent)))) + { + // A partial event may not have multiple implementing declarations + diagnostics.Add(ErrorCode.ERR_PartialMemberDuplicateImplementation, currentEvent.GetFirstLocation(), currentEvent); + } + else if (currentEvent.IsPartialDefinition && + (prevEvent.IsPartialDefinition || (prevEvent.OtherPartOfPartial is { } otherDefinition && !ReferenceEquals(otherDefinition, currentEvent)))) + { + // A partial event may not have multiple defining declarations + diagnostics.Add(ErrorCode.ERR_PartialMemberDuplicateDefinition, currentEvent.GetFirstLocation(), currentEvent); + } + else + { + mergeAccessors(nonTypeMembers, (SourceEventAccessorSymbol?)currentEvent.AddMethod, (SourceEventAccessorSymbol?)prevEvent.AddMethod); + mergeAccessors(nonTypeMembers, (SourceEventAccessorSymbol?)currentEvent.RemoveMethod, (SourceEventAccessorSymbol?)prevEvent.RemoveMethod); + FixPartialEvent(nonTypeMembers, prevEvent, currentEvent); + } + + static void mergeAccessors(ArrayBuilder nonTypeMembers, SourceEventAccessorSymbol? currentAccessor, SourceEventAccessorSymbol? prevAccessor) + { + if (currentAccessor?.IsPartialImplementation == true) + { + Remove(nonTypeMembers, currentAccessor); + } + else if (prevAccessor?.IsPartialImplementation == true) + { + Remove(nonTypeMembers, prevAccessor); + } + } + } } /// Links together the definition and implementation parts of a partial method. Removes implementation part from . @@ -3904,6 +4271,50 @@ private static void FixPartialProperty(ArrayBuilder nonTypeMembers, Sour Remove(nonTypeMembers, implementation); } + /// Links together the definition and implementation parts of a partial constructor. Removes implementation part from . + private static void FixPartialConstructor(ArrayBuilder nonTypeMembers, SourceConstructorSymbol part1, SourceConstructorSymbol part2) + { + SourceConstructorSymbol definition; + SourceConstructorSymbol implementation; + if (part1.IsPartialDefinition) + { + definition = part1; + implementation = part2; + } + else + { + definition = part2; + implementation = part1; + } + + SourceConstructorSymbol.InitializePartialConstructorParts(definition, implementation); + + // a partial constructor is represented in the member list by its definition part: + Remove(nonTypeMembers, implementation); + } + + /// Links together the definition and implementation parts of a partial event. Removes implementation part from . + private static void FixPartialEvent(ArrayBuilder nonTypeMembers, SourceEventSymbol part1, SourceEventSymbol part2) + { + SourceEventSymbol definition; + SourceEventSymbol implementation; + if (part1.IsPartialDefinition) + { + definition = part1; + implementation = part2; + } + else + { + definition = part2; + implementation = part1; + } + + SourceEventSymbol.InitializePartialEventParts(definition, implementation); + + // a partial event is represented in the member list by its definition part: + Remove(nonTypeMembers, implementation); + } + private static void Remove(ArrayBuilder symbols, Symbol symbol) { for (int i = 0; i < symbols.Count; i++) @@ -3923,7 +4334,10 @@ private static void Remove(ArrayBuilder symbols, Symbol symbol) /// Report an error if a member (other than a method) exists with the same name /// as the property accessor, or if a method exists with the same name and signature. /// - private void CheckForMemberConflictWithPropertyAccessor( + private static void CheckForMemberConflictWithPropertyAccessor( + SourceMemberContainerTypeSymbol containerForDiagnostics, + bool mightHaveMembersFromDistinctNonPartialDeclarations, + Dictionary, ImmutableArray> membersByName, PropertySymbol propertySymbol, bool getNotSet, BindingDiagnosticBag diagnostics) @@ -3944,13 +4358,13 @@ private void CheckForMemberConflictWithPropertyAccessor( propertySymbol.IsCompilationOutputWinMdObj()); } - foreach (var symbol in GetMembers(accessorName)) + foreach (var symbol in membersByName.TryGetValue(accessorName.AsMemory(), out var members) ? members : []) { if (symbol.Kind != SymbolKind.Method) { // The type '{0}' already contains a definition for '{1}' - if (Locations.Length == 1 || IsPartial) - diagnostics.Add(ErrorCode.ERR_DuplicateNameInClass, GetAccessorOrPropertyLocation(propertySymbol, getNotSet), this, accessorName); + if (!mightHaveMembersFromDistinctNonPartialDeclarations) + diagnostics.Add(ErrorCode.ERR_DuplicateNameInClass, GetAccessorOrPropertyLocation(propertySymbol, getNotSet), containerForDiagnostics, accessorName); return; } else @@ -3960,7 +4374,7 @@ private void CheckForMemberConflictWithPropertyAccessor( ParametersMatchPropertyAccessor(propertySymbol, getNotSet, methodSymbol.Parameters)) { // Type '{1}' already reserves a member called '{0}' with the same parameter types - diagnostics.Add(ErrorCode.ERR_MemberReserved, GetAccessorOrPropertyLocation(propertySymbol, getNotSet), accessorName, this); + diagnostics.Add(ErrorCode.ERR_MemberReserved, GetAccessorOrPropertyLocation(propertySymbol, getNotSet), accessorName, containerForDiagnostics); return; } } @@ -3971,7 +4385,10 @@ private void CheckForMemberConflictWithPropertyAccessor( /// Report an error if a member (other than a method) exists with the same name /// as the event accessor, or if a method exists with the same name and signature. /// - private void CheckForMemberConflictWithEventAccessor( + private static void CheckForMemberConflictWithEventAccessor( + SourceMemberContainerTypeSymbol containerForDiagnostics, + bool mightHaveMembersFromDistinctNonPartialDeclarations, + Dictionary, ImmutableArray> membersByName, EventSymbol eventSymbol, bool isAdder, BindingDiagnosticBag diagnostics) @@ -3980,13 +4397,13 @@ private void CheckForMemberConflictWithEventAccessor( string accessorName = SourceEventSymbol.GetAccessorName(eventSymbol.Name, isAdder); - foreach (var symbol in GetMembers(accessorName)) + foreach (var symbol in membersByName.TryGetValue(accessorName.AsMemory(), out var members) ? members : []) { if (symbol.Kind != SymbolKind.Method) { // The type '{0}' already contains a definition for '{1}' - if (Locations.Length == 1 || IsPartial) - diagnostics.Add(ErrorCode.ERR_DuplicateNameInClass, GetAccessorOrEventLocation(eventSymbol, isAdder), this, accessorName); + if (!mightHaveMembersFromDistinctNonPartialDeclarations) + diagnostics.Add(ErrorCode.ERR_DuplicateNameInClass, GetAccessorOrEventLocation(eventSymbol, isAdder), containerForDiagnostics, accessorName); return; } else @@ -3996,7 +4413,7 @@ private void CheckForMemberConflictWithEventAccessor( ParametersMatchEventAccessor(eventSymbol, methodSymbol.Parameters)) { // Type '{1}' already reserves a member called '{0}' with the same parameter types - diagnostics.Add(ErrorCode.ERR_MemberReserved, GetAccessorOrEventLocation(eventSymbol, isAdder), accessorName, this); + diagnostics.Add(ErrorCode.ERR_MemberReserved, GetAccessorOrEventLocation(eventSymbol, isAdder), accessorName, containerForDiagnostics); return; } } @@ -4183,6 +4600,59 @@ private static void CheckInterfaceMember(Symbol member, BindingDiagnosticBag dia } } + private static void CheckExtensionMembers(ImmutableArray members, BindingDiagnosticBag diagnostics) + { + foreach (var member in members) + { + checkExtensionMember(member, diagnostics); + } + + return; + + static void checkExtensionMember(Symbol member, BindingDiagnosticBag diagnostics) + { + switch (member.Kind) + { + case SymbolKind.Method: + var meth = (MethodSymbol)member; + switch (meth.MethodKind) + { + case MethodKind.Constructor: + case MethodKind.Conversion: + case MethodKind.UserDefinedOperator: + case MethodKind.Destructor: + case MethodKind.EventAdd: + case MethodKind.EventRemove: + case MethodKind.StaticConstructor: + break; + case MethodKind.ExplicitInterfaceImplementation: + // error, but reported elsewhere + return; + case MethodKind.Ordinary: + case MethodKind.PropertyGet: + case MethodKind.PropertySet: + return; + default: + throw ExceptionUtilities.UnexpectedValue(meth.MethodKind); + } + break; + + case SymbolKind.Property: + return; + + case SymbolKind.Field: + case SymbolKind.Event: + case SymbolKind.NamedType: + break; + + default: + throw ExceptionUtilities.UnexpectedValue(member.Kind); + } + + diagnostics.Add(ErrorCode.ERR_ExtensionDisallowsMember, member.GetFirstLocation()); + } + } + private static void CheckForStructDefaultConstructors( ArrayBuilder members, bool isEnum, @@ -4317,6 +4787,11 @@ private void AddSynthesizedTypeMembersIfNecessary(MembersAndInitializersBuilder Debug.Assert(ctor is object); members.Add(ctor); + if (!memberSignatures.ContainsKey(ctor)) + { + memberSignatures.Add(ctor, ctor); + } + if (ctor.ParameterCount != 0) { // properties and Deconstruct @@ -4332,7 +4807,7 @@ private void AddSynthesizedTypeMembersIfNecessary(MembersAndInitializersBuilder if (isRecordClass) { - addCopyCtor(primaryAndCopyCtorAmbiguity); + addCopyCtor(primaryAndCopyCtorAmbiguity, declaredMembersAndInitializers); addCloneMethod(); } @@ -4419,7 +4894,7 @@ void addDeconstruct(SynthesizedPrimaryConstructor ctor, ImmutableArray p } } - void addCopyCtor(bool primaryAndCopyCtorAmbiguity) + void addCopyCtor(bool primaryAndCopyCtorAmbiguity, DeclaredMembersAndInitializers declaredMembersAndInitializers) { Debug.Assert(isRecordClass); var targetMethod = new SignatureOnlyMethodSymbol( @@ -4456,7 +4931,11 @@ void addCopyCtor(bool primaryAndCopyCtorAmbiguity) { var constructor = (MethodSymbol)existingConstructor; - if (!this.IsSealed && (constructor.DeclaredAccessibility != Accessibility.Public && constructor.DeclaredAccessibility != Accessibility.Protected)) + if ((object)constructor == declaredMembersAndInitializers.PrimaryConstructor && primaryAndCopyCtorAmbiguity) + { + diagnostics.Add(ErrorCode.ERR_RecordAmbigCtor, this.GetFirstLocation()); + } + else if (!this.IsSealed && (constructor.DeclaredAccessibility != Accessibility.Public && constructor.DeclaredAccessibility != Accessibility.Protected)) { diagnostics.Add(ErrorCode.ERR_CopyConstructorWrongAccessibility, constructor.GetFirstLocation(), constructor); } @@ -5200,8 +5679,8 @@ private void AddNonTypeMembers( } } - Debug.Assert((object)@event.AddMethod != null); - Debug.Assert((object)@event.RemoveMethod != null); + Debug.Assert(@event.IsPartial || @event.AddMethod is not null); + Debug.Assert(@event.IsPartial || @event.RemoveMethod is not null); AddAccessorIfAvailable(builder.NonTypeMembersWithPartialImplementations, @event.AddMethod); AddAccessorIfAvailable(builder.NonTypeMembersWithPartialImplementations, @event.RemoveMethod); @@ -5456,7 +5935,8 @@ internal bool ContainsExtensionMethods { if (!_lazyContainsExtensionMethods.HasValue()) { - bool containsExtensionMethods = ((this.IsStatic && !this.IsGenericType) || this.IsScriptClass) && this.declaration.ContainsExtensionMethods; + bool containsExtensionMethods = ((this.IsStatic && !this.IsGenericType) || this.IsScriptClass) && + (this.declaration.ContainsExtensionMethods || this.declaration.ContainsExtensionDeclarations); _lazyContainsExtensionMethods = containsExtensionMethods.ToThreeState(); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs index 33474e9b9d792..a1c218672234b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs @@ -509,9 +509,10 @@ private void CheckMembersAgainstBaseType( switch (this.TypeKind) { - // These checks don't make sense for enums and delegates: + // These checks don't make sense for enums, delegates or extensions: case TypeKind.Enum: case TypeKind.Delegate: + case TypeKind.Extension: return; case TypeKind.Class: diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs index 792385eafbda8..9f179a98f89be 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs @@ -193,7 +193,7 @@ internal static DeclarationModifiers MakeModifiers(NamedTypeSymbol containingTyp var errorLocation = new SourceLocation(firstIdentifier); DeclarationModifiers result = ModifierUtils.MakeAndCheckNonTypeMemberModifiers( isOrdinaryMethod: false, isForInterfaceMember: isInterface, - modifiers, defaultAccess, allowedModifiers, errorLocation, diagnostics, out modifierErrors); + modifiers, defaultAccess, allowedModifiers, errorLocation, diagnostics, out modifierErrors, out _); if ((result & DeclarationModifiers.Abstract) != 0) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs index fc43f0601c28c..94ffe236219c3 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs @@ -24,7 +24,7 @@ protected struct Flags { // We currently pack everything into a 32 bit int with the following layout: // - // | |t|a|b|e|n|vvv|yy|s|r|q|z|kkk|wwwww| + // | |m|t|a|b|e|n|vvv|yy|s|r|q|z|kkk|wwwww| // // w = method kind. 5 bits. // k = ref kind. 3 bits. @@ -39,6 +39,7 @@ protected struct Flags // b = HasAnyBody. 1 bit. // a = IsVararg. 1 bit. // t = HasThisInitializer. 1 bit. + // m = HasExplicitAccessModifier. 1 bit. private int _flags; private const int MethodKindOffset = 0; @@ -81,8 +82,11 @@ protected struct Flags private const int IsVarargSize = 1; private const int HasThisInitializerOffset = IsVarargOffset + IsVarargSize; -#pragma warning disable IDE0051 // Remove unused private members private const int HasThisInitializerSize = 1; + + private const int HasExplicitAccessModifierOffset = HasThisInitializerOffset + HasThisInitializerSize; +#pragma warning disable IDE0051 // Remove unused private members + private const int HasExplicitAccessModifierSize = 1; #pragma warning restore IDE0051 // Remove unused private members private const int HasAnyBodyBit = 1 << HasAnyBodyOffset; @@ -93,6 +97,7 @@ protected struct Flags private const int IsMetadataVirtualLockedBit = 1 << IsMetadataVirtualLockedOffset; private const int IsVarargBit = 1 << IsVarargOffset; private const int HasThisInitializerBit = 1 << HasThisInitializerOffset; + private const int HasExplicitAccessModifierBit = 1 << HasExplicitAccessModifierOffset; private const int ReturnsVoidBit = 1 << ReturnsVoidOffset; private const int ReturnsVoidIsSetBit = 1 << ReturnsVoidOffset + 1; @@ -161,6 +166,9 @@ public bool IsVararg public readonly bool HasThisInitializer => (_flags & HasThisInitializerBit) != 0; + public readonly bool HasExplicitAccessModifier + => (_flags & HasExplicitAccessModifierBit) != 0; + #if DEBUG static Flags() { @@ -188,7 +196,8 @@ public Flags( bool isNullableAnalysisEnabled, bool isVararg, bool isExplicitInterfaceImplementation, - bool hasThisInitializer) + bool hasThisInitializer, + bool hasExplicitAccessModifier) { Debug.Assert(!returnsVoid || returnsVoidIsSet); @@ -204,6 +213,7 @@ public Flags( int isMetadataVirtualIgnoringInterfaceImplementationChangesInt = isMetadataVirtual ? IsMetadataVirtualIgnoringInterfaceChangesBit : 0; int isMetadataVirtualInt = isMetadataVirtual ? IsMetadataVirtualBit : 0; int hasThisInitializerInt = hasThisInitializer ? HasThisInitializerBit : 0; + int hasExplicitAccessModifierInt = hasExplicitAccessModifier ? HasExplicitAccessModifierBit : 0; _flags = methodKindInt | refKindInt @@ -215,6 +225,7 @@ public Flags( | isMetadataVirtualIgnoringInterfaceImplementationChangesInt | isMetadataVirtualInt | hasThisInitializerInt + | hasExplicitAccessModifierInt | (returnsVoid ? ReturnsVoidBit : 0) | (returnsVoidIsSet ? ReturnsVoidIsSetBit : 0); } @@ -242,7 +253,8 @@ public Flags( isNullableAnalysisEnabled: isNullableAnalysisEnabled, isVararg: isVararg, isExplicitInterfaceImplementation: isExplicitInterfaceImplementation, - hasThisInitializer: hasThisInitializer) + hasThisInitializer: hasThisInitializer, + hasExplicitAccessModifier: false) { } @@ -366,26 +378,42 @@ protected void CheckEffectiveAccessibility(TypeWithAnnotations returnType, Immut } } + if (!IsStatic && this.GetIsNewExtensionMember() && ContainingType.ExtensionParameter is { } extensionParameter) + { + if (!extensionParameter.TypeWithAnnotations.IsAtLeastAsVisibleAs(this, ref useSiteInfo)) + { + // Inconsistent accessibility: parameter type '{1}' is less accessible than method '{0}' + diagnostics.Add(code, GetFirstLocation(), this, extensionParameter.Type); + } + } + diagnostics.Add(GetFirstLocation(), useSiteInfo); } protected void CheckFileTypeUsage(TypeWithAnnotations returnType, ImmutableArray parameters, BindingDiagnosticBag diagnostics) { - if (ContainingType.HasFileLocalTypes()) + NamedTypeSymbol containingType = ContainingType; + + if (containingType is { IsExtension: true, ContainingType: { } enclosing }) + { + containingType = enclosing; + } + + if (containingType.HasFileLocalTypes()) { return; } if (returnType.Type.HasFileLocalTypes()) { - diagnostics.Add(ErrorCode.ERR_FileTypeDisallowedInSignature, GetFirstLocation(), returnType.Type, ContainingType); + diagnostics.Add(ErrorCode.ERR_FileTypeDisallowedInSignature, GetFirstLocation(), returnType.Type, containingType); } foreach (var param in parameters) { if (param.Type.HasFileLocalTypes()) { - diagnostics.Add(ErrorCode.ERR_FileTypeDisallowedInSignature, GetFirstLocation(), param.Type, ContainingType); + diagnostics.Add(ErrorCode.ERR_FileTypeDisallowedInSignature, GetFirstLocation(), param.Type, containingType); } } } @@ -531,7 +559,7 @@ public sealed override MethodKind MethodKind } } - public override bool IsExtensionMethod + public sealed override bool IsExtensionMethod { get { @@ -1005,74 +1033,6 @@ internal override bool IsNullableAnalysisEnabled() return flags.IsNullableAnalysisEnabled; } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) - { - base.AddSynthesizedAttributes(moduleBuilder, ref attributes); - - if (IsDeclaredReadOnly && !ContainingType.IsReadOnly) - { - AddSynthesizedAttribute(ref attributes, moduleBuilder.SynthesizeIsReadOnlyAttribute(this)); - } - - var compilation = this.DeclaringCompilation; - - if (compilation.ShouldEmitNullableAttributes(this) && - ShouldEmitNullableContextValue(out byte nullableContextValue)) - { - AddSynthesizedAttribute(ref attributes, moduleBuilder.SynthesizeNullableContextAttribute(this, nullableContextValue)); - } - - if (this.RequiresExplicitOverride(out _)) - { - // On platforms where it is present, add PreserveBaseOverridesAttribute when a methodimpl is used to override a class method. - AddSynthesizedAttribute(ref attributes, moduleBuilder.SynthesizePreserveBaseOverridesAttribute()); - } - - bool isAsync = this.IsAsync; - bool isIterator = this.IsIterator; - - if (!isAsync && !isIterator) - { - return; - } - - // The async state machine type is not synthesized until the async method body is rewritten. If we are - // only emitting metadata the method body will not have been rewritten, and the async state machine - // type will not have been created. In this case, omit the attribute. - if (moduleBuilder.CompilationState.TryGetStateMachineType(this, out NamedTypeSymbol stateMachineType)) - { - var arg = new TypedConstant(compilation.GetWellKnownType(WellKnownType.System_Type), - TypedConstantKind.Type, stateMachineType.GetUnboundGenericTypeOrSelf()); - - if (isAsync && isIterator) - { - AddSynthesizedAttribute(ref attributes, - compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_AsyncIteratorStateMachineAttribute__ctor, - ImmutableArray.Create(arg))); - } - else if (isAsync) - { - AddSynthesizedAttribute(ref attributes, - compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor, - ImmutableArray.Create(arg))); - } - else if (isIterator) - { - AddSynthesizedAttribute(ref attributes, - compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_IteratorStateMachineAttribute__ctor, - ImmutableArray.Create(arg))); - } - } - - if (isAsync && !isIterator) - { - // Regular async (not async-iterator) kick-off method calls MoveNext, which contains user code. - // This means we need to emit DebuggerStepThroughAttribute in order - // to have correct stepping behavior during debugging. - AddSynthesizedAttribute(ref attributes, compilation.SynthesizeDebuggerStepThroughAttribute()); - } - } - /// /// Checks to see if a body is legal given the current modifiers. /// If it is not, a diagnostic is added with the current type. diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbol.cs index 3f0597c402e65..63f85869f0c4d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbol.cs @@ -3,8 +3,11 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; +using System.Diagnostics; using System.Linq; +using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Symbols @@ -88,5 +91,131 @@ internal override bool HasAsyncMethodBuilderAttribute(out TypeSymbol? builderArg { return SourceMemberContainerTypeSymbol.HasAsyncMethodBuilderAttribute(this, out builderArgument); } + + internal sealed override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + { + base.AddSynthesizedAttributes(moduleBuilder, ref attributes); + AddSynthesizedAttributes(this, moduleBuilder, ref attributes); + } + + internal static void AddSynthesizedAttributes(MethodSymbol target, PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + { + Debug.Assert(target is not (LambdaSymbol or LocalFunctionSymbol)); + + if (target.IsDeclaredReadOnly && !target.ContainingType.IsReadOnly) + { + AddSynthesizedAttribute(ref attributes, moduleBuilder.SynthesizeIsReadOnlyAttribute(target)); + } + + var compilation = target.DeclaringCompilation; + + if (compilation.ShouldEmitNullableAttributes(target) && + target.ShouldEmitNullableContextValue(out byte nullableContextValue)) + { + AddSynthesizedAttribute(ref attributes, moduleBuilder.SynthesizeNullableContextAttribute(target, nullableContextValue)); + } + + if (target.RequiresExplicitOverride(out _)) + { + // On platforms where it is present, add PreserveBaseOverridesAttribute when a methodimpl is used to override a class method. + AddSynthesizedAttribute(ref attributes, moduleBuilder.SynthesizePreserveBaseOverridesAttribute()); + } + + bool isAsync = target.IsAsync; + bool isIterator = target.IsIterator; + + if ((isAsync || isIterator) && !target.GetIsNewExtensionMember()) + { + // The async state machine type is not synthesized until the async method body is rewritten. If we are + // only emitting metadata the method body will not have been rewritten, and the async state machine + // type will not have been created. In this case, omit the attribute. + + if (moduleBuilder.CompilationState.TryGetStateMachineType(target, out NamedTypeSymbol? stateMachineType)) + { + var arg = new TypedConstant(compilation.GetWellKnownType(WellKnownType.System_Type), + TypedConstantKind.Type, stateMachineType.GetUnboundGenericTypeOrSelf()); + + if (isAsync && isIterator) + { + AddSynthesizedAttribute(ref attributes, + compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_AsyncIteratorStateMachineAttribute__ctor, + ImmutableArray.Create(arg))); + } + else if (isAsync) + { + AddSynthesizedAttribute(ref attributes, + compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor, + ImmutableArray.Create(arg))); + } + else if (isIterator) + { + AddSynthesizedAttribute(ref attributes, + compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_IteratorStateMachineAttribute__ctor, + ImmutableArray.Create(arg))); + } + } + + if (isAsync && !isIterator) + { + // Regular async (not async-iterator) kick-off method calls MoveNext, which contains user code. + // This means we need to emit DebuggerStepThroughAttribute in order + // to have correct stepping behavior during debugging. + AddSynthesizedAttribute(ref attributes, compilation.SynthesizeDebuggerStepThroughAttribute()); + } + } + + // Do not generate CompilerGeneratedAttribute for members of compiler-generated types: + if (((target.IsImplicitlyDeclared && target is not SourceFieldLikeEventSymbol.SourceEventDefinitionAccessorSymbol { PartialImplementationPart.IsImplicitlyDeclared: false }) || + target is SourcePropertyAccessorSymbol { IsAutoPropertyAccessor: true }) && + !target.ContainingType.IsImplicitlyDeclared && + target is SynthesizedMethodBaseSymbol or + SourcePropertyAccessorSymbol or + SynthesizedSourceOrdinaryMethodSymbol or + SynthesizedRecordEqualityOperatorBase or + SynthesizedEventAccessorSymbol or + SourceFieldLikeEventSymbol.SourceEventDefinitionAccessorSymbol) + { + Debug.Assert(WellKnownMembers.IsSynthesizedAttributeOptional(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor)); + AddSynthesizedAttribute(ref attributes, + compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor)); + } + + if (target is SourceConstructorSymbolBase) + { + AddRequiredMembersMarkerAttributes(ref attributes, target); + } + + if (target.IsExtensionMethod) + { + // No need to check if [Extension] attribute was explicitly set since + // we'll issue CS1112 error in those cases and won't generate IL. + AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute( + WellKnownMember.System_Runtime_CompilerServices_ExtensionAttribute__ctor)); + } + + if (target is SourcePropertyAccessorSymbol { AssociatedSymbol: SourcePropertySymbolBase property }) + { + if (!target.NotNullMembers.IsEmpty) + { + foreach (var attributeData in property.MemberNotNullAttributeIfExists) + { + AddSynthesizedAttribute(ref attributes, SynthesizedAttributeData.Create(attributeData)); + } + } + + if (!target.NotNullWhenTrueMembers.IsEmpty || !target.NotNullWhenFalseMembers.IsEmpty) + { + foreach (var attributeData in property.MemberNotNullWhenAttributeIfExists) + { + AddSynthesizedAttribute(ref attributes, SynthesizedAttributeData.Create(attributeData)); + } + } + } + + if (target is MethodToClassRewriter.BaseMethodWrapperSymbol) + { + AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute(WellKnownMember.System_Diagnostics_DebuggerHiddenAttribute__ctor)); + } + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs index 7fa6d895a89b5..ddd951ad2b8d4 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs @@ -83,6 +83,7 @@ internal SourceNamedTypeSymbol(NamespaceOrTypeSymbol containingSymbol, MergedTyp case DeclarationKind.Class: case DeclarationKind.Record: case DeclarationKind.RecordStruct: + case DeclarationKind.Extension: break; default: Debug.Assert(false, "bad declaration kind"); @@ -162,6 +163,7 @@ private ImmutableArray MakeTypeParameters(BindingDiagnostic case SyntaxKind.InterfaceDeclaration: case SyntaxKind.RecordDeclaration: case SyntaxKind.RecordStructDeclaration: + case SyntaxKind.ExtensionDeclaration: tpl = ((TypeDeclarationSyntax)typeDecl).TypeParameterList; break; @@ -471,6 +473,7 @@ private static SyntaxList GetConstraintClau case SyntaxKind.InterfaceDeclaration: case SyntaxKind.RecordDeclaration: case SyntaxKind.RecordStructDeclaration: + case SyntaxKind.ExtensionDeclaration: var typeDeclaration = (TypeDeclarationSyntax)node; typeParameterList = typeDeclaration.TypeParameterList; return typeDeclaration.ConstraintClauses; @@ -1812,6 +1815,16 @@ internal bool IsSimpleProgram } } + public override string MetadataName + { + get + { + return IsExtension + ? MetadataHelpers.ComposeAritySuffixedMetadataName(this.ExtensionName, Arity, associatedFileIdentifier: null) + : base.MetadataName; + } + } + protected override void AfterMembersCompletedChecks(BindingDiagnosticBag diagnostics) { base.AfterMembersCompletedChecks(diagnostics); @@ -1964,6 +1977,16 @@ protected override void AfterMembersCompletedChecks(BindingDiagnosticBag diagnos } } + + if (IsExtension && ContainingType?.IsExtension != true) + { + // If the containing type is an extension, we'll have already reported an error + if (ContainingType is null || !ContainingType.IsStatic || ContainingType.Arity != 0 || ContainingType.ContainingType is not null) + { + var syntax = (ExtensionDeclarationSyntax)this.GetNonNullSyntaxNode(); + diagnostics.Add(ErrorCode.ERR_BadExtensionContainingType, syntax.Keyword); + } + } } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol_Bases.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol_Bases.cs index c6aef2c70456b..c4ba746250eeb 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol_Bases.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol_Bases.cs @@ -716,6 +716,10 @@ private NamedTypeSymbol MakeAcyclicBaseType(BindingDiagnosticBag diagnostics) Debug.Assert((object)GetDeclaredBaseType(basesBeingResolved: null) == null, "Computation skipped for enums"); declaredBase = compilation.GetSpecialType(SpecialType.System_Enum); } + else if (typeKind == TypeKind.Extension) + { + return null; + } else { declaredBase = GetDeclaredBaseType(basesBeingResolved: null); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol_Extension.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol_Extension.cs new file mode 100644 index 0000000000000..03182aa0738b8 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol_Extension.cs @@ -0,0 +1,216 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.Symbols +{ + internal partial class SourceNamedTypeSymbol + { + private ExtensionInfo _lazyExtensionInfo; + + private class ExtensionInfo + { + public MethodSymbol? LazyExtensionMarker = ErrorMethodSymbol.UnknownMethod; + public ParameterSymbol? LazyExtensionParameter; + public ImmutableDictionary? LazyImplementationMap; + } + + internal override string ExtensionName + { + get + { + if (!IsExtension) + { + throw ExceptionUtilities.Unreachable(); + } + + MergedNamespaceOrTypeDeclaration declaration; + if (ContainingType is not null) + { + declaration = ((SourceNamedTypeSymbol)this.ContainingType).declaration; + } + else + { + declaration = ((SourceNamespaceSymbol)this.ContainingSymbol).MergedDeclaration; + } + + var index = declaration.Children.IndexOf(this.declaration); + return GeneratedNames.MakeExtensionName(index); + } + } + + internal sealed override ParameterSymbol? ExtensionParameter + { + get + { + if (!IsExtension) + { + return null; + } + + var markerMethod = TryGetOrCreateExtensionMarker(); + + if (_lazyExtensionInfo.LazyExtensionParameter == null && markerMethod is { Parameters: [var parameter, ..] }) + { + Interlocked.CompareExchange(ref _lazyExtensionInfo.LazyExtensionParameter, new ReceiverParameterSymbol(this, parameter), null); + } + + return _lazyExtensionInfo.LazyExtensionParameter; + } + } + + public sealed override MethodSymbol? TryGetCorrespondingExtensionImplementationMethod(MethodSymbol method) + { + Debug.Assert(this.IsExtension); + Debug.Assert(method.IsDefinition); + Debug.Assert(method.ContainingType == (object)this); + + var containingType = this.ContainingType; + + if (containingType is null) + { + return null; // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Test this code path + } + + if (_lazyExtensionInfo is null) + { + Interlocked.CompareExchange(ref _lazyExtensionInfo, new ExtensionInfo(), null); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Test this code path + } + + if (_lazyExtensionInfo.LazyImplementationMap is null) + { + var builder = ImmutableDictionary.CreateBuilder(Roslyn.Utilities.ReferenceEqualityComparer.Instance); + + builder.AddRange( + containingType.GetMembersUnordered().OfType(). + Select(static m => new KeyValuePair(m.UnderlyingMethod, m))); + + Interlocked.CompareExchange(ref _lazyExtensionInfo.LazyImplementationMap, builder.ToImmutable(), null); + } + + return _lazyExtensionInfo.LazyImplementationMap.GetValueOrDefault(method); + } + + protected sealed override MethodSymbol? CreateSynthesizedExtensionMarker() + { + return TryGetOrCreateExtensionMarker(); + } + + [MemberNotNull(nameof(_lazyExtensionInfo))] + private MethodSymbol? TryGetOrCreateExtensionMarker() + { + Debug.Assert(IsExtension); + + if (_lazyExtensionInfo is null) + { + Interlocked.CompareExchange(ref _lazyExtensionInfo, new ExtensionInfo(), null); + } + + if (_lazyExtensionInfo.LazyExtensionMarker == (object)ErrorMethodSymbol.UnknownMethod) + { + Interlocked.CompareExchange(ref _lazyExtensionInfo.LazyExtensionMarker, tryCreateExtensionMarker(), ErrorMethodSymbol.UnknownMethod); + } + + return _lazyExtensionInfo.LazyExtensionMarker; + + MethodSymbol? tryCreateExtensionMarker() + { + var syntax = (ExtensionDeclarationSyntax)this.GetNonNullSyntaxNode(); + var parameterList = syntax.ParameterList; + Debug.Assert(parameterList is not null); + + if (parameterList is null) + { + return null; + } + + int count = parameterList.Parameters.Count; + Debug.Assert(count > 0); + + return new SynthesizedExtensionMarker(this, parameterList); + } + } + + internal static Symbol? GetCompatibleSubstitutedMember(CSharpCompilation compilation, Symbol extensionMember, TypeSymbol receiverType) + { + Debug.Assert(extensionMember.GetIsNewExtensionMember()); + + NamedTypeSymbol extension = extensionMember.ContainingType; + if (extension.ExtensionParameter is null) + { + return null; + } + + Symbol result; + if (extensionMember.IsDefinition) + { + NamedTypeSymbol? constructedExtension = inferExtensionTypeArguments(extension, receiverType, compilation); + if (constructedExtension is null) + { + return null; + } + + result = extensionMember.SymbolAsMember(constructedExtension); + } + else + { + result = extensionMember; + } + + Debug.Assert(result.ContainingType.ExtensionParameter is not null); + var discardedUseSiteInfo = CompoundUseSiteInfo.Discarded; + Conversion conversion = compilation.Conversions.ConvertExtensionMethodThisArg(parameterType: result.ContainingType.ExtensionParameter.Type, receiverType, ref discardedUseSiteInfo, isMethodGroupConversion: false); + if (!conversion.Exists) + { + return null; + } + + return result; + + static NamedTypeSymbol? inferExtensionTypeArguments(NamedTypeSymbol extension, TypeSymbol receiverType, CSharpCompilation compilation) + { + if (extension.Arity == 0) + { + return extension; + } + + TypeConversions conversions = extension.ContainingAssembly.CorLibrary.TypeConversions; + + // Note: we create a value for purpose of inferring type arguments even when the receiver type is static + var syntax = (CSharpSyntaxNode)CSharpSyntaxTree.Dummy.GetRoot(); + var receiverValue = new BoundLiteral(syntax, ConstantValue.Bad, receiverType) { WasCompilerGenerated = true }; + + var discardedUseSiteInfo = CompoundUseSiteInfo.Discarded; + ImmutableArray typeArguments = MethodTypeInferrer.InferTypeArgumentsFromReceiverType(extension, receiverValue, compilation, conversions, ref discardedUseSiteInfo); + if (typeArguments.IsDefault || typeArguments.Any(t => !t.HasType)) + { + return null; + } + + var result = extension.Construct(typeArguments); + + var constraintArgs = new ConstraintsHelper.CheckConstraintsArgs(compilation, conversions, includeNullability: false, + NoLocation.Singleton, diagnostics: BindingDiagnosticBag.Discarded, template: CompoundUseSiteInfo.Discarded); + + bool success = result.CheckConstraints(constraintArgs); + if (!success) + { + return null; + } + + return result; + } + } + } +} diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamespaceSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamespaceSymbol.cs index a02eb45cc149c..ee1bea85c7f90 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamespaceSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamespaceSymbol.cs @@ -313,6 +313,8 @@ private static void CheckMembers(NamespaceSymbol @namespace, Dictionary GetSyntax().ReturnType.Location; internal MethodDeclarationSyntax GetSyntax() @@ -424,7 +429,7 @@ private SyntaxList AttributeDeclarationSyntaxList private static DeclarationModifiers MakeDeclarationModifiers(MethodDeclarationSyntax syntax, NamedTypeSymbol containingType, Location location, DeclarationModifiers allowedModifiers, BindingDiagnosticBag diagnostics) { return ModifierUtils.MakeAndCheckNonTypeMemberModifiers(isOrdinaryMethod: true, isForInterfaceMember: containingType.IsInterface, - syntax.Modifiers, defaultAccess: DeclarationModifiers.None, allowedModifiers, location, diagnostics, out _); + syntax.Modifiers, defaultAccess: DeclarationModifiers.None, allowedModifiers, location, diagnostics, out _, out _); } internal sealed override void ForceComplete(SourceLocation locationOpt, Predicate filter, CancellationToken cancellationToken) @@ -679,10 +684,20 @@ protected override void MethodChecks(BindingDiagnosticBag diagnostics) CheckModifiers(MethodKind == MethodKind.ExplicitInterfaceImplementation, _location, diagnostics); } + + internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, BindingDiagnosticBag diagnostics) + { + base.AfterAddingTypeMembersChecks(conversions, diagnostics); + + if (this.ReturnType?.IsErrorType() == true && GetSyntax().ReturnType is IdentifierNameSyntax { Identifier.RawContextualKind: (int)SyntaxKind.PartialKeyword }) + { + var available = MessageID.IDS_FeaturePartialEventsAndConstructors.CheckFeatureAvailability(diagnostics, DeclaringCompilation, ReturnTypeLocation); + Debug.Assert(!available, "Should have been parsed as partial constructor."); + } + } #nullable disable - // Consider moving this to flags to save space - internal bool HasExplicitAccessModifier { get; } + internal bool HasExplicitAccessModifier => flags.HasExplicitAccessModifier; private static (DeclarationModifiers mods, bool hasExplicitAccessMod) MakeModifiers(MethodDeclarationSyntax syntax, NamedTypeSymbol containingType, MethodKind methodKind, bool hasBody, Location location, BindingDiagnosticBag diagnostics) { @@ -1126,24 +1141,37 @@ private ImmutableArray MakeTypeParameters(MethodDeclaration // Note: It is not an error to have a type parameter named the same as its enclosing method: void M() {} - for (int i = 0; i < result.Count; i++) + var tpEnclosing = ContainingType.FindEnclosingTypeParameter(name); + bool checkForDuplicates = true; + + if ((object)tpEnclosing != null) { - if (name == result[i].Name) + if (tpEnclosing.ContainingSymbol is NamedTypeSymbol { IsExtension: true }) { - diagnostics.Add(ErrorCode.ERR_DuplicateTypeParameter, location, name); - break; + diagnostics.Add(ErrorCode.ERR_TypeParameterSameNameAsExtensionTypeParameter, location, name); + checkForDuplicates = false; + } + else + { + // Type parameter '{0}' has the same name as the type parameter from outer type '{1}' + diagnostics.Add(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, location, name, tpEnclosing.ContainingType); } } - SourceMemberContainerTypeSymbol.ReportReservedTypeName(identifier.Text, this.DeclaringCompilation, diagnostics.DiagnosticBag, location); - - var tpEnclosing = ContainingType.FindEnclosingTypeParameter(name); - if ((object)tpEnclosing != null) + if (checkForDuplicates) { - // Type parameter '{0}' has the same name as the type parameter from outer type '{1}' - diagnostics.Add(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, location, name, tpEnclosing.ContainingType); + for (int i = 0; i < result.Count; i++) + { + if (name == result[i].Name) + { + diagnostics.Add(ErrorCode.ERR_DuplicateTypeParameter, location, name); + break; + } + } } + SourceMemberContainerTypeSymbol.ReportReservedTypeName(identifier.Text, this.DeclaringCompilation, diagnostics.DiagnosticBag, location); + var syntaxRefs = ImmutableArray.Create(parameter.GetReference()); var locations = ImmutableArray.Create(location); var typeParameter = (typeMap != null) ? diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbolBase.cs index ade24d4dcfefe..769d31c34ca28 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbolBase.cs @@ -80,7 +80,7 @@ private void CompleteAsyncMethodChecks(BindingDiagnosticBag diagnosticsOpt, Canc public abstract override string GetDocumentationCommentXml(CultureInfo preferredCulture = null, bool expandIncludes = false, CancellationToken cancellationToken = default(CancellationToken)); - public override string Name + public sealed override string Name { get { @@ -91,20 +91,5 @@ public override string Name protected abstract override SourceMemberMethodSymbol BoundAttributesSource { get; } internal abstract override OneOrMany> GetAttributeDeclarations(); - - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) - { - base.AddSynthesizedAttributes(moduleBuilder, ref attributes); - - if (this.IsExtensionMethod) - { - // No need to check if [Extension] attribute was explicitly set since - // we'll issue CS1112 error in those cases and won't generate IL. - var compilation = this.DeclaringCompilation; - - AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute( - WellKnownMember.System_Runtime_CompilerServices_ExtensionAttribute__ctor)); - } - } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceParameterSymbol.cs index 15c514be372ef..dfe4b4f419760 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceParameterSymbol.cs @@ -44,7 +44,7 @@ public static SourceParameterSymbol Create( Debug.Assert(owner is not LambdaSymbol); // therefore we don't need to deal with discard parameters var name = identifier.ValueText; - var location = new SourceLocation(identifier); + var location = new SourceLocation(name == "" ? syntax.Type : identifier); if (hasParamsModifier && parameterType.IsSZArray()) { @@ -108,7 +108,7 @@ protected SourceParameterSymbol( Location location) : base(owner, ordinal) { - Debug.Assert((owner.Kind == SymbolKind.Method) || (owner.Kind == SymbolKind.Property)); + Debug.Assert((owner.Kind == SymbolKind.Method) || (owner.Kind == SymbolKind.Property) || owner is TypeSymbol { IsExtension: true }); _refKind = refKind; _scope = scope; _name = name; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs index 4c7a1dd16a416..c67c5fc3d1f61 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs @@ -512,7 +512,7 @@ private static DeclarationModifiers MakeModifiers(NamedTypeSymbol containingType } var mods = ModifierUtils.MakeAndCheckNonTypeMemberModifiers(isOrdinaryMethod: false, isForInterfaceMember: isInterface, - modifiers, defaultAccess, allowedModifiers, location, diagnostics, out modifierErrors); + modifiers, defaultAccess, allowedModifiers, location, diagnostics, out modifierErrors, out _); ModifierUtils.ReportDefaultInterfaceImplementationModifiers(hasBody, mods, defaultInterfaceImplementationModifiers, @@ -654,13 +654,16 @@ private SyntaxList AttributeDeclarationList { get { - var syntax = this.GetSyntax(); - switch (syntax.Kind()) + if (this._property.ContainingType is SourceMemberContainerTypeSymbol { AnyMemberHasAttributes: true }) { - case SyntaxKind.GetAccessorDeclaration: - case SyntaxKind.SetAccessorDeclaration: - case SyntaxKind.InitAccessorDeclaration: - return ((AccessorDeclarationSyntax)syntax).AttributeLists; + var syntax = this.GetSyntax(); + switch (syntax.Kind()) + { + case SyntaxKind.GetAccessorDeclaration: + case SyntaxKind.SetAccessorDeclaration: + case SyntaxKind.InitAccessorDeclaration: + return ((AccessorDeclarationSyntax)syntax).AttributeLists; + } } return default; @@ -721,7 +724,7 @@ public sealed override string Name } #nullable disable - public sealed override bool IsImplicitlyDeclared + public override bool IsImplicitlyDeclared { get { @@ -801,33 +804,6 @@ internal sealed override void AddSynthesizedReturnTypeAttributes(PEModuleBuilder } } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) - { - base.AddSynthesizedAttributes(moduleBuilder, ref attributes); - - if (_isAutoPropertyAccessor) - { - var compilation = this.DeclaringCompilation; - AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor)); - } - - if (!NotNullMembers.IsEmpty) - { - foreach (var attributeData in _property.MemberNotNullAttributeIfExists) - { - AddSynthesizedAttribute(ref attributes, SynthesizedAttributeData.Create(attributeData)); - } - } - - if (!NotNullWhenTrueMembers.IsEmpty || !NotNullWhenFalseMembers.IsEmpty) - { - foreach (var attributeData in _property.MemberNotNullWhenAttributeIfExists) - { - AddSynthesizedAttribute(ref attributes, SynthesizedAttributeData.Create(attributeData)); - } - } - } - #nullable enable protected sealed override SourceMemberMethodSymbol? BoundAttributesSource => (SourceMemberMethodSymbol?)PartialDefinitionPart; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs index 9c716dd1fa2bf..b5cd129376f0b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs @@ -199,12 +199,25 @@ public override OneOrMany> GetAttributeDeclarati if (SourcePartialImplementationPart is { } implementationPart) { return OneOrMany.Create( - ((BasePropertyDeclarationSyntax)CSharpSyntaxNode).AttributeLists, - ((BasePropertyDeclarationSyntax)implementationPart.CSharpSyntaxNode).AttributeLists); + this.AttributeDeclarationSyntaxList, + implementationPart.AttributeDeclarationSyntaxList); } else { - return OneOrMany.Create(((BasePropertyDeclarationSyntax)CSharpSyntaxNode).AttributeLists); + return OneOrMany.Create(this.AttributeDeclarationSyntaxList); + } + } + + private SyntaxList AttributeDeclarationSyntaxList + { + get + { + if (this.ContainingType is SourceMemberContainerTypeSymbol { AnyMemberHasAttributes: true }) + { + return ((BasePropertyDeclarationSyntax)this.CSharpSyntaxNode).AttributeLists; + } + + return default; } } @@ -430,20 +443,9 @@ private static (DeclarationModifiers modifiers, bool hasExplicitAccessMod) MakeM allowedModifiers |= DeclarationModifiers.Extern; - // In order to detect whether explicit accessibility mods were provided, we pass the default value - // for 'defaultAccess' and manually add in the 'defaultAccess' flags after the call. bool hasExplicitAccessMod; var mods = ModifierUtils.MakeAndCheckNonTypeMemberModifiers(isOrdinaryMethod: false, isForInterfaceMember: isInterface, - modifiers, defaultAccess: DeclarationModifiers.None, allowedModifiers, location, diagnostics, out modifierErrors); - if ((mods & DeclarationModifiers.AccessibilityMask) == 0) - { - hasExplicitAccessMod = false; - mods |= defaultAccess; - } - else - { - hasExplicitAccessMod = true; - } + modifiers, defaultAccess, allowedModifiers, location, diagnostics, out modifierErrors, out hasExplicitAccessMod); if ((mods & DeclarationModifiers.Partial) != 0) { @@ -574,9 +576,18 @@ private TypeWithAnnotations ComputeType(Binder binder, SyntaxNode syntax, Bindin diagnostics.Add((this.IsIndexer ? ErrorCode.ERR_BadVisIndexerReturn : ErrorCode.ERR_BadVisPropertyType), Location, this, type.Type); } - if (type.Type.HasFileLocalTypes() && !ContainingType.HasFileLocalTypes()) + if (type.Type.HasFileLocalTypes()) { - diagnostics.Add(ErrorCode.ERR_FileTypeDisallowedInSignature, Location, type.Type, ContainingType); + NamedTypeSymbol containingType = ContainingType; + if (containingType is { IsExtension: true, ContainingType: { } enclosing }) + { + containingType = enclosing; + } + + if (!containingType.HasFileLocalTypes()) + { + diagnostics.Add(ErrorCode.ERR_FileTypeDisallowedInSignature, Location, type.Type, containingType); + } } diagnostics.Add(Location, useSiteInfo); @@ -650,15 +661,21 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, var useSiteInfo = new CompoundUseSiteInfo(diagnostics, ContainingAssembly); + var containingTypeForFileTypeCheck = this.ContainingType; + if (containingTypeForFileTypeCheck is { IsExtension: true, ContainingType: { } enclosing }) + { + containingTypeForFileTypeCheck = enclosing; + } + foreach (ParameterSymbol param in Parameters) { if (!IsExplicitInterfaceImplementation && !this.IsNoMoreVisibleThan(param.Type, ref useSiteInfo)) { diagnostics.Add(ErrorCode.ERR_BadVisIndexerParam, Location, this, param.Type); } - else if (param.Type.HasFileLocalTypes() && !this.ContainingType.HasFileLocalTypes()) + else if (param.Type.HasFileLocalTypes() && !containingTypeForFileTypeCheck.HasFileLocalTypes()) { - diagnostics.Add(ErrorCode.ERR_FileTypeDisallowedInSignature, Location, param.Type, this.ContainingType); + diagnostics.Add(ErrorCode.ERR_FileTypeDisallowedInSignature, Location, param.Type, containingTypeForFileTypeCheck); } else if (SetMethod is object && param.Name == ParameterSymbol.ValueParameterName) { @@ -666,6 +683,25 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, } } + if (SetMethod is { } setter && this.GetIsNewExtensionMember()) + { + if (ContainingType.TypeParameters.Any(static tp => tp.Name == ParameterSymbol.ValueParameterName)) + { + diagnostics.Add(ErrorCode.ERR_ValueParameterSameNameAsExtensionTypeParameter, setter.GetFirstLocationOrNone()); + } + + if (ContainingType.ExtensionParameter is { Name: ParameterSymbol.ValueParameterName }) + { + diagnostics.Add(ErrorCode.ERR_ValueParameterSameNameAsExtensionParameter, setter.GetFirstLocationOrNone()); + } + } + + if (!IsStatic && this.GetIsNewExtensionMember() && ContainingType.ExtensionParameter is { } extensionParameter && + !this.IsNoMoreVisibleThan(extensionParameter.Type, ref useSiteInfo)) + { + diagnostics.Add(ErrorCode.ERR_BadVisIndexerParam, Location, this, extensionParameter.Type); + } + diagnostics.Add(Location, useSiteInfo); if (IsPartialDefinition && OtherPartOfPartial is { } implementation) @@ -690,7 +726,7 @@ private void PartialPropertyChecks(SourcePropertySymbol implementation, BindingD if (hasTypeDifferences) { - diagnostics.Add(ErrorCode.ERR_PartialPropertyTypeDifference, implementation.GetFirstLocation()); + diagnostics.Add(ErrorCode.ERR_PartialMemberTypeDifference, implementation.GetFirstLocation()); } else if (MemberSignatureComparer.ConsideringTupleNamesCreatesDifference(this, implementation)) { @@ -707,7 +743,7 @@ private void PartialPropertyChecks(SourcePropertySymbol implementation, BindingD if ((!hasTypeDifferences && !MemberSignatureComparer.PartialMethodsStrictComparer.Equals(this, implementation)) || !Parameters.SequenceEqual(implementation.Parameters, (a, b) => a.Name == b.Name)) { - diagnostics.Add(ErrorCode.WRN_PartialPropertySignatureDifference, implementation.GetFirstLocation(), + diagnostics.Add(ErrorCode.WRN_PartialMemberSignatureDifference, implementation.GetFirstLocation(), new FormattedSymbol(this, SymbolDisplayFormat.MinimallyQualifiedFormat), new FormattedSymbol(implementation, SymbolDisplayFormat.MinimallyQualifiedFormat)); } @@ -789,8 +825,8 @@ private void PartialPropertyChecks(SourcePropertySymbol implementation, BindingD internal SourcePropertySymbol? SourcePartialDefinitionPart => IsPartialImplementation ? OtherPartOfPartial : null; internal SourcePropertySymbol? SourcePartialImplementationPart => IsPartialDefinition ? OtherPartOfPartial : null; - internal override PropertySymbol? PartialDefinitionPart => SourcePartialDefinitionPart; - internal override PropertySymbol? PartialImplementationPart => SourcePartialImplementationPart; + internal sealed override PropertySymbol? PartialDefinitionPart => SourcePartialDefinitionPart; + internal sealed override PropertySymbol? PartialImplementationPart => SourcePartialImplementationPart; internal static void InitializePartialPropertyParts(SourcePropertySymbol definition, SourcePropertySymbol implementation) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs index d3fa761b0baee..a2062e129739a 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs @@ -470,7 +470,11 @@ internal string SourceName // always use the real attribute bag of this symbol and modify LoadAndValidateAttributes to // handle partially filled bags. CustomAttributesBag? temp = null; - LoadAndValidateAttributes(OneOrMany.Create(indexerNameAttributeLists), ref temp, earlyDecodingOnly: true); + Binder rootBinder = GetAttributeBinder(indexerNameAttributeLists, DeclaringCompilation); + LoadAndValidateAttributes( + OneOrMany.Create(indexerNameAttributeLists), ref temp, earlyDecodingOnly: true, + binderOpt: rootBinder, + attributeMatchesOpt: this.GetIsNewExtensionMember() ? isPossibleIndexerNameAttributeInExtension : isPossibleIndexerNameAttribute); if (temp != null) { Debug.Assert(temp.IsEarlyDecodedWellKnownAttributeDataComputed); @@ -487,6 +491,24 @@ internal string SourceName } return _lazySourceName; + + static bool isPossibleIndexerNameAttribute(AttributeSyntax node, Binder? rootBinderOpt) + { + Debug.Assert(rootBinderOpt is not null); + QuickAttributeChecker checker = rootBinderOpt.QuickAttributeChecker; + return checker.IsPossibleMatch(node, QuickAttributes.IndexerName); + } + + static bool isPossibleIndexerNameAttributeInExtension(AttributeSyntax node, Binder? rootBinderOpt) + { + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Temporarily limit binding to a string literal argument in order to avoid a binding cycle. + if (node.ArgumentList?.Arguments is not [{ NameColon: null, NameEquals: null, Expression: LiteralExpressionSyntax { RawKind: (int)SyntaxKind.StringLiteralExpression } }]) + { + return false; + } + + return isPossibleIndexerNameAttribute(node, rootBinderOpt); + } } } #nullable disable @@ -1696,6 +1718,12 @@ private void ValidateIndexerNameAttribute(CSharpAttributeData attribute, Attribu { diagnostics.Add(ErrorCode.ERR_BadArgumentToAttribute, node.ArgumentList.Arguments[0].Location, node.GetErrorDisplayName()); } + else if (this.GetIsNewExtensionMember() && SourceName != indexerName) + { + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Report more descriptive error + // error CS8078: An expression is too long or complex to compile + diagnostics.Add(ErrorCode.ERR_InsufficientStack, node.ArgumentList.Arguments[0].Location); + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs index b5a73d85c0ddc..5899dde5c1af1 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs @@ -230,7 +230,7 @@ protected static DeclarationModifiers MakeDeclarationModifiers(MethodKind method var result = ModifierUtils.MakeAndCheckNonTypeMemberModifiers( isOrdinaryMethod: false, isForInterfaceMember: inInterface, - syntax.Modifiers, defaultAccess, allowedModifiers, location, diagnostics, modifierErrors: out _); + syntax.Modifiers, defaultAccess, allowedModifiers, location, diagnostics, modifierErrors: out _, hasExplicitAccessModifier: out _); if (inInterface) { @@ -880,14 +880,6 @@ public sealed override string Name } } - public sealed override bool IsExtensionMethod - { - get - { - return false; - } - } - public sealed override ImmutableArray TypeParameters { get { return ImmutableArray.Empty; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SynthesizedSourceOrdinaryMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SynthesizedSourceOrdinaryMethodSymbol.cs new file mode 100644 index 0000000000000..5b642de3e2371 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SynthesizedSourceOrdinaryMethodSymbol.cs @@ -0,0 +1,77 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using System.Diagnostics; +using System.Globalization; +using System.Threading; +using Microsoft.CodeAnalysis.CSharp.Emit; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.Symbols +{ + /// + /// Common base for ordinary methods synthesized by compiler and added to the result. + /// + internal abstract class SynthesizedSourceOrdinaryMethodSymbol : SourceOrdinaryMethodSymbolBase + { + protected SynthesizedSourceOrdinaryMethodSymbol(SourceMemberContainerTypeSymbol containingType, string name, Location location, CSharpSyntaxNode syntax, (DeclarationModifiers declarationModifiers, Flags flags) modifiersAndFlags) + : base(containingType, name, location, syntax, isIterator: false, modifiersAndFlags) + { + } + + protected override void MethodChecks(BindingDiagnosticBag diagnostics) + { + Debug.Assert(Arity == 0); + var (returnType, parameters) = MakeParametersAndBindReturnType(diagnostics); + MethodChecks(returnType, parameters, diagnostics); + } + + protected abstract (TypeWithAnnotations ReturnType, ImmutableArray Parameters) MakeParametersAndBindReturnType(BindingDiagnosticBag diagnostics); + + public sealed override bool IsImplicitlyDeclared => true; + + protected sealed override Location ReturnTypeLocation => GetFirstLocation(); + + protected sealed override MethodSymbol? FindExplicitlyImplementedMethod(BindingDiagnosticBag diagnostics) => null; + + public sealed override ImmutableArray TypeParameters => ImmutableArray.Empty; + + public sealed override ImmutableArray> GetTypeParameterConstraintTypes() => ImmutableArray>.Empty; + + public sealed override ImmutableArray GetTypeParameterConstraintKinds() => ImmutableArray.Empty; + + protected sealed override void PartialMethodChecks(BindingDiagnosticBag diagnostics) + { + } + + protected sealed override void ExtensionMethodChecks(BindingDiagnosticBag diagnostics) + { + } + + protected sealed override void CompleteAsyncMethodChecksBetweenStartAndFinish() + { + } + + protected sealed override TypeSymbol? ExplicitInterfaceType => null; + + protected sealed override void CheckConstraintsForExplicitInterfaceType(ConversionsBase conversions, BindingDiagnosticBag diagnostics) + { + } + + protected sealed override SourceMemberMethodSymbol? BoundAttributesSource => null; + + internal sealed override OneOrMany> GetAttributeDeclarations() => OneOrMany.Create(default(SyntaxList)); + + public sealed override string? GetDocumentationCommentXml(CultureInfo? preferredCulture = null, bool expandIncludes = false, CancellationToken cancellationToken = default) => null; + + internal sealed override bool GenerateDebugInfo => false; + + internal sealed override bool SynthesizesLoweredBoundBody => true; + internal sealed override ExecutableCodeBinder? TryGetBodyBinder(BinderFactory? binderFactoryOpt = null, bool ignoreAccessibility = false) => throw ExceptionUtilities.Unreachable(); + internal abstract override void GenerateMethodBody(TypeCompilationState compilationState, BindingDiagnosticBag diagnostics); + } +} diff --git a/src/Compilers/CSharp/Portable/Symbols/SubstitutedNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/SubstitutedNamedTypeSymbol.cs index 379aae474eb7e..f83a89bd604e5 100644 --- a/src/Compilers/CSharp/Portable/Symbols/SubstitutedNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/SubstitutedNamedTypeSymbol.cs @@ -9,6 +9,7 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Linq; +using System.Runtime.CompilerServices; using System.Threading; using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.CSharp.Emit; @@ -40,6 +41,10 @@ internal abstract class SubstitutedNamedTypeSymbol : WrappedNamedTypeSymbol private TypeMap _lazyMap; private ImmutableArray _lazyTypeParameters; +#nullable enable + private StrongBox _lazyExtensionParameter; +#nullable disable + private NamedTypeSymbol _lazyBaseType = ErrorTypeSymbol.UnknownResultType; // computed on demand @@ -487,5 +492,35 @@ internal sealed override bool HasInlineArrayAttribute(out int length) } internal sealed override bool HasCompilerLoweringPreserveAttribute => _underlyingType.HasCompilerLoweringPreserveAttribute; + +#nullable enable + internal sealed override ParameterSymbol? ExtensionParameter + { + get + { + if (_lazyExtensionParameter is null) + { + Interlocked.CompareExchange(ref _lazyExtensionParameter, new StrongBox(substituteParameter()), null); + } + + return _lazyExtensionParameter.Value; + + ParameterSymbol? substituteParameter() + { + if (!this.IsExtension) + { + return null; + } + + var unsubstitutedParameter = OriginalDefinition.ExtensionParameter; + if (unsubstitutedParameter is null) + { + return null; + } + + return new SubstitutedParameterSymbol(containingSymbol: this, Map, unsubstitutedParameter); + } + } + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/SubstitutedParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/SubstitutedParameterSymbol.cs index 383aacb6b7583..d8b6c80c504c5 100644 --- a/src/Compilers/CSharp/Portable/Symbols/SubstitutedParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/SubstitutedParameterSymbol.cs @@ -24,6 +24,11 @@ internal SubstitutedParameterSymbol(PropertySymbol containingSymbol, TypeMap map { } + internal SubstitutedParameterSymbol(NamedTypeSymbol containingSymbol, TypeMap map, ParameterSymbol originalParameter) : + this((Symbol)containingSymbol, map, originalParameter) + { + } + private SubstitutedParameterSymbol(Symbol containingSymbol, TypeMap map, ParameterSymbol originalParameter) : base(originalParameter) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Symbol.cs b/src/Compilers/CSharp/Portable/Symbols/Symbol.cs index 216b61f6d68ae..1b843d8c13d89 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Symbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Symbol.cs @@ -9,7 +9,6 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Globalization; -using System.Reflection.Metadata; using System.Runtime.InteropServices; using System.Text; using System.Threading; @@ -648,10 +647,12 @@ public bool CanBeReferencedByName break; case SymbolKind.NamedType: - if (((NamedTypeSymbol)this).IsSubmissionClass) + var namedType = (NamedTypeSymbol)this; + if (namedType.IsSubmissionClass || namedType.IsExtension) { return false; } + break; case SymbolKind.Property: @@ -1740,6 +1741,13 @@ internal static bool IsCaptured(Symbol variable, SourceMethodSymbol containingSy throw ExceptionUtilities.UnexpectedValue(variable.Kind); } + if (containingSymbol.GetIsNewExtensionMember() + && variable is ParameterSymbol { ContainingSymbol: TypeSymbol { IsExtension: true } }) + { + // An extension member doesn't capture the extension parameter + return false; + } + // Walk up the containing symbols until we find the target function, in which // case the variable is not captured by the target function, or null, in which // case it is. diff --git a/src/Compilers/CSharp/Portable/Symbols/Symbol_Attributes.cs b/src/Compilers/CSharp/Portable/Symbols/Symbol_Attributes.cs index 752624007b7e6..0850691a84d82 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Symbol_Attributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Symbol_Attributes.cs @@ -302,7 +302,7 @@ internal bool LoadAndValidateAttributes( AttributeLocation symbolPart = AttributeLocation.None, bool earlyDecodingOnly = false, Binder? binderOpt = null, - Func? attributeMatchesOpt = null, + Func? attributeMatchesOpt = null, Action? beforeAttributePartBound = null, Action? afterAttributePartBound = null) { @@ -586,7 +586,7 @@ private ImmutableArray GetAttributesToBind( AttributeLocation symbolPart, BindingDiagnosticBag diagnostics, CSharpCompilation compilation, - Func attributeMatchesOpt, + Func attributeMatchesOpt, Binder rootBinderOpt, out ImmutableArray binders) { @@ -624,7 +624,7 @@ private ImmutableArray GetAttributesToBind( { foreach (var attribute in attributesToBind) { - if (attributeMatchesOpt(attribute)) + if (attributeMatchesOpt(attribute, rootBinderOpt)) { syntaxBuilder.Add(attribute); attributesToBindCount++; @@ -666,7 +666,7 @@ protected virtual bool ShouldBindAttributes(AttributeListSyntax attributeDeclara } #nullable enable - private Binder GetAttributeBinder(SyntaxList attributeDeclarationSyntaxList, CSharpCompilation compilation, Binder? rootBinder = null) + protected Binder GetAttributeBinder(SyntaxList attributeDeclarationSyntaxList, CSharpCompilation compilation, Binder? rootBinder = null) { var binder = rootBinder ?? compilation.GetBinderFactory(attributeDeclarationSyntaxList.Node!.SyntaxTree).GetBinder(attributeDeclarationSyntaxList.Node); binder = new ContextualAttributeBinder(binder, this); diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNameKind.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNameKind.cs index 1ce4cbea2afe8..81e158c5e9331 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNameKind.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNameKind.cs @@ -30,6 +30,7 @@ internal enum GeneratedNameKind ReusableHoistedLocalField = '7', LambdaCacheField = '9', FixedBufferField = 'e', + Extension = 'E', FileType = 'F', AnonymousType = 'f', TransparentIdentifier = 'h', diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNames.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNames.cs index 2430ad6d920c0..e55d1f8eca160 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNames.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNames.cs @@ -70,6 +70,12 @@ internal static string MakeAnonymousTypeBackingFieldName(string propertyName) return "<" + propertyName + ">i__Field"; } + internal static string MakeExtensionName(int index) + { + Debug.Assert((char)GeneratedNameKind.Extension == 'E'); + return "<>E__" + StringExtensions.GetNumeral(index); + } + internal static string MakeAnonymousTypeParameterName(string propertyName) { return "<" + propertyName + ">j__TPar"; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/ReadOnlyListType/SynthesizedReadOnlyListEnumeratorTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/ReadOnlyListType/SynthesizedReadOnlyListEnumeratorTypeSymbol.cs index 927c1d23d5931..0d6a1dd0e4773 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/ReadOnlyListType/SynthesizedReadOnlyListEnumeratorTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/ReadOnlyListType/SynthesizedReadOnlyListEnumeratorTypeSymbol.cs @@ -139,6 +139,9 @@ static void addProperty(ArrayBuilder builder, PropertySymbol property) public override bool IsRefLikeType => false; + internal override string ExtensionName + => throw ExceptionUtilities.Unreachable(); + public override bool IsReadOnly => false; public override Symbol ContainingSymbol => _containingType; @@ -173,6 +176,8 @@ static void addProperty(ArrayBuilder builder, PropertySymbol property) internal override bool IsInterpolatedStringHandlerType => false; + internal sealed override ParameterSymbol? ExtensionParameter => null; + internal override bool HasSpecialName => false; internal override bool IsComImport => false; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/ReadOnlyListType/SynthesizedReadOnlyListTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/ReadOnlyListType/SynthesizedReadOnlyListTypeSymbol.cs index 43b5765ed7076..7d1c4d80cfd6b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/ReadOnlyListType/SynthesizedReadOnlyListTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/ReadOnlyListType/SynthesizedReadOnlyListTypeSymbol.cs @@ -816,6 +816,9 @@ public static bool CanCreateSingleElement(CSharpCompilation compilation) public override bool IsRefLikeType => false; + internal override string ExtensionName + => throw ExceptionUtilities.Unreachable(); + public override bool IsReadOnly => false; public override Symbol? ContainingSymbol => _containingModule.GlobalNamespace; @@ -850,6 +853,8 @@ public static bool CanCreateSingleElement(CSharpCompilation compilation) internal override bool IsInterpolatedStringHandlerType => false; + internal sealed override ParameterSymbol? ExtensionParameter => null; + internal override bool HasSpecialName => false; internal override bool IsComImport => false; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEqualityContractProperty.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEqualityContractProperty.cs index b99b4283207fc..bf26af38968aa 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEqualityContractProperty.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEqualityContractProperty.cs @@ -155,14 +155,7 @@ internal GetAccessorSymbol( { } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) - { - base.AddSynthesizedAttributes(moduleBuilder, ref attributes); - - var compilation = this.DeclaringCompilation; - AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor)); - Debug.Assert(WellKnownMembers.IsSynthesizedAttributeOptional(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor)); - } + public override bool IsImplicitlyDeclared => true; public override ImmutableArray DeclaringSyntaxReferences => ImmutableArray.Empty; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEqualityOperatorBase.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEqualityOperatorBase.cs index 9b1f67f53bcd3..ec959a2e84c7b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEqualityOperatorBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEqualityOperatorBase.cs @@ -77,14 +77,5 @@ protected sealed override (TypeWithAnnotations ReturnType, ImmutableArray 2; - - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) - { - base.AddSynthesizedAttributes(moduleBuilder, ref attributes); - Debug.Assert(IsImplicitlyDeclared); - var compilation = this.DeclaringCompilation; - AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor)); - Debug.Assert(WellKnownMembers.IsSynthesizedAttributeOptional(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor)); - } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordOrdinaryMethod.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordOrdinaryMethod.cs index 404ed77cadab1..6811e4cd49ea6 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordOrdinaryMethod.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordOrdinaryMethod.cs @@ -2,27 +2,17 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Immutable; -using System.Diagnostics; -using System.Globalization; -using System.Threading; -using Microsoft.CodeAnalysis.CSharp.Emit; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.PooledObjects; -using Roslyn.Utilities; - namespace Microsoft.CodeAnalysis.CSharp.Symbols { /// /// Common base for ordinary methods synthesized by compiler for records. /// - internal abstract class SynthesizedRecordOrdinaryMethod : SourceOrdinaryMethodSymbolBase + internal abstract class SynthesizedRecordOrdinaryMethod : SynthesizedSourceOrdinaryMethodSymbol { private readonly int _memberOffset; protected SynthesizedRecordOrdinaryMethod(SourceMemberContainerTypeSymbol containingType, string name, int memberOffset, DeclarationModifiers declarationModifiers) : base(containingType, name, containingType.GetFirstLocation(), (CSharpSyntaxNode)containingType.SyntaxReferences[0].GetSyntax(), - isIterator: false, (declarationModifiers, MakeFlags( MethodKind.Ordinary, RefKind.None, declarationModifiers, returnsVoid: false, returnsVoidIsSet: false, isExpressionBodied: false, isExtensionMethod: false, isNullableAnalysisEnabled: false, isVarArg: false, @@ -31,66 +21,6 @@ protected SynthesizedRecordOrdinaryMethod(SourceMemberContainerTypeSymbol contai _memberOffset = memberOffset; } - protected override void MethodChecks(BindingDiagnosticBag diagnostics) - { - Debug.Assert(Arity == 0); - var (returnType, parameters) = MakeParametersAndBindReturnType(diagnostics); - MethodChecks(returnType, parameters, diagnostics); - } - - protected abstract (TypeWithAnnotations ReturnType, ImmutableArray Parameters) MakeParametersAndBindReturnType(BindingDiagnosticBag diagnostics); - - public sealed override bool IsImplicitlyDeclared => true; - - protected sealed override Location ReturnTypeLocation => GetFirstLocation(); - - protected sealed override MethodSymbol? FindExplicitlyImplementedMethod(BindingDiagnosticBag diagnostics) => null; - internal sealed override LexicalSortKey GetLexicalSortKey() => LexicalSortKey.GetSynthesizedMemberKey(_memberOffset); - - public sealed override ImmutableArray TypeParameters => ImmutableArray.Empty; - - public sealed override ImmutableArray> GetTypeParameterConstraintTypes() => ImmutableArray>.Empty; - - public sealed override ImmutableArray GetTypeParameterConstraintKinds() => ImmutableArray.Empty; - - protected sealed override void PartialMethodChecks(BindingDiagnosticBag diagnostics) - { - } - - protected sealed override void ExtensionMethodChecks(BindingDiagnosticBag diagnostics) - { - } - - protected sealed override void CompleteAsyncMethodChecksBetweenStartAndFinish() - { - } - - protected sealed override TypeSymbol? ExplicitInterfaceType => null; - - protected sealed override void CheckConstraintsForExplicitInterfaceType(ConversionsBase conversions, BindingDiagnosticBag diagnostics) - { - } - - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) - { - base.AddSynthesizedAttributes(moduleBuilder, ref attributes); - Debug.Assert(IsImplicitlyDeclared); - var compilation = this.DeclaringCompilation; - AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor)); - Debug.Assert(WellKnownMembers.IsSynthesizedAttributeOptional(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor)); - } - - protected sealed override SourceMemberMethodSymbol? BoundAttributesSource => null; - - internal sealed override OneOrMany> GetAttributeDeclarations() => OneOrMany.Create(default(SyntaxList)); - - public sealed override string? GetDocumentationCommentXml(CultureInfo? preferredCulture = null, bool expandIncludes = false, CancellationToken cancellationToken = default) => null; - - internal sealed override bool GenerateDebugInfo => false; - - internal sealed override bool SynthesizesLoweredBoundBody => true; - internal sealed override ExecutableCodeBinder? TryGetBodyBinder(BinderFactory? binderFactoryOpt = null, bool ignoreAccessibility = false) => throw ExceptionUtilities.Unreachable(); - internal abstract override void GenerateMethodBody(TypeCompilationState compilationState, BindingDiagnosticBag diagnostics); } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs index 851b7d1f214d2..b7290cbe61ecc 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs @@ -4,8 +4,10 @@ #nullable disable +using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using System.Threading; using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; @@ -78,6 +80,7 @@ public override bool IsImplicitlyDeclared internal sealed class SynthesizedBackingFieldSymbol : SynthesizedBackingFieldSymbolBase { private readonly SourcePropertySymbolBase _property; + private int _inferredNullableAnnotation = (int)NullableAnnotation.Ignored; internal override bool HasInitializer { get; } public SynthesizedBackingFieldSymbol( @@ -122,6 +125,110 @@ public override ImmutableArray Locations internal override TypeWithAnnotations GetFieldType(ConsList fieldsBeingBound) => _property.TypeWithAnnotations; +#nullable enable + internal bool InfersNullableAnnotation + { + get + { + if (FlowAnalysisAnnotations != FlowAnalysisAnnotations.None) + { + return false; + } + + var propertyType = _property.TypeWithAnnotations; + if (propertyType.NullableAnnotation != NullableAnnotation.NotAnnotated + || !_property.UsesFieldKeyword) + { + return false; + } + + return true; + } + } + + internal NullableAnnotation GetInferredNullableAnnotation() + { + if (_inferredNullableAnnotation == (int)NullableAnnotation.Ignored) + { + var inferredAnnotation = ComputeInferredNullableAnnotation(); + Debug.Assert(inferredAnnotation is not NullableAnnotation.Ignored); + Interlocked.CompareExchange(ref _inferredNullableAnnotation, (int)inferredAnnotation, (int)NullableAnnotation.Ignored); + } + Debug.Assert((NullableAnnotation)_inferredNullableAnnotation is NullableAnnotation.NotAnnotated or NullableAnnotation.Annotated); + return (NullableAnnotation)_inferredNullableAnnotation; + } + + private NullableAnnotation ComputeInferredNullableAnnotation() + { + // https://github.com/dotnet/csharplang/blob/94205582d0f5c73e5765cb5888311c2f14890b95/proposals/field-keyword.md#nullability-of-the-backing-field + Debug.Assert(InfersNullableAnnotation); + + // If the property does not have a get accessor, it is (vacuously) null-resilient. + if (_property.GetMethod is not SourcePropertyAccessorSymbol getAccessor) + { + Debug.Assert(_property.GetMethod is null); + return NullableAnnotation.Annotated; + } + + // If the get accessor is auto-implemented, the property is not null-resilient. + if (getAccessor.IsAutoPropertyAccessor) + return NullableAnnotation.NotAnnotated; + + getAccessor = (SourcePropertyAccessorSymbol?)getAccessor.PartialImplementationPart ?? getAccessor; + var binder = getAccessor.TryGetBodyBinder() ?? throw ExceptionUtilities.UnexpectedValue(getAccessor); + var boundGetAccessor = binder.BindMethodBody(getAccessor.SyntaxNode, BindingDiagnosticBag.Discarded); + + var annotatedDiagnostics = nullableAnalyzeAndFilterDiagnostics(assumedNullableAnnotation: NullableAnnotation.Annotated); + if (annotatedDiagnostics.IsEmptyWithoutResolution) + { + // If the pass where the field was annotated results in no diagnostics at all, then the property is null-resilient and the not-annotated pass can be skipped. + annotatedDiagnostics.Free(); + return NullableAnnotation.Annotated; + } + + var notAnnotatedDiagnostics = nullableAnalyzeAndFilterDiagnostics(assumedNullableAnnotation: NullableAnnotation.NotAnnotated); + if (notAnnotatedDiagnostics.IsEmptyWithoutResolution) + { + // annotated pass had diagnostics, and not-annotated pass had no diagnostics. + annotatedDiagnostics.Free(); + notAnnotatedDiagnostics.Free(); + return NullableAnnotation.NotAnnotated; + } + + // Both annotated and not-annotated cases had nullable warnings. + var notAnnotatedDiagnosticsSet = new HashSet(notAnnotatedDiagnostics.AsEnumerable(), SameDiagnosticComparer.Instance); + notAnnotatedDiagnostics.Free(); + + foreach (var diagnostic in annotatedDiagnostics.AsEnumerable()) + { + if (!notAnnotatedDiagnosticsSet.Contains(diagnostic)) + { + // There is a nullable diagnostic in the pass where the field was *annotated*, + // which was not present in the pass where the field is *not-annotated*. The property is not null-resilient. + annotatedDiagnostics.Free(); + return NullableAnnotation.NotAnnotated; + } + } + + annotatedDiagnostics.Free(); + return NullableAnnotation.Annotated; + + DiagnosticBag nullableAnalyzeAndFilterDiagnostics(NullableAnnotation assumedNullableAnnotation) + { + var diagnostics = DiagnosticBag.GetInstance(); + NullableWalker.AnalyzeIfNeeded(binder, boundGetAccessor, boundGetAccessor.Syntax, diagnostics, getterNullResilienceData: (getAccessor, _property.BackingField, assumedNullableAnnotation)); + if (diagnostics.IsEmptyWithoutResolution) + { + return diagnostics; + } + + var filteredDiagnostics = DiagnosticBag.GetInstance(); + _ = DeclaringCompilation.FilterAndAppendAndFreeDiagnostics(filteredDiagnostics, ref diagnostics, cancellationToken: default); + return filteredDiagnostics; + } + } +#nullable disable + internal override bool HasPointerType => _property.HasPointerType; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedContainer.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedContainer.cs index f6e73c27ebbe0..f4582d2a201ad 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedContainer.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedContainer.cs @@ -23,19 +23,12 @@ internal abstract class SynthesizedContainer : NamedTypeSymbol private readonly ImmutableArray _typeParameters; private readonly ImmutableArray _constructedFromTypeParameters; - protected SynthesizedContainer(string name, MethodSymbol containingMethod) + protected SynthesizedContainer(string name, ImmutableArray typeParametersToAlphaRename) { Debug.Assert(name != null); Name = name; - if (containingMethod == null) - { - TypeMap = TypeMap.Empty; - _typeParameters = ImmutableArray.Empty; - } - else - { - TypeMap = TypeMap.Empty.WithConcatAlphaRename(containingMethod, this, out _typeParameters, out _constructedFromTypeParameters); - } + _constructedFromTypeParameters = typeParametersToAlphaRename; + TypeMap = TypeMap.Empty.WithAlphaRename(typeParametersToAlphaRename, this, out _typeParameters); } protected SynthesizedContainer(string name) @@ -53,6 +46,8 @@ protected SynthesizedContainer(string name) internal sealed override bool IsInterface => this.TypeKind == TypeKind.Interface; + internal sealed override ParameterSymbol ExtensionParameter => null; + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); @@ -153,6 +148,9 @@ internal override IEnumerable GetFieldsToEmit() public sealed override bool IsRefLikeType => false; + internal override string ExtensionName + => throw ExceptionUtilities.Unreachable(); + public sealed override bool IsReadOnly => false; internal override ImmutableArray InterfacesNoUseSiteDiagnostics(ConsList basesBeingResolved) => ImmutableArray.Empty; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedDelegateSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedDelegateSymbol.cs index 33d3253985712..27527193735ea 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedDelegateSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedDelegateSymbol.cs @@ -28,7 +28,7 @@ public override ImmutableArray Parameters } } - internal sealed class SynthesizedDelegateInvokeMethod : SynthesizedInstanceMethodSymbol + internal sealed class SynthesizedDelegateInvokeMethod : SynthesizedMethodSymbol { internal readonly struct ParameterDescription { diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEmbeddedAttributeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEmbeddedAttributeSymbol.cs index b3a57c3c7e1c7..c57954b8425c3 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEmbeddedAttributeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEmbeddedAttributeSymbol.cs @@ -89,6 +89,9 @@ public SynthesizedEmbeddedAttributeSymbolBase( public override bool IsRefLikeType => false; + internal override string ExtensionName + => throw ExceptionUtilities.Unreachable(); + public override bool IsReadOnly => false; public override bool IsAbstract => false; @@ -114,6 +117,8 @@ internal override bool GetGuidString(out string guidString) internal override bool IsInterpolatedStringHandlerType => false; + internal sealed override ParameterSymbol ExtensionParameter => null; + internal override bool HasSpecialName => false; internal override bool IsComImport => false; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEventAccessorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEventAccessorSymbol.cs index 9c37841206071..3fafab5d05194 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEventAccessorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEventAccessorSymbol.cs @@ -50,6 +50,13 @@ protected override SourceMemberMethodSymbol BoundAttributesSource { get { + Debug.Assert(PartialImplementationPart is null); + + if (PartialDefinitionPart is { } definitionPart) + { + return (SourceMemberMethodSymbol)definitionPart; + } + return this.MethodKind == MethodKind.EventAdd ? (SourceMemberMethodSymbol)this.AssociatedEvent.RemoveMethod : null; @@ -67,15 +74,24 @@ protected override IAttributeTargetSymbol AttributeOwner internal override OneOrMany> GetAttributeDeclarations() { - return OneOrMany.Create(this.AssociatedEvent.AttributeDeclarationSyntaxList); - } + // If we are asking this question on a partial implementation symbol, + // it must be from a context which prefers to order implementation attributes before definition attributes. + // For example, the 'value' parameter of an add or remove accessor. + if (PartialDefinitionPart is { } definitionPart) + { + return OneOrMany.Create( + this.AssociatedEvent.AttributeDeclarationSyntaxList, + ((SourceEventAccessorSymbol)definitionPart).AssociatedEvent.AttributeDeclarationSyntaxList); + } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) - { - base.AddSynthesizedAttributes(moduleBuilder, ref attributes); + if (PartialImplementationPart is { } implementationPart) + { + return OneOrMany.Create( + this.AssociatedEvent.AttributeDeclarationSyntaxList, + ((SourceEventAccessorSymbol)implementationPart).AssociatedEvent.AttributeDeclarationSyntaxList); + } - var compilation = this.DeclaringCompilation; - AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor)); + return OneOrMany.Create(this.AssociatedEvent.AttributeDeclarationSyntaxList); } protected override object MethodChecksLockObject diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedHotReloadExceptionSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedHotReloadExceptionSymbol.cs index 30bcbb683b475..adbb03ff0a6d5 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedHotReloadExceptionSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedHotReloadExceptionSymbol.cs @@ -96,6 +96,10 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r public override ImmutableArray DeclaringSyntaxReferences => []; public override bool IsStatic => false; public override bool IsRefLikeType => false; + + internal override string ExtensionName + => throw ExceptionUtilities.Unreachable(); + public override bool IsReadOnly => false; public override bool IsAbstract => false; public override bool IsSealed => true; @@ -106,6 +110,7 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r internal override bool HasCodeAnalysisEmbeddedAttribute => true; internal override bool HasCompilerLoweringPreserveAttribute => false; internal override bool IsInterpolatedStringHandlerType => false; + internal sealed override ParameterSymbol? ExtensionParameter => null; internal override bool HasSpecialName => false; internal override bool IsComImport => false; internal override bool IsWindowsRuntimeImport => false; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedImplementationMethod.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedImplementationMethod.cs index cdde99030bca4..16d8fb98bb4ba 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedImplementationMethod.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedImplementationMethod.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols { - internal abstract class SynthesizedImplementationMethod : SynthesizedInstanceMethodSymbol + internal abstract class SynthesizedImplementationMethod : SynthesizedMethodSymbol { //inputs protected readonly MethodSymbol _interfaceMethod; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInlineArrayTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInlineArrayTypeSymbol.cs index 014d0e9005941..317f919c9ba5d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInlineArrayTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInlineArrayTypeSymbol.cs @@ -64,6 +64,9 @@ internal SynthesizedInlineArrayTypeSymbol(SourceModuleSymbol containingModule, s public override bool IsRefLikeType => false; + internal override string ExtensionName + => throw ExceptionUtilities.Unreachable(); + public override bool IsReadOnly => true; public override Symbol? ContainingSymbol => _containingModule.GlobalNamespace; @@ -104,6 +107,8 @@ internal override bool GetGuidString(out string? guidString) internal override bool IsInterpolatedStringHandlerType => false; + internal sealed override ParameterSymbol? ExtensionParameter => null; + internal override bool HasSpecialName => false; internal override bool IsComImport => false; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceConstructor.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceConstructor.cs index 70ea99af74714..248c22bffc6e9 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceConstructor.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceConstructor.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols { - internal class SynthesizedInstanceConstructor : SynthesizedInstanceMethodSymbol + internal class SynthesizedInstanceConstructor : SynthesizedMethodSymbol { private readonly NamedTypeSymbol _containingType; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInteractiveInitializerMethod.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInteractiveInitializerMethod.cs index 19e7b4476dcc7..7a27eaeeac500 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInteractiveInitializerMethod.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInteractiveInitializerMethod.cs @@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols { - internal sealed class SynthesizedInteractiveInitializerMethod : SynthesizedInstanceMethodSymbol + internal sealed class SynthesizedInteractiveInitializerMethod : SynthesizedMethodSymbol { internal const string InitializerName = ""; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedMethodSymbol.cs similarity index 89% rename from src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceMethodSymbol.cs rename to src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedMethodSymbol.cs index a3f190bfafa9d..de0966d0f8ac4 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedMethodSymbol.cs @@ -12,9 +12,9 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols { /// - /// A base class for synthesized methods that want a this parameter. + /// A base class for synthesized methods that might want a this parameter. /// - internal abstract class SynthesizedInstanceMethodSymbol : MethodSymbol + internal abstract class SynthesizedMethodSymbol : MethodSymbol { private ParameterSymbol _lazyThisParameter; @@ -42,9 +42,15 @@ public sealed override bool AreLocalsZeroed } } + public abstract override bool IsStatic { get; } + internal override bool TryGetThisParameter(out ParameterSymbol thisParameter) { - Debug.Assert(!IsStatic); + if (IsStatic) + { + thisParameter = null; + return true; + } if ((object)_lazyThisParameter == null) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedPrivateImplementationDetailsType.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedPrivateImplementationDetailsType.cs index 7436082c596fe..e207f611093d2 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedPrivateImplementationDetailsType.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedPrivateImplementationDetailsType.cs @@ -57,6 +57,9 @@ public SynthesizedPrivateImplementationDetailsType(PrivateImplementationDetails public override bool IsRefLikeType => false; + internal override string ExtensionName + => throw ExceptionUtilities.Unreachable(); + public override bool IsReadOnly => false; public override Symbol ContainingSymbol => _globalNamespace; @@ -87,6 +90,8 @@ public SynthesizedPrivateImplementationDetailsType(PrivateImplementationDetails internal override bool IsInterpolatedStringHandlerType => false; + internal sealed override ParameterSymbol? ExtensionParameter => null; + internal override bool HasSpecialName => _privateImplementationDetails.IsSpecialName; internal override bool IsComImport => false; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSealedPropertyAccessor.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSealedPropertyAccessor.cs index 3896f75f165f4..aa17a287362b4 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSealedPropertyAccessor.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSealedPropertyAccessor.cs @@ -20,7 +20,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols /// original virtual property, it is necessary to synthesize a sealed /// accessor so that the accessor will not be overridable from metadata. /// - internal sealed partial class SynthesizedSealedPropertyAccessor : SynthesizedInstanceMethodSymbol + internal sealed partial class SynthesizedSealedPropertyAccessor : SynthesizedMethodSymbol { private readonly PropertySymbol _property; private readonly MethodSymbol _overriddenAccessor; diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeMap.cs b/src/Compilers/CSharp/Portable/Symbols/TypeMap.cs index 483f075e3e9fd..e37396f1c9685 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeMap.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeMap.cs @@ -43,7 +43,7 @@ internal TypeMap(ImmutableArray from, ImmutableArray tp is SubstitutedTypeParameterSymbol)); + Debug.Assert(allowAlpha || !from.Any(static tp => tp is SubstitutedTypeParameterSymbol && tp.ContainingSymbol is not SourceExtensionImplementationMethodSymbol)); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Follow up, will the SourceExtensionImplementationMethodSymbol type check still be necessary at the end } // Only when the caller passes allowAlpha=true do we tolerate substituted (alpha-renamed) type parameters as keys @@ -100,7 +100,7 @@ public static TypeMap Empty } } - private TypeMap WithAlphaRename(ImmutableArray oldTypeParameters, Symbol newOwner, out ImmutableArray newTypeParameters) + internal TypeMap WithAlphaRename(ImmutableArray oldTypeParameters, Symbol newOwner, out ImmutableArray newTypeParameters) { if (oldTypeParameters.Length == 0) { @@ -148,12 +148,7 @@ internal TypeMap WithAlphaRename(MethodSymbol oldOwner, Symbol newOwner, out Imm return WithAlphaRename(oldOwner.OriginalDefinition.TypeParameters, newOwner, out newTypeParameters); } - internal TypeMap WithConcatAlphaRename( - MethodSymbol oldOwner, - Symbol newOwner, - out ImmutableArray newTypeParameters, - out ImmutableArray oldTypeParameters, - MethodSymbol stopAt = null) + internal static ImmutableArray ConcatMethodTypeParameters(MethodSymbol oldOwner, MethodSymbol stopAt) { Debug.Assert(oldOwner.ConstructedFrom == oldOwner); Debug.Assert(stopAt == null || stopAt.ConstructedFrom == stopAt); @@ -193,8 +188,7 @@ internal TypeMap WithConcatAlphaRename( stopAt?.MethodKind == MethodKind.StaticConstructor || stopAt?.MethodKind == MethodKind.Constructor); - oldTypeParameters = parameters.ToImmutableAndFree(); - return WithAlphaRename(oldTypeParameters, newOwner, out newTypeParameters); + return parameters.ToImmutableAndFree(); } private static SmallDictionary ConstructMapping(ImmutableArray from, ImmutableArray to) diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/TypeParameterSymbol.cs index ccab2679def85..57ed680f45364 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeParameterSymbol.cs @@ -591,6 +591,8 @@ public sealed override bool IsValueType } } + internal sealed override ParameterSymbol ExtensionParameter => null; + internal sealed override ManagedKind GetManagedKind(ref CompoundUseSiteInfo useSiteInfo) { return HasUnmanagedTypeConstraint ? ManagedKind.Unmanaged : ManagedKind.Managed; diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs index 61fd5fa1bc95e..38e42656dee4a 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs @@ -555,6 +555,16 @@ public virtual bool IsAnonymousType /// internal virtual bool IsNativeIntegerWrapperType => false; +#nullable enable + public bool IsExtension + => TypeKind == TypeKind.Extension; + + /// + /// For the type representing an extension declaration, returns the receiver parameter symbol. + /// + internal abstract ParameterSymbol? ExtensionParameter { get; } +#nullable disable + internal bool IsNativeIntegerType => IsNativeIntegerWrapperType || (SpecialType is SpecialType.System_IntPtr or SpecialType.System_UIntPtr && this.ContainingAssembly.RuntimeSupportsNumericIntPtr); diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs index 3940f6f3e229e..9c31d578b65cc 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs @@ -851,6 +851,7 @@ private static bool IsTypeLessVisibleThan(TypeSymbol type, Symbol sym, ref Compo case TypeKind.Struct: case TypeKind.Interface: case TypeKind.Delegate: + case TypeKind.Extension: if (current.IsAnonymousType) { @@ -1715,22 +1716,21 @@ internal static void GetAllTypeParameters(this NamedTypeSymbol type, ArrayBuilde /// internal static TypeParameterSymbol? FindEnclosingTypeParameter(this NamedTypeSymbol type, string name) { - var allTypeParameters = ArrayBuilder.GetInstance(); - type.GetAllTypeParameters(allTypeParameters); - - TypeParameterSymbol? result = null; - - foreach (TypeParameterSymbol tpEnclosing in allTypeParameters) + do { - if (name == tpEnclosing.Name) + foreach (TypeParameterSymbol tpEnclosing in type.TypeParameters) { - result = tpEnclosing; - break; + if (name == tpEnclosing.Name) + { + return tpEnclosing; + } } + + type = type.ContainingType; } + while (type is not null); - allTypeParameters.Free(); - return result; + return null; } /// diff --git a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedNamedTypeSymbol.cs index 48a0389a946be..63a931375bbaa 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedNamedTypeSymbol.cs @@ -95,6 +95,14 @@ internal override bool MangleName } } + internal override string ExtensionName + { + get + { + return _underlyingType.ExtensionName; + } + } + public override string GetDocumentationCommentXml(CultureInfo preferredCulture = null, bool expandIncludes = false, CancellationToken cancellationToken = default(CancellationToken)) { return _underlyingType.GetDocumentationCommentXml(preferredCulture, expandIncludes, cancellationToken); diff --git a/src/Compilers/CSharp/Portable/Syntax/ExtensionDeclarationSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/ExtensionDeclarationSyntax.cs new file mode 100644 index 0000000000000..b6b919098d81b --- /dev/null +++ b/src/Compilers/CSharp/Portable/Syntax/ExtensionDeclarationSyntax.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 Microsoft.CodeAnalysis.CSharp.Syntax +{ + public partial class ExtensionDeclarationSyntax + { + public override SyntaxToken Identifier => default; + + internal override BaseTypeDeclarationSyntax WithIdentifierCore(SyntaxToken identifier) + => throw new System.NotSupportedException(); + + public override BaseListSyntax? BaseList => null; + + internal override BaseTypeDeclarationSyntax AddBaseListTypesCore(params BaseTypeSyntax[] items) + => throw new System.NotSupportedException(); + + internal override BaseTypeDeclarationSyntax WithBaseListCore(BaseListSyntax? baseList) + => throw new System.NotSupportedException(); + } +} diff --git a/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/TypeDeclarationSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/TypeDeclarationSyntax.cs index b41530c1f7a5d..6750b331260e9 100644 --- a/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/TypeDeclarationSyntax.cs +++ b/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/TypeDeclarationSyntax.cs @@ -4,6 +4,7 @@ #nullable disable +using Roslyn.Utilities; using CoreSyntax = Microsoft.CodeAnalysis.Syntax.InternalSyntax; namespace Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax @@ -153,4 +154,47 @@ public override TypeDeclarationSyntax UpdateCore( semicolonToken); } } + + internal partial class ExtensionDeclarationSyntax + { + public override TypeDeclarationSyntax UpdateCore( + CoreSyntax.SyntaxList attributeLists, + CoreSyntax.SyntaxList modifiers, + SyntaxToken keyword, + SyntaxToken identifier, + TypeParameterListSyntax typeParameterList, + ParameterListSyntax parameterList, + BaseListSyntax baseList, + CoreSyntax.SyntaxList constraintClauses, + SyntaxToken openBraceToken, + CoreSyntax.SyntaxList members, + SyntaxToken closeBraceToken, + SyntaxToken semicolonToken) + { + if (identifier is not null) + { + throw ExceptionUtilities.Unreachable(); + } + + if (baseList is not null) + { + throw ExceptionUtilities.Unreachable(); + } + + return this.Update( + attributeLists, + modifiers, + keyword, + typeParameterList, + parameterList, + constraintClauses, + openBraceToken, + members, + closeBraceToken, + semicolonToken); + } + + public override SyntaxToken Identifier => null; + public override BaseListSyntax BaseList => null; + } } diff --git a/src/Compilers/CSharp/Portable/Syntax/ParameterDeclarationSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/ParameterDeclarationSyntax.cs new file mode 100644 index 0000000000000..44e699e832c3f --- /dev/null +++ b/src/Compilers/CSharp/Portable/Syntax/ParameterDeclarationSyntax.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Microsoft.CodeAnalysis.CSharp +{ + public partial class SyntaxFactory + { + /// Creates a new ParameterSyntax instance. + public static ParameterSyntax Parameter(SyntaxToken identifier) + => SyntaxFactory.Parameter(default, default(SyntaxTokenList), null, identifier, null); + } +} + diff --git a/src/Compilers/CSharp/Portable/Syntax/SimpleLambdaExpressionSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/SimpleLambdaExpressionSyntax.cs index 7e070e3fe7c8b..dbd917f946cc9 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SimpleLambdaExpressionSyntax.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SimpleLambdaExpressionSyntax.cs @@ -39,6 +39,14 @@ namespace Microsoft.CodeAnalysis.CSharp { public partial class SyntaxFactory { + /// Creates a new SimpleLambdaExpressionSyntax instance. + public static SimpleLambdaExpressionSyntax SimpleLambdaExpression(SyntaxList attributeLists, SyntaxTokenList modifiers, ParameterSyntax parameter, BlockSyntax? block, ExpressionSyntax? expressionBody) + => SyntaxFactory.SimpleLambdaExpression(attributeLists, modifiers, parameter, SyntaxFactory.Token(SyntaxKind.EqualsGreaterThanToken), block, expressionBody); + + /// Creates a new SimpleLambdaExpressionSyntax instance. + public static SimpleLambdaExpressionSyntax SimpleLambdaExpression(ParameterSyntax parameter) + => SyntaxFactory.SimpleLambdaExpression(default, default(SyntaxTokenList), parameter, SyntaxFactory.Token(SyntaxKind.EqualsGreaterThanToken), null, null); + public static SimpleLambdaExpressionSyntax SimpleLambdaExpression(SyntaxToken asyncKeyword, ParameterSyntax parameter, SyntaxToken arrowToken, BlockSyntax? block, ExpressionSyntax? expressionBody) => SimpleLambdaExpression(attributeLists: default, TokenList(asyncKeyword), parameter, arrowToken, block, expressionBody); diff --git a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml index 8e05ae9fee8b7..4c34bbf696e2c 100644 --- a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml +++ b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml @@ -1440,7 +1440,7 @@ - + @@ -3352,7 +3352,7 @@ Base class for type declaration syntax. - + Gets the identifier. @@ -3384,11 +3384,11 @@ - Base class for type declaration syntax (class, struct, interface, record). + Base class for type declaration syntax (class, struct, interface, record, extension). - Gets the type keyword token ("class", "struct", "interface", "record"). + Gets the type keyword token ("class", "struct", "interface", "record", "extension"). @@ -3617,6 +3617,30 @@ + + + Extension container syntax. + + + + + + + + + + + + + + + + + + + + + Base list syntax. @@ -4307,7 +4331,7 @@ - + Parameter syntax. @@ -4323,7 +4347,8 @@ - + + Gets the identifier. diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs index 5c7b02cdd3254..a1cbe33a1b30f 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs @@ -1817,7 +1817,7 @@ public static ParameterListSyntax ParseParameterList(string text, int offset = 0 using (var lexer = MakeLexer(text, offset, (CSharpParseOptions?)options)) using (var parser = MakeParser(lexer)) { - var node = parser.ParseParenthesizedParameterList(); + var node = parser.ParseParenthesizedParameterList(forExtension: false); if (consumeFullText) node = parser.ConsumeUnexpectedTokens(node); return (ParameterListSyntax)node.CreateRed(); } diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs index d697c4c2202be..d110fee28917e 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs @@ -421,6 +421,8 @@ public enum SyntaxKind : ushort FileKeyword = 8449, /// Represents . AllowsKeyword = 8450, + /// Represents . + ExtensionKeyword = 8451, // when adding a contextual keyword following functions must be adapted: // @@ -925,5 +927,7 @@ public enum SyntaxKind : ushort CollectionExpression = 9076, ExpressionElement = 9077, SpreadElement = 9078, + + ExtensionDeclaration = 9079, } } diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs index 17382780cb90e..b2b8b824b17ac 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs @@ -383,6 +383,7 @@ public static bool IsTypeDeclaration(SyntaxKind kind) case SyntaxKind.EnumDeclaration: case SyntaxKind.RecordDeclaration: case SyntaxKind.RecordStructDeclaration: + case SyntaxKind.ExtensionDeclaration: return true; default: @@ -828,6 +829,7 @@ public static SyntaxKind GetBaseTypeDeclarationKind(SyntaxKind kind) return kind == SyntaxKind.EnumKeyword ? SyntaxKind.EnumDeclaration : GetTypeDeclarationKind(kind); } + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : decide what we want for extension declaration public static SyntaxKind GetTypeDeclarationKind(SyntaxKind kind) { switch (kind) @@ -1166,7 +1168,7 @@ public static SyntaxKind GetPreprocessorKeywordKind(string text) public static IEnumerable GetContextualKeywordKinds() { - for (int i = (int)SyntaxKind.YieldKeyword; i <= (int)SyntaxKind.AllowsKeyword; i++) + for (int i = (int)SyntaxKind.YieldKeyword; i <= (int)SyntaxKind.ExtensionKeyword; i++) { // 8441 corresponds to a deleted kind (DataKeyword) that was previously shipped. if (i != 8441) @@ -1228,6 +1230,7 @@ public static bool IsContextualKeyword(SyntaxKind kind) case SyntaxKind.ScopedKeyword: case SyntaxKind.FileKeyword: case SyntaxKind.AllowsKeyword: + case SyntaxKind.ExtensionKeyword: return true; default: return false; @@ -1355,6 +1358,8 @@ public static SyntaxKind GetContextualKeywordKind(string text) return SyntaxKind.FileKeyword; case "allows": return SyntaxKind.AllowsKeyword; + case "extension": + return SyntaxKind.ExtensionKeyword; default: return SyntaxKind.None; } @@ -1802,6 +1807,8 @@ public static string GetText(SyntaxKind kind) return "file"; case SyntaxKind.AllowsKeyword: return "allows"; + case SyntaxKind.ExtensionKeyword: + return "extension"; default: return string.Empty; } diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxNormalizer.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxNormalizer.cs index 0471674501472..4376ad61d88f2 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxNormalizer.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxNormalizer.cs @@ -100,7 +100,7 @@ public override SyntaxToken VisitToken(SyntaxToken token) isTrailing: false, indentAfterLineBreak: NeedsIndentAfterLineBreak(token), mustHaveSeparator: false, - lineBreaksAfter: 0)); + lineBreaksAfter: lineBreaksAfterLeading(token))); var nextToken = this.GetNextRelevantToken(token); @@ -118,6 +118,22 @@ public override SyntaxToken VisitToken(SyntaxToken token) lineBreaksAfter: lineBreaksAfter)); return tk; + + static int lineBreaksAfterLeading(SyntaxToken syntaxToken) + { + if (syntaxToken.LeadingTrivia.Count < 2) + { + return 0; + } + + if (syntaxToken.LeadingTrivia[^2].IsKind(SyntaxKind.MultiLineDocumentationCommentTrivia) && + syntaxToken.LeadingTrivia[^1].IsKind(SyntaxKind.EndOfLineTrivia)) + { + return 1; + } + + return 0; + } } finally { @@ -1247,7 +1263,7 @@ private static bool EndsInLineBreak(SyntaxTrivia trivia) } else { - return IsLineBreak(node.GetLastToken()); + return !node.IsKind(SyntaxKind.MultiLineDocumentationCommentTrivia) && IsLineBreak(node.GetLastToken()); } } diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxReplacer.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxReplacer.cs index 5be08a6030e18..2cf64f0ab9d58 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxReplacer.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxReplacer.cs @@ -6,9 +6,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; -using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Syntax { @@ -74,9 +72,9 @@ private class Replacer : CSharpSyntaxRewriter where TNode : SyntaxNode private readonly HashSet _triviaSet; private readonly HashSet _spanSet; - private readonly TextSpan _totalSpan; - private readonly bool _visitIntoStructuredTrivia; - private readonly bool _shouldVisitTrivia; + private TextSpan _totalSpan; + private bool _visitIntoStructuredTrivia; + private bool _shouldVisitTrivia; public Replacer( IEnumerable? nodes, @@ -94,19 +92,9 @@ public Replacer( _tokenSet = tokens != null ? new HashSet(tokens) : s_noTokens; _triviaSet = trivia != null ? new HashSet(trivia) : s_noTrivia; - _spanSet = new HashSet( - _nodeSet.Select(n => n.FullSpan).Concat( - _tokenSet.Select(t => t.FullSpan).Concat( - _triviaSet.Select(t => t.FullSpan)))); - - _totalSpan = ComputeTotalSpan(_spanSet); - - _visitIntoStructuredTrivia = - _nodeSet.Any(n => n.IsPartOfStructuredTrivia()) || - _tokenSet.Any(t => t.IsPartOfStructuredTrivia()) || - _triviaSet.Any(t => t.IsPartOfStructuredTrivia()); + _spanSet = new HashSet(); - _shouldVisitTrivia = _triviaSet.Count > 0 || _visitIntoStructuredTrivia; + CalculateVisitationCriteria(); } private static readonly HashSet s_noNodes = new HashSet(); @@ -129,13 +117,29 @@ public bool HasWork } } - private static TextSpan ComputeTotalSpan(IEnumerable spans) + private void CalculateVisitationCriteria() { + _spanSet.Clear(); + foreach (var node in _nodeSet) + { + _spanSet.Add(node.FullSpan); + } + + foreach (var token in _tokenSet) + { + _spanSet.Add(token.FullSpan); + } + + foreach (var trivia in _triviaSet) + { + _spanSet.Add(trivia.FullSpan); + } + bool first = true; int start = 0; int end = 0; - foreach (var span in spans) + foreach (var span in _spanSet) { if (first) { @@ -150,7 +154,14 @@ private static TextSpan ComputeTotalSpan(IEnumerable spans) } } - return new TextSpan(start, end - start); + _totalSpan = new TextSpan(start, end - start); + + _visitIntoStructuredTrivia = + _nodeSet.Any(static n => n.IsPartOfStructuredTrivia()) || + _tokenSet.Any(static t => t.IsPartOfStructuredTrivia()) || + _triviaSet.Any(static t => t.IsPartOfStructuredTrivia()); + + _shouldVisitTrivia = _triviaSet.Count > 0 || _visitIntoStructuredTrivia; } private bool ShouldVisit(TextSpan span) @@ -179,16 +190,28 @@ private bool ShouldVisit(TextSpan span) [return: NotNullIfNotNull(nameof(node))] public override SyntaxNode? Visit(SyntaxNode? node) { - SyntaxNode? rewritten = node; + var rewritten = node; if (node != null) { + bool isReplacedNode = _nodeSet.Remove(node); + + if (isReplacedNode) + { + // If node is in _nodeSet, then it contributed to the calculation of _spanSet. + // We are currently processing that node, so it no longer needs to contribute + // to _spanSet and affect determination of inward visitation. This is done before + // calling ShouldVisit to avoid walking into the node if there aren't any remaining + // spans inside it representing items to replace. + CalculateVisitationCriteria(); + } + if (this.ShouldVisit(node.FullSpan)) { rewritten = base.Visit(node); } - if (_nodeSet.Contains(node) && _computeReplacementNode != null) + if (isReplacedNode && _computeReplacementNode != null) { rewritten = _computeReplacementNode((TNode)node, (TNode)rewritten!); } @@ -200,13 +223,24 @@ private bool ShouldVisit(TextSpan span) public override SyntaxToken VisitToken(SyntaxToken token) { var rewritten = token; + bool isReplacedToken = _tokenSet.Remove(token); + + if (isReplacedToken) + { + // If token is in _tokenSet, then it contributed to the calculation of _spanSet. + // We are currently processing that token, so it no longer needs to contribute + // to _spanSet and affect determination of inward visitation. This is done before + // calling ShouldVisit to avoid walking into the token if there aren't any remaining + // spans inside it representing items to replace. + CalculateVisitationCriteria(); + } if (_shouldVisitTrivia && this.ShouldVisit(token.FullSpan)) { rewritten = base.VisitToken(token); } - if (_tokenSet.Contains(token) && _computeReplacementToken != null) + if (isReplacedToken && _computeReplacementToken != null) { rewritten = _computeReplacementToken(token, rewritten); } @@ -217,13 +251,24 @@ public override SyntaxToken VisitToken(SyntaxToken token) public override SyntaxTrivia VisitListElement(SyntaxTrivia trivia) { var rewritten = trivia; + bool isReplacedTrivia = _triviaSet.Remove(trivia); + + if (isReplacedTrivia) + { + // If trivia is in _triviaSet, then it contributed to the calculation of _spanSet. + // We are currently processing that trivia, so it no longer needs to contribute + // to _spanSet and affect determination of inward visitation. This is done before + // calling ShouldVisit to avoid walking into the trivia if there aren't any remaining + // spans inside it representing items to replace. + CalculateVisitationCriteria(); + } if (this.VisitIntoStructuredTrivia && trivia.HasStructure && this.ShouldVisit(trivia.FullSpan)) { rewritten = this.VisitTrivia(trivia); } - if (_triviaSet.Contains(trivia) && _computeReplacementTrivia != null) + if (isReplacedTrivia && _computeReplacementTrivia != null) { rewritten = _computeReplacementTrivia(trivia, rewritten); } diff --git a/src/Compilers/CSharp/Portable/Utilities/InterceptableLocation.cs b/src/Compilers/CSharp/Portable/Utilities/InterceptableLocation.cs index 85c76ab47e0e4..049f6878cb7dc 100644 --- a/src/Compilers/CSharp/Portable/Utilities/InterceptableLocation.cs +++ b/src/Compilers/CSharp/Portable/Utilities/InterceptableLocation.cs @@ -18,7 +18,7 @@ namespace Microsoft.CodeAnalysis.CSharp; /// Denotes an interceptable call. Used by source generators to generate '[InterceptsLocation]' attributes. /// /// -public abstract class InterceptableLocation +public abstract class InterceptableLocation : IEquatable { private protected InterceptableLocation() { } @@ -40,6 +40,8 @@ private protected InterceptableLocation() { } public abstract override bool Equals(object? obj); public abstract override int GetHashCode(); + + public abstract bool Equals(InterceptableLocation? other); } #pragma warning disable RSEXPERIMENTAL002 // internal usage of experimental API @@ -167,12 +169,7 @@ public override bool Equals(object? obj) if ((object)this == obj) return true; - return obj is InterceptableLocation1 other - && _checksum.SequenceEqual(other._checksum) - && _path == other._path - && _position == other._position - && _lineNumberOneIndexed == other._lineNumberOneIndexed - && _characterNumberOneIndexed == other._characterNumberOneIndexed; + return obj is InterceptableLocation other && Equals(other); } public override int GetHashCode() @@ -183,4 +180,14 @@ public override int GetHashCode() BinaryPrimitives.ReadInt32LittleEndian(_checksum.AsSpan()), _position); } + + public override bool Equals(InterceptableLocation? obj) + { + return obj is InterceptableLocation1 other + && _checksum.SequenceEqual(other._checksum) + && _path == other._path + && _position == other._position + && _lineNumberOneIndexed == other._lineNumberOneIndexed + && _characterNumberOneIndexed == other._characterNumberOneIndexed; + } } diff --git a/src/Compilers/CSharp/Portable/Utilities/TypeSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Utilities/TypeSymbolExtensions.cs index 75434c8f292c4..d0d250a0be2e4 100644 --- a/src/Compilers/CSharp/Portable/Utilities/TypeSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Utilities/TypeSymbolExtensions.cs @@ -196,7 +196,8 @@ internal static TypeSymbol GetNextBaseTypeNoUseSiteDiagnostics(this TypeSymbol t case TypeKind.Submission: case TypeKind.Pointer: case TypeKind.FunctionPointer: - // Enums, arrays, submissions and delegates know their own base types + case TypeKind.Extension: + // Enums, arrays, submissions, delegates and extensions know their own base types // intrinsically (and do not include interface lists) // so there is no possibility of a cycle. return type.BaseTypeNoUseSiteDiagnostics; diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index c6be2cfc14aa2..2c7fae5bdeaa0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -222,6 +222,11 @@ V asynchronním příkazu foreach nejde použít kolekce dynamického typu. + + Extensions must be declared in a top-level, non-generic, static class + Extensions must be declared in a top-level, non-generic, static class + + The type '{0}' may not be used for a field of a record. Typ {0} se nedá použít pro pole záznamu. @@ -373,8 +378,8 @@ - Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specifc numeric type. - Nelze použít číselnou konstantu ani relační vzor pro „{0}“, protože dědí z nebo rozšiřuje INumberBase<T>. Zvažte použití vzoru typu k zúžení na konkrétní číselný typ. + Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specific numeric type. + Nelze použít číselnou konstantu ani relační vzor pro „{0}“, protože dědí z nebo rozšiřuje INumberBase<T>. Zvažte použití vzoru typu k zúžení na konkrétní číselný typ. @@ -542,6 +547,11 @@ Kopírovací konstruktor {0} musí být veřejný nebo chráněný, protože záznam není zapečetěný. + + Cannot emit this string literal into the data section because it has XXHash128 collision with another string literal: {0} + Cannot emit this string literal into the data section because it has XXHash128 collision with another string literal: {0} + + The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'. Název {0} neodpovídá příslušnému parametru Deconstruct {1}. @@ -639,7 +649,7 @@ Cannot emit update; {0} '{1}' is missing. - Cannot emit update; {0} '{1}' is missing. + Nelze vygenerovat aktualizaci; chybí {0} '{1}' . @@ -717,6 +727,11 @@ Strom výrazů nesmí obsahovat výraz kolekce. + + An expression tree may not contain an extension property access + An expression tree may not contain an extension property access + + An expression tree may not contain a from-end index ('^') expression. Strom výrazů nesmí obsahovat výraz indexu od-do (^). @@ -762,6 +777,26 @@ Strom výrazů nesmí obsahovat výraz with. + + Extension declarations can include only methods or properties + Extension declarations can include only methods or properties + + + + Extension declarations may not have a name. + Extension declarations may not have a name. + + + + The receiver parameter of an extension cannot have a default value + The receiver parameter of an extension cannot have a default value + + + + '{0}' does not contain a definition for '{1}' and no accessible extension member '{1}' for receiver of type '{0}' could be found (are you missing a using directive or an assembly reference?) + '{0}' does not contain a definition for '{1}' and no accessible extension member '{1}' for receiver of type '{0}' could be found (are you missing a using directive or an assembly reference?) + + '{0}': extern event cannot have initializer {0}: Externí událost nemůže mít inicializátor. @@ -1247,6 +1282,11 @@ Argument diagnosticId atributu Experimental musí být platný identifikátor + + Cannot use extension parameter '{0}' in this context. + Cannot use extension parameter '{0}' in this context. + + '{0}' is not a valid function pointer return type modifier. Valid modifiers are 'ref' and 'ref readonly'. {0} není platný modifikátor návratového typu ukazatele na funkci. Platné modifikátory jsou ref a ref readonly. @@ -1339,7 +1379,7 @@ Element type of an iterator may not be a ref struct or a type parameter allowing ref structs - Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + Typ elementu iterátoru nemůže být struktura ref nebo parametr typu povolující struktury ref. @@ -1387,6 +1427,16 @@ Vzory seznamů nelze použít pro hodnotu typu {0}. Nenašla se žádná vhodná vlastnost Length nebo Count. + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + + No overload for '{0}' matches function pointer '{1}' Žádná přetížená metoda {0} neodpovídá ukazateli na funkci {1}. @@ -1687,6 +1737,16 @@ Parametr params musí mít platný typ kolekce. + + '{0}': only the implementing declaration of a partial constructor can have an initializer + '{0}': only the implementing declaration of a partial constructor can have an initializer + + + + '{0}': partial event cannot have initializer + '{0}': partial event cannot have initializer + + Both partial member declarations must have identical accessibility modifiers. Obě deklarace částečných členů musí mít shodné modifikátory přístupnosti. @@ -1697,11 +1757,31 @@ Částečný člen nemůže mít modifikátor abstract. + + Partial member '{0}' may not have multiple defining declarations. + Partial member '{0}' may not have multiple defining declarations. + + + + Partial member '{0}' may not have multiple implementing declarations. + Partial member '{0}' may not have multiple implementing declarations. + + Both partial member declarations, '{0}' and '{1}', must use the same tuple element names. V deklaracích částečných členů, {0} a {1} se musí používat stejné názvy prvků řazené kolekce členů. + + Partial member '{0}' must have a definition part. + Partial member '{0}' must have a definition part. + + + + Partial member '{0}' must have an implementation part. + Partial member '{0}' must have an implementation part. + + A partial member must be declared within a partial type Částečný člen musí být deklarován v rámci částečného typu. @@ -1727,6 +1807,11 @@ Deklarace částečných členů musí mít odpovídající referenční návratové hodnoty. + + Both partial member declarations must have the same type. + Both partial member declarations must have the same type. + + Both partial member declarations must be unsafe or neither may be unsafe Obě deklarace částečného člena musí být nezabezpečené, nebo nesmí být nezabezpečená žádná z nich. @@ -1797,11 +1882,6 @@ Obě deklarace částečných vlastností musí být vyžadovány, nebo nesmí být vyžadována žádná z nich. - - Both partial property declarations must have the same type. - Obě deklarace částečných vlastností musí mít stejný typ. - - Property accessor '{0}' does not implement any accessor declared on the definition part Přístupový objekt vlastnosti {0} neimplementuje žádný přístupový objekt deklarovaný v definiční části. @@ -1862,6 +1942,16 @@ {0}: U přístupových objektů se modifikátor readonly může použít jenom v případě, že vlastnost nebo indexer má přístupový objekt get i set. + + An extension container can have only one receiver parameter + An extension container can have only one receiver parameter + + + + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + + The primary constructor conflicts with the synthesized copy constructor. Primární konstruktor je v konfliktu se syntetizovaně zkopírovaným konstruktorem. @@ -2019,7 +2109,7 @@ The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. - The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + Typ Microsoft.CodeAnalysis.EmbeddedAttribute musí být neobecný, interní, zapečetěný, nestatický, musí mít konstruktor bez parametrů, dědit z System.Attribute a být možné ho použít pro libovolný typ. @@ -2272,6 +2362,16 @@ Aby se typ {0} dal použít jako konvence volání, musí být veřejný. + + Type parameter '{0}' has the same name as an extension parameter + Type parameter '{0}' has the same name as an extension parameter + + + + Type parameter '{0}' has the same name as an extension container type parameter + Type parameter '{0}' has the same name as an extension container type parameter + + Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. Před vrácením řízení volajícímu se musí plně přiřadit automaticky implementovaná vlastnost {0}. Zvažte aktualizaci jazykové verze {1} na automatické výchozí nastavení vlastnosti. @@ -2282,6 +2382,11 @@ Před vrácením řízení volajícímu se musí plně přiřadit pole {0}. Zvažte aktualizaci jazykové verze {1} na automatické výchozí nastavení pole. + + The extended type '{0}' must reference all the type parameters declared by the extension, but type parameter '{1}' is not referenced. + The extended type '{0}' must reference all the type parameters declared by the extension, but type parameter '{1}' is not referenced. + + Unexpected parameter list. Neočekávaný seznam parametrů. @@ -2372,6 +2477,16 @@ Objekt this nelze použít před přiřazením všech jeho polí. Zvažte aktualizaci na jazykovou verzi {0} na automatické výchozí nastavení nepřiřazených polí. + + 'value': an automatically-generated parameter name conflicts with an extension parameter name + 'value': an automatically-generated parameter name conflicts with an extension parameter name + + + + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + + In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. @@ -2442,6 +2557,11 @@ vzory rozšířených vlastností + + extensions + extensions + + field keyword klíčové slovo pole @@ -2459,7 +2579,7 @@ first-class Span types - first-class Span types + typy span první třídy @@ -2539,7 +2659,7 @@ overload resolution priority - overload resolution priority + priorita řešení přetížení @@ -2552,6 +2672,11 @@ kolekce parametrů + + partial events and constructors + partial events and constructors + + positional fields in records pozice polí v záznamech @@ -2624,7 +2749,7 @@ unbound generic types in nameof operator - unbound generic types in nameof operator + nevázané obecné typy v operátoru nameof @@ -2714,12 +2839,12 @@ The '{0}' accessor of property '{1}' should use 'field' because the other accessor is using it. - The '{0}' accessor of property '{1}' should use 'field' because the other accessor is using it. + Přístupový objekt '{0}' vlastnosti '{1}' by měl používat vlastnost field, protože ho používá jiný přístupový objekt. Property accessor should use 'field' because the other accessor is using it. - Property accessor should use 'field' because the other accessor is using it. + Přístupový objekt vlastnosti by měl používat pole, protože ho používá jiný přístupový objekt. @@ -2743,13 +2868,13 @@ - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - Sestavení analyzátoru {0} odkazuje na verzi {1} kompilátoru, která je novější než aktuálně spuštěná verze {2}. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + Sestavení analyzátoru {0} odkazuje na verzi {1} kompilátoru, která je novější než aktuálně spuštěná verze {2}. - The analyzer assembly references a newer version of the compiler than the currently running version. - Sestavení analyzátoru odkazuje na novější verzi kompilátoru, než je aktuálně spuštěná verze. + Analyzer assembly cannot be used because it references a newer version of the compiler than the currently running version. + Sestavení analyzátoru odkazuje na novější verzi kompilátoru, než je aktuálně spuštěná verze. @@ -2994,12 +3119,12 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + {0} slouží jen pro účely vyhodnocení a v budoucích aktualizacích může dojít ke změně nebo odebrání: {1}. Potlačte tuto diagnostiku, abyste mohli pokračovat. Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + Typ slouží jen pro účely vyhodnocení a v budoucích aktualizacích může dojít ke změnám nebo odebrání. Potlačte tuto diagnostiku, abyste mohli pokračovat. @@ -3074,12 +3199,12 @@ 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) - 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + InterceptsLocationAttribute(string, int, int) se nepodporuje. Přesuňte se místo toho na generování těchto atributů založené na InterceptableLocation. (https://github.com/dotnet/roslyn/issues/72133) 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) - 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + InterceptsLocationAttribute(string, int, int) se nepodporuje. Přesuňte se místo toho na generování těchto atributů založené na InterceptableLocation. (https://github.com/dotnet/roslyn/issues/72133) @@ -3212,14 +3337,14 @@ Parametr má modifikátor params ve výrazu lambda, ale ne v cílovém typu delegáta. - - Partial property declarations '{0}' and '{1}' have signature differences. - Deklarace částečných vlastností {0} a {1} mají rozdíly v signaturách. + + Partial member declarations '{0}' and '{1}' have signature differences. + Partial member declarations '{0}' and '{1}' have signature differences. - - Partial property declarations have signature differences. - Deklarace částečných vlastností mají rozdíly v signaturách. + + Partial member declarations have signature differences. + Partial member declarations have signature differences. @@ -3868,7 +3993,7 @@ -appconfig:<file> Zadejte konfigurační soubor aplikace obsahující nastavení vazby sestavení -moduleassemblyname:<string> Název sestavení, jehož součástí bude - částí + částí -modulename:<string> Zadejte název zdrojového modulu -generatedfilesout:<dir> Umístí soubory vygenerované během kompilace do zadaného adresáře. @@ -5300,12 +5425,12 @@ Field '{0}' is never ref-assigned to, and will always have its default value (null reference) - Field '{0}' is never ref-assigned to, and will always have its default value (null reference) + Do pole {0} se nikdy nepřiřadí referenční pole. Bude mít vždy výchozí hodnotu (odkaz null). Field is never ref-assigned to, and will always have its default value (null reference) - Field is never ref-assigned to, and will always have its default value (null reference) + Do pole se nikdy nepřiřadí referenční pole. Bude mít vždy výchozí hodnotu (odkaz null). @@ -5379,12 +5504,12 @@ - Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or safely handling the case where 'field' is null in the 'get' accessor. Proměnná {0} {1}, která nemůže být null, musí při ukončování konstruktoru obsahovat hodnotu, která není null. Zvažte přidání modifikátoru required, deklaraci {0} jako s možnou hodnotou null nebo přidání atributů [field: MaybeNull, AllowNull]. Similar diagnostic message as 'WRN_UninitializedNonNullableField' - Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. Při ukončovacím konstruktoru musí vlastnost, která nemůže mít hodnotu null, obsahovat hodnotu, která není null. Zvažte přidání modifikátoru required, deklaraci vlastnosti jako s možnou hodnotou null nebo přidání atributů [field: MaybeNull, AllowNull]. @@ -5420,12 +5545,12 @@ UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. - UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute je platný jenom v C# 11 nebo novějším nebo při cílení na net7.0 nebo novější. UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. - UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute je platný jenom v C# 11 nebo novějším nebo při cílení na net7.0 nebo novější. @@ -6729,8 +6854,8 @@ - The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. - Modifikátor partial se může objevit jen bezprostředně před klíčovými slovy class, record, struct, interface nebo návratovým typem metody nebo vlastnosti. + The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. + Modifikátor partial se může objevit jen bezprostředně před klíčovými slovy class, record, struct, interface nebo návratovým typem metody nebo vlastnosti. @@ -8832,8 +8957,8 @@ Blok catch() po bloku catch (System.Exception e) může zachytit výjimky, kter - Cannot define a new extension method because the compiler required type '{0}' cannot be found. Are you missing a reference to System.Core.dll? - Nejde definovat novou metodu rozšíření, protože se nenašel vyžadovaný typ kompilátoru {0}. Nechybí odkaz na System.Core.dll? + Cannot define a new extension because the compiler required type '{0}' cannot be found. Are you missing a reference to System.Core.dll? + Nejde definovat novou metodu rozšíření, protože se nenašel vyžadovaný typ kompilátoru {0}. Nechybí odkaz na System.Core.dll? @@ -8927,8 +9052,8 @@ Blok catch() po bloku catch (System.Exception e) může zachytit výjimky, kter - Invalid token '{0}' in class, record, struct, or interface member declaration - Neplatný token {0} v deklaraci člena rozhraní, třídy, záznamu nebo struktury + Invalid token '{0}' in a member declaration + Neplatný token {0} v deklaraci člena rozhraní, třídy, záznamu nebo struktury @@ -10376,7 +10501,7 @@ Poskytněte kompilátoru nějaký způsob, jak metody rozlišit. Můžete např Cannot open '{0}' for writing -- {1} - {0} se nedá otevřít pro zápis -- {1}. + {0} se nedá otevřít pro zápis -- {1}. @@ -12741,7 +12866,7 @@ Pokud chcete odstranit toto varování, můžete místo toho použít /reference Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string literals or try the EXPERIMENTAL feature flag 'experimental-data-section-string-literals'. - Kombinovaná délka uživatelských řetězců, které používá tento program, překročila povolený limit. Zkuste omezit použití řetězcových literálů. + Kombinovaná délka uživatelských řetězců, které používá tento program, překročila povolený limit. Zkuste omezit používání řetězcových literálů nebo zkuste použít příznak funkce EXPERIMENTAL experimental-data-section-string-literals. @@ -13036,7 +13161,7 @@ Pokud chcete odstranit toto varování, můžete místo toho použít /reference '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + {0} slouží jen pro účely vyhodnocení a v budoucích aktualizacích může dojít ke změně nebo odebrání. Potlačte tuto diagnostiku, abyste mohli pokračovat. @@ -13091,7 +13216,7 @@ Pokud chcete odstranit toto varování, můžete místo toho použít /reference Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Informace o ladění metody {0} (token 0x{1:X8}) ze sestavení {2} nelze přečíst: {3} diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 2540a66dc2470..12f4e0af2928f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -222,6 +222,11 @@ Eine Sammlung des dynamic-Typs kann in einem asynchronen foreach nicht verwendet werden. + + Extensions must be declared in a top-level, non-generic, static class + Extensions must be declared in a top-level, non-generic, static class + + The type '{0}' may not be used for a field of a record. Der Typ "{0}" darf nicht für ein Feld eines Datensatzes verwendet werden. @@ -373,8 +378,8 @@ - Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specifc numeric type. - Für "{0}" kann keine numerische Konstante oder ein relationales Muster verwendet werden, da es von "INumberBase<T>" vererbt oder erweitert wird. Erwägen Sie die Verwendung eines Typmusters, um auf einen bestimmten numerischen Typ einzugrenzen. + Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specific numeric type. + Für "{0}" kann keine numerische Konstante oder ein relationales Muster verwendet werden, da es von "INumberBase<T>" vererbt oder erweitert wird. Erwägen Sie die Verwendung eines Typmusters, um auf einen bestimmten numerischen Typ einzugrenzen. @@ -542,6 +547,11 @@ Der Kopierkonstruktor "{0}" muss öffentlich oder geschützt sein, weil der Datensatz nicht versiegelt ist. + + Cannot emit this string literal into the data section because it has XXHash128 collision with another string literal: {0} + Cannot emit this string literal into the data section because it has XXHash128 collision with another string literal: {0} + + The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'. Der Name "{0}" stimmt nicht mit dem entsprechenden Deconstruct-Parameter "{1}" überein. @@ -639,7 +649,7 @@ Cannot emit update; {0} '{1}' is missing. - Cannot emit update; {0} '{1}' is missing. + Update kann nicht ausgeben; {0} '{1}' fehlt. @@ -717,6 +727,11 @@ Eine Ausdrucksbaumstruktur darf keinen Sammlungsausdruck enthalten. + + An expression tree may not contain an extension property access + An expression tree may not contain an extension property access + + An expression tree may not contain a from-end index ('^') expression. Eine Ausdrucksbaumstruktur darf keinen vom Ende ausgehenden Indexausdruck ("^") enthalten. @@ -762,6 +777,26 @@ Eine Ausdrucksbaumstruktur darf keinen with-Ausdruck enthalten. + + Extension declarations can include only methods or properties + Extension declarations can include only methods or properties + + + + Extension declarations may not have a name. + Extension declarations may not have a name. + + + + The receiver parameter of an extension cannot have a default value + The receiver parameter of an extension cannot have a default value + + + + '{0}' does not contain a definition for '{1}' and no accessible extension member '{1}' for receiver of type '{0}' could be found (are you missing a using directive or an assembly reference?) + '{0}' does not contain a definition for '{1}' and no accessible extension member '{1}' for receiver of type '{0}' could be found (are you missing a using directive or an assembly reference?) + + '{0}': extern event cannot have initializer "{0}": Externes Ereignis darf keinen Initialisierer aufweisen. @@ -1247,6 +1282,11 @@ Das diagnosticId-Argument für das Experimental-Attribut muss ein gültiger Bezeichner sein. + + Cannot use extension parameter '{0}' in this context. + Cannot use extension parameter '{0}' in this context. + + '{0}' is not a valid function pointer return type modifier. Valid modifiers are 'ref' and 'ref readonly'. "{0}" ist kein gültiger Rückgabetyp-Modifizierer für Funktionszeiger. Gültige Modifizierer sind "ref" und "ref readonly". @@ -1339,7 +1379,7 @@ Element type of an iterator may not be a ref struct or a type parameter allowing ref structs - Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + Der Elementtyp eines Iterators darf keine Verweisstruktur oder kein Typparameter sein, der Verweisstrukturen zulässt. @@ -1387,6 +1427,16 @@ Listenmuster dürfen nicht für einen Wert vom Typ „{0}“ verwendet werden. Es wurde keine geeignete Längen- oder Anzahl-Eigenschaft gefunden. + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + + No overload for '{0}' matches function pointer '{1}' Keine Überladung für "{0}" stimmt mit dem Funktionszeiger "{1}" überein. @@ -1687,6 +1737,16 @@ Der Params-Parameter muss einen gültigen Sammlungstyp aufweisen + + '{0}': only the implementing declaration of a partial constructor can have an initializer + '{0}': only the implementing declaration of a partial constructor can have an initializer + + + + '{0}': partial event cannot have initializer + '{0}': partial event cannot have initializer + + Both partial member declarations must have identical accessibility modifiers. Beide Deklarationen des partiellen Mitglieds müssen identische Zugriffsmodifizierer aufweisen. @@ -1697,11 +1757,31 @@ Ein partielles Mitglied darf nicht den Modifizierer "abstract" aufweisen. + + Partial member '{0}' may not have multiple defining declarations. + Partial member '{0}' may not have multiple defining declarations. + + + + Partial member '{0}' may not have multiple implementing declarations. + Partial member '{0}' may not have multiple implementing declarations. + + Both partial member declarations, '{0}' and '{1}', must use the same tuple element names. Beide Deklarationen des partiellen Mitglieds ("{0}" und "{1}") müssen die gleichen Tupelelementnamen verwenden. + + Partial member '{0}' must have a definition part. + Partial member '{0}' must have a definition part. + + + + Partial member '{0}' must have an implementation part. + Partial member '{0}' must have an implementation part. + + A partial member must be declared within a partial type Ein partielles Mitglied muss innerhalb eines partiellen Typs deklariert sein. @@ -1727,6 +1807,11 @@ Deklarationen partieller Mitglieder müssen übereinstimmende Ref-Rückgabewerte aufweisen. + + Both partial member declarations must have the same type. + Both partial member declarations must have the same type. + + Both partial member declarations must be unsafe or neither may be unsafe Beide Deklarationen des partiellen Mitglieds müssen unsicher sein, oder keine von beiden darf unsicher sein. @@ -1797,11 +1882,6 @@ Entweder beide oder keine der Deklarationen der partiellen Eigenschaft müssen als "required" festgelegt werden. - - Both partial property declarations must have the same type. - Beide Deklarationen der partiellen Eigenschaft müssen den gleichen Typ aufweisen. - - Property accessor '{0}' does not implement any accessor declared on the definition part Der Eigenschaftenaccessor "{0}" implementiert keinen Accessor, der für den Definitionsteil deklariert wurde. @@ -1862,6 +1942,16 @@ {0}: "readonly" kann für Accessoren nur verwendet werden, wenn die Eigenschaft oder der Indexer sowohl einen get- als auch einen set-Accessor aufweist. + + An extension container can have only one receiver parameter + An extension container can have only one receiver parameter + + + + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + + The primary constructor conflicts with the synthesized copy constructor. Der primäre Konstruktor verursacht einen Konflikt mit dem synthetisierten Kopierkonstruktor. @@ -2019,7 +2109,7 @@ The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. - The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + Der Typ "Microsoft.CodeAnalysis.EmbeddedAttribute" muss nicht generisch, intern, versiegelt oder nicht statisch sein, einen parameterlosen Konstruktor aufweisen, von System.Attribute erben und auf einen beliebigen Typ angewendet werden können. @@ -2272,6 +2362,16 @@ Der Typ "{0}" muss öffentlich sein, damit er als Aufrufkonvention verwendet werden kann. + + Type parameter '{0}' has the same name as an extension parameter + Type parameter '{0}' has the same name as an extension parameter + + + + Type parameter '{0}' has the same name as an extension container type parameter + Type parameter '{0}' has the same name as an extension container type parameter + + Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. Die automatisch implementierte Eigenschaft '{0}' muss vollständig zugewiesen werden, bevor das Steuerelement an den Aufrufer zurückgegeben wird. Erwägen Sie eine Aktualisierung auf die Sprachversion '{1}', um die Eigenschaft automatisch als Standard zu verwenden. @@ -2282,6 +2382,11 @@ Das Feld "{0}" muss vollständig zugewiesen werden, bevor das Steuerelement an den Aufrufer zurückgegeben wird. Aktualisieren Sie ggf. auf die Sprachversion "{1}", um das Feld automatisch als Standard zu verwenden. + + The extended type '{0}' must reference all the type parameters declared by the extension, but type parameter '{1}' is not referenced. + The extended type '{0}' must reference all the type parameters declared by the extension, but type parameter '{1}' is not referenced. + + Unexpected parameter list. Unerwartete Parameterliste. @@ -2372,6 +2477,16 @@ Das „this“-Objekt kann nicht verwendet werden, bevor alle zugehörigen Felder zugewiesen wurden. Aktualisieren Sie ggf. auf die Sprachversion „{0}“, um die nicht zugewiesenen Felder automatisch als Standard zu verwenden. + + 'value': an automatically-generated parameter name conflicts with an extension parameter name + 'value': an automatically-generated parameter name conflicts with an extension parameter name + + + + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + + In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. @@ -2442,6 +2557,11 @@ Muster für erweiterte Eigenschaften + + extensions + extensions + + field keyword Feld Schlüsselwort @@ -2459,7 +2579,7 @@ first-class Span types - first-class Span types + Bereichstypen der ersten Klasse @@ -2539,7 +2659,7 @@ overload resolution priority - overload resolution priority + Priorität der Überladungsauflösung @@ -2552,6 +2672,11 @@ Params-Sammlungen + + partial events and constructors + partial events and constructors + + positional fields in records Positionsfelder in Datensätzen @@ -2624,7 +2749,7 @@ unbound generic types in nameof operator - unbound generic types in nameof operator + Ungebundene generische Typen im nameof-Operator @@ -2714,12 +2839,12 @@ The '{0}' accessor of property '{1}' should use 'field' because the other accessor is using it. - The '{0}' accessor of property '{1}' should use 'field' because the other accessor is using it. + Der '{0}' Accessor der Eigenschaft '{1}' sollte "field" verwenden, da der andere Accessor diesen verwendet. Property accessor should use 'field' because the other accessor is using it. - Property accessor should use 'field' because the other accessor is using it. + Der Eigenschaftenaccessor sollte "field" verwenden, da der andere Accessor es verwendet. @@ -2743,13 +2868,13 @@ - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - Die Analyzerassembly „{0}“ verweist auf Version „{1}“ des Compilers, die neuer ist als die aktuell ausgeführte Version „{2}“. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + Die Analyzerassembly „{0}“ verweist auf Version „{1}“ des Compilers, die neuer ist als die aktuell ausgeführte Version „{2}“. - The analyzer assembly references a newer version of the compiler than the currently running version. - Die Analyzerassembly verweist auf eine neuere Version des Compilers als die derzeit ausgeführte Version. + Analyzer assembly cannot be used because it references a newer version of the compiler than the currently running version. + Die Analyzerassembly verweist auf eine neuere Version des Compilers als die derzeit ausgeführte Version. @@ -2994,12 +3119,12 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + „{0}“ dient nur zu Evaluierungszwecken und kann in zukünftigen Updates geändert oder entfernt werden: „{1}“. Unterdrücken Sie diese Diagnose, um fortzufahren. Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + Der Typ dient nur zu Testzwecken und kann in zukünftigen Aktualisierungen geändert oder entfernt werden. Unterdrücken Sie diese Diagnose, um fortzufahren. @@ -3074,12 +3199,12 @@ 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) - 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + "InterceptsLocationAttribute(string, int, int)" wird nicht unterstützt. Wechseln Sie stattdessen zur "InterceptableLocation"-basierten Generierung dieser Attribute. (https://github.com/dotnet/roslyn/issues/72133) 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) - 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + "InterceptsLocationAttribute(string, int, int)" wird nicht unterstützt. Wechseln Sie stattdessen zur "InterceptableLocation"-basierten Generierung dieser Attribute. (https://github.com/dotnet/roslyn/issues/72133) @@ -3212,14 +3337,14 @@ Der Parameter verfügt über den Modifizierer „params“ in der Lambdafunktion, aber nicht im Delegattyp des Ziels. - - Partial property declarations '{0}' and '{1}' have signature differences. - Die Deklarationen der partiellen Eigenschaft "{0}" und "{1}" weisen Signaturunterschiede auf. + + Partial member declarations '{0}' and '{1}' have signature differences. + Partial member declarations '{0}' and '{1}' have signature differences. - - Partial property declarations have signature differences. - Die Deklarationen der partiellen Eigenschaft "" und "" weisen Signaturunterschiede auf. + + Partial member declarations have signature differences. + Partial member declarations have signature differences. @@ -3289,7 +3414,7 @@ This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escape scopes than '{1}'. - Dieser weist „{1}“ für „{0}“ zu, aber „{1}“ hat einen breiteren Werte-Escapebereich als „{0}“, wodurch die Zuweisung über „{0}“ von Werten mit engeren Escapebereichen als „{1}“ ermöglicht wird. + Dieser weist „{1}“ „{0}“ zu, aber „{1}“ hat einen breiteren Werte-Escapebereich als „{0}“, wodurch die Zuweisung über „{0}“ von Werten mit engeren Escapebereichen als „{1}“ ermöglicht wird. @@ -5300,12 +5425,12 @@ Field '{0}' is never ref-assigned to, and will always have its default value (null reference) - Field '{0}' is never ref-assigned to, and will always have its default value (null reference) + Dem Feld „{0}“ wird nie etwas zugewiesen, und es hat immer seinen Standardwert (NULL-Verweis). Field is never ref-assigned to, and will always have its default value (null reference) - Field is never ref-assigned to, and will always have its default value (null reference) + Dem Feld wird nie etwas zugewiesen, und es hat immer seinen Standardwert (NULL-Verweis). @@ -5379,12 +5504,12 @@ - Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or safely handling the case where 'field' is null in the 'get' accessor. Non-Nullable-{0} "{1}" muss beim Beenden des Konstruktors einen Wert ungleich NULL enthalten. Fügen Sie ggf. den Modifizierer "required" hinzu, oder deklarieren Sie die {0} als Nullwerte zulassend, oder fügen Sie "[field: MaybeNull, AllowNull] "-Attribute hinzu. Similar diagnostic message as 'WRN_UninitializedNonNullableField' - Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. Non-Nullable-Eigenschaft muss beim Beenden des Konstruktors einen Wert ungleich NULL enthalten. Fügen Sie ggf. den Modifizierer "required" hinzu, oder deklarieren Sie die Eigenschaft als Nullwerte zulassend, oder fügen Sie "[field: MaybeNull, AllowNull] "-Attribute hinzu. @@ -5420,12 +5545,12 @@ UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. - UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute ist nur in C# 11 oder höher oder bei net7.0 oder höher gültig. UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. - UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute ist nur in C# 11 oder höher oder bei net7.0 oder höher gültig. @@ -6729,8 +6854,8 @@ - The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. - Der partial-Modifizierer kann nur unmittelbar vor "class", "record", "struct", "interface" oder einem Methoden- Eigenschaftsrückgabetyp verwendet werden. + The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. + Der partial-Modifizierer kann nur unmittelbar vor "class", "record", "struct", "interface" oder einem Methoden- Eigenschaftsrückgabetyp verwendet werden. @@ -8832,8 +8957,8 @@ Ein catch()-Block nach einem catch (System.Exception e)-Block kann nicht-CLS-Aus - Cannot define a new extension method because the compiler required type '{0}' cannot be found. Are you missing a reference to System.Core.dll? - Es kann keine neue Erweiterungsmethode definiert werden, weil der für den Compiler erforderliche Typ "{0}" nicht gefunden werden kann. Fehlt möglicherweise ein Verweis auf "System.Core.dll"? + Cannot define a new extension because the compiler required type '{0}' cannot be found. Are you missing a reference to System.Core.dll? + Es kann keine neue Erweiterungsmethode definiert werden, weil der für den Compiler erforderliche Typ "{0}" nicht gefunden werden kann. Fehlt möglicherweise ein Verweis auf "System.Core.dll"? @@ -8927,8 +9052,8 @@ Ein catch()-Block nach einem catch (System.Exception e)-Block kann nicht-CLS-Aus - Invalid token '{0}' in class, record, struct, or interface member declaration - Ungültiges Token "{0}" in Klassen-, Datensatz-, Struktur- oder Schnittstellenmemberdeklaration + Invalid token '{0}' in a member declaration + Ungültiges Token "{0}" in Klassen-, Datensatz-, Struktur- oder Schnittstellenmemberdeklaration @@ -10376,7 +10501,7 @@ Unterstützen Sie den Compiler bei der Unterscheidung zwischen den Methoden. Daz Cannot open '{0}' for writing -- {1} - "{0}" kann nicht zum Schreiben geöffnet werden: "{1}" + „{0}“ kann nicht zum Schreiben geöffnet werden – "{1}" @@ -12741,7 +12866,7 @@ Um die Warnung zu beheben, können Sie stattdessen /reference verwenden (Einbett Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string literals or try the EXPERIMENTAL feature flag 'experimental-data-section-string-literals'. - Die kombinierte Länge der vom Programm verwendeten Benutzerzeichenfolgen überschreitet den zulässigen Grenzwert. Versuchen Sie, die Verwendung von Zeichenfolgenliteralen zu verringern. + Die kombinierte Länge der vom Programm verwendeten Benutzerzeichenfolgen überschreitet den zulässigen Grenzwert. Versuchen Sie, die Verwendung von Zeichenfolgenliteralen zu verringern, oder testen Sie das EXPERIMENTAL-Featureflag „experimental-data-section-string-literals“. @@ -13036,7 +13161,7 @@ Um die Warnung zu beheben, können Sie stattdessen /reference verwenden (Einbett '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + "{0}" dient nur zu Testzwecken und kann in zukünftigen Aktualisierungen geändert oder entfernt werden. Unterdrücken Sie diese Diagnose, um fortzufahren. @@ -13091,7 +13216,7 @@ Um die Warnung zu beheben, können Sie stattdessen /reference verwenden (Einbett Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Die Debuginformationen der Methode „{0}“ (Token 0x{1:X8}) können nicht aus der Assembly „{2}“ gelesen werden: {3} diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 5f97bbfc2a425..6d3fa95a32609 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -222,6 +222,11 @@ No se puede usar una colección de tipo dinámico en una instrucción foreach asincrónica. + + Extensions must be declared in a top-level, non-generic, static class + Extensions must be declared in a top-level, non-generic, static class + + The type '{0}' may not be used for a field of a record. No se puede usar el tipo "{0}" para un campo de un registro. @@ -373,8 +378,8 @@ - Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specifc numeric type. - No se puede usar una constante numérica o un patrón relacional en '{0}' porque hereda o extiende 'INumberBase<T>'. Considere la posibilidad de usar un patrón de tipo para restringir a un tipo numérico específico. + Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specific numeric type. + No se puede usar una constante numérica o un patrón relacional en '{0}' porque hereda o extiende 'INumberBase<T>'. Considere la posibilidad de usar un patrón de tipo para restringir a un tipo numérico específico. @@ -542,6 +547,11 @@ Un constructor de copia "{0}" debe ser público o estar protegido porque el registro no está sellado. + + Cannot emit this string literal into the data section because it has XXHash128 collision with another string literal: {0} + Cannot emit this string literal into the data section because it has XXHash128 collision with another string literal: {0} + + The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'. El nombre "{0}" no coincide con el parámetro de "Deconstruct" correspondiente, "{1}". @@ -639,7 +649,7 @@ Cannot emit update; {0} '{1}' is missing. - Cannot emit update; {0} '{1}' is missing. + No se puede emitir la actualización; falta {0} '{1}' . @@ -717,6 +727,11 @@ Un árbol de expresión no puede contener una expresión de colección. + + An expression tree may not contain an extension property access + An expression tree may not contain an extension property access + + An expression tree may not contain a from-end index ('^') expression. Un árbol de expresión no puede contener una expresión de índice del otro extremo ("^"). @@ -762,6 +777,26 @@ Un árbol de expresión no puede contener una expresión with. + + Extension declarations can include only methods or properties + Extension declarations can include only methods or properties + + + + Extension declarations may not have a name. + Extension declarations may not have a name. + + + + The receiver parameter of an extension cannot have a default value + The receiver parameter of an extension cannot have a default value + + + + '{0}' does not contain a definition for '{1}' and no accessible extension member '{1}' for receiver of type '{0}' could be found (are you missing a using directive or an assembly reference?) + '{0}' does not contain a definition for '{1}' and no accessible extension member '{1}' for receiver of type '{0}' could be found (are you missing a using directive or an assembly reference?) + + '{0}': extern event cannot have initializer "{0}": un evento externo no puede tener un inicializador @@ -1247,6 +1282,11 @@ El argumento diagnosticId del atributo "Experimental" debe ser un identificador válido. + + Cannot use extension parameter '{0}' in this context. + Cannot use extension parameter '{0}' in this context. + + '{0}' is not a valid function pointer return type modifier. Valid modifiers are 'ref' and 'ref readonly'. "{0}" no es un modificador de tipo de valor devuelto de puntero de función válido. Los modificadores válidos son "ref" y "ref readonly". @@ -1339,7 +1379,7 @@ Element type of an iterator may not be a ref struct or a type parameter allowing ref structs - Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + El tipo de elemento de un iterador no puede ser un struct ref ni un parámetro de tipo que permita estructuras ref @@ -1387,6 +1427,16 @@ No se pueden usar patrones de lista para un valor de tipo \"{0}\". No se encontró ninguna propiedad \"Length\" o \"Count\" adecuada. + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + + No overload for '{0}' matches function pointer '{1}' Ninguna sobrecarga correspondiente a "{0}" coincide con el puntero de función "{1}". @@ -1687,6 +1737,16 @@ El parámetro params debe tener un tipo de colección válido + + '{0}': only the implementing declaration of a partial constructor can have an initializer + '{0}': only the implementing declaration of a partial constructor can have an initializer + + + + '{0}': partial event cannot have initializer + '{0}': partial event cannot have initializer + + Both partial member declarations must have identical accessibility modifiers. Ambas declaraciones de miembro parcial deben tener modificadores de accesibilidad idénticos. @@ -1697,11 +1757,31 @@ Un miembro parcial no puede tener el modificador 'abstract' + + Partial member '{0}' may not have multiple defining declarations. + Partial member '{0}' may not have multiple defining declarations. + + + + Partial member '{0}' may not have multiple implementing declarations. + Partial member '{0}' may not have multiple implementing declarations. + + Both partial member declarations, '{0}' and '{1}', must use the same tuple element names. Ambas declaraciones de miembro parcial, '{0}' y '{1}', deben usar los mismos nombres de elemento de tupla. + + Partial member '{0}' must have a definition part. + Partial member '{0}' must have a definition part. + + + + Partial member '{0}' must have an implementation part. + Partial member '{0}' must have an implementation part. + + A partial member must be declared within a partial type Un miembro parcial debe declararse dentro de un tipo parcial @@ -1727,6 +1807,11 @@ Las declaraciones de miembros parciales deben tener valores devueltos de referencia coincidentes. + + Both partial member declarations must have the same type. + Both partial member declarations must have the same type. + + Both partial member declarations must be unsafe or neither may be unsafe Ambas declaraciones de miembros parciales deben ser no seguras o ninguna de ellas puede no ser segura @@ -1797,11 +1882,6 @@ Ambas declaraciones de propiedades parciales deben ser obligatorias o ninguna de ellas podrá serlo - - Both partial property declarations must have the same type. - Ambas declaraciones de propiedad parcial deben tener el mismo tipo. - - Property accessor '{0}' does not implement any accessor declared on the definition part El descriptor de acceso de propiedad '{0}' no implementa ningún descriptor de acceso declarado en la parte de definición @@ -1862,6 +1942,16 @@ "{0}": "readonly" solo se puede usar en los descriptores de acceso si la propiedad o el indexador tienen un descriptor de acceso get y set + + An extension container can have only one receiver parameter + An extension container can have only one receiver parameter + + + + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + + The primary constructor conflicts with the synthesized copy constructor. El constructor principal está en conflicto con el constructor de copia sintetizado. @@ -1884,7 +1974,7 @@ Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escape scopes than '{1}'. - No se puede asignar referencia de “{1}” a “{0}” porque “{1}” tiene un ámbito de escape de valor más amplio que “{0}” lo que permite la asignación mediante “{0}” de valores con ámbitos de escape más estrechos que “{1}”. + No se puede asignar referencia de "{1}" a "{0}" porque "{1}" tiene un ámbito de escape de valor más amplio que "{0}" lo que permite la asignación mediante "{0}" de valores con ámbitos de escape más estrechos que "{1}". @@ -2019,7 +2109,7 @@ The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. - The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + El tipo "Microsoft.CodeAnalysis.EmbeddedAttribute" debe ser no genérico, interno, sellado, no estático, tener un constructor sin parámetros, heredar de System.Attribute y poder aplicarse a cualquier tipo. @@ -2272,6 +2362,16 @@ El tipo "{0}" debe ser público para poder usarlo como convención de llamada. + + Type parameter '{0}' has the same name as an extension parameter + Type parameter '{0}' has the same name as an extension parameter + + + + Type parameter '{0}' has the same name as an extension container type parameter + Type parameter '{0}' has the same name as an extension container type parameter + + Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. La propiedad implementada automáticamente '{0}' debe estar totalmente asignada antes de que el control se devuelva al autor de la llamada. Considere la posibilidad de actualizar a la versión de idioma "{1}" para establecer automáticamente el valor predeterminado de la propiedad. @@ -2282,6 +2382,11 @@ El campo '{0}' debe estar totalmente asignado antes de que el control se devuelva al autor de la llamada. Considere la posibilidad de actualizar a la versión de idioma "{1}" para establecer automáticamente el valor predeterminado del campo. + + The extended type '{0}' must reference all the type parameters declared by the extension, but type parameter '{1}' is not referenced. + The extended type '{0}' must reference all the type parameters declared by the extension, but type parameter '{1}' is not referenced. + + Unexpected parameter list. Lista de parámetros inesperada. @@ -2372,6 +2477,16 @@ No se puede usar el objeto 'this' antes de que se hayan asignado todos sus campos. Considere la posibilidad de actualizar a la versión de idioma "{0}" para establecer automáticamente el valor predeterminado de los campos sin asignar. + + 'value': an automatically-generated parameter name conflicts with an extension parameter name + 'value': an automatically-generated parameter name conflicts with an extension parameter name + + + + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + + In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. @@ -2442,6 +2557,11 @@ patrones de propiedad extendidos + + extensions + extensions + + field keyword palabra clave field @@ -2459,7 +2579,7 @@ first-class Span types - first-class Span types + tipos span de primera clase @@ -2539,7 +2659,7 @@ overload resolution priority - overload resolution priority + prioridad de resolución de sobrecarga @@ -2552,6 +2672,11 @@ colecciones params + + partial events and constructors + partial events and constructors + + positional fields in records campos posicionales en registros @@ -2624,7 +2749,7 @@ unbound generic types in nameof operator - unbound generic types in nameof operator + tipos genéricos no enlazados en el operador nameof @@ -2714,12 +2839,12 @@ The '{0}' accessor of property '{1}' should use 'field' because the other accessor is using it. - The '{0}' accessor of property '{1}' should use 'field' because the other accessor is using it. + El descriptor de acceso '{0}' de la propiedad '{1}' debe usar "field" porque el otro descriptor de acceso lo está usando. Property accessor should use 'field' because the other accessor is using it. - Property accessor should use 'field' because the other accessor is using it. + El descriptor de acceso de la propiedad debe usar "field" porque el otro descriptor de acceso lo está usando. @@ -2743,13 +2868,13 @@ - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - El ensamblado del analizador ”{0}” hace referencia a la versión ”{1}” del compilador, que es más reciente que la versión "{2}" que se está ejecutando actualmente. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + El ensamblado del analizador ”{0}” hace referencia a la versión ”{1}” del compilador, que es más reciente que la versión "{2}" que se está ejecutando actualmente. - The analyzer assembly references a newer version of the compiler than the currently running version. - El ensamblado del analizador hace referencia a una versión más reciente del compilador que la versión que se está ejecutando actualmente. + Analyzer assembly cannot be used because it references a newer version of the compiler than the currently running version. + El ensamblado del analizador hace referencia a una versión más reciente del compilador que la versión que se está ejecutando actualmente. @@ -2994,12 +3119,12 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + ''{0}'' es solo para fines de evaluación y está sujeto a cambios o eliminaciones en futuras actualizaciones: ''{1}''. Suprima este diagnóstico para continuar. Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + Este tipo se incluye solo con fines de evaluación y está sujeto a cambios o a que se elimine en próximas actualizaciones. Suprima este diagnóstico para continuar. @@ -3074,12 +3199,12 @@ 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) - 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + No se admite 'InterceptsLocationAttribute(string, int, int)'. En su lugar, vaya a la generación basada en "InterceptableLocation" de estos atributos. (https://github.com/dotnet/roslyn/issues/72133) 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) - 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + No se admite 'InterceptsLocationAttribute(string, int, int)'. En su lugar, vaya a la generación basada en "InterceptableLocation" de estos atributos. (https://github.com/dotnet/roslyn/issues/72133) @@ -3212,14 +3337,14 @@ El parámetro tiene modificador de parámetros en lambda, pero no en el tipo delegado de destino. - - Partial property declarations '{0}' and '{1}' have signature differences. - Las declaraciones de propiedades parciales '{0}' y '{1}' tienen diferencias de firma. + + Partial member declarations '{0}' and '{1}' have signature differences. + Partial member declarations '{0}' and '{1}' have signature differences. - - Partial property declarations have signature differences. - Las declaraciones de propiedades parciales tienen diferencias de firma. + + Partial member declarations have signature differences. + Partial member declarations have signature differences. @@ -3289,7 +3414,7 @@ This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escape scopes than '{1}'. - Esta referencia asigna “{1}” a “{0}” pero “{1}” tiene un ámbito de escape de valor más amplio que “{0}” lo que permite la asignación mediante “{0}” de valores con ámbitos de escape más estrechos que “{1}”. + Esta referencia asigna "{1}" a "{0}" pero "{1}" tiene un ámbito de escape de valor más amplio que "{0}" que permite la asignación a través de "{0}" de valores con ámbitos de escape más estrechos que "{1}". @@ -3863,7 +3988,7 @@ -lib:<file list> Especificar directorios adicionales en los que buscar referencias -errorreport:<string> Especificar cómo controlar los errores del compilador interno: - solicitar, enviar, poner en cola o ninguno. El valor predeterminado es + solicitar, enviar, poner en cola o ninguno. El valor predeterminado es queue. -appconfig:<file> Especificar un archivo de configuración de la aplicación que contiene la configuración de enlace del ensamblado @@ -5300,12 +5425,12 @@ Field '{0}' is never ref-assigned to, and will always have its default value (null reference) - Field '{0}' is never ref-assigned to, and will always have its default value (null reference) + El campo "{0}" nunca se asigna a una referencia y siempre tendrá su valor predeterminado (referencia nula) Field is never ref-assigned to, and will always have its default value (null reference) - Field is never ref-assigned to, and will always have its default value (null reference) + El campo nunca se asigna a una referencia y siempre tendrá su valor predeterminado (referencia nula) @@ -5379,12 +5504,12 @@ - Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or safely handling the case where 'field' is null in the 'get' accessor. El elemento {0} "{1}" que no acepta valores NULL debe contener un valor distinto de NULL al salir del constructor. Considere agregar el modificador "requerido", o declarar {0} como anulable, o agregar atributos "[campo: MaybeNull, AllowNull]". Similar diagnostic message as 'WRN_UninitializedNonNullableField' - Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. La propiedad no anulable debe contener un valor no nulo al salir del constructor. Considere agregar el modificador "requerido", o declarar la propiedad como anulable, o agregar atributos "[campo: MaybeNull, AllowNull]". @@ -5420,12 +5545,12 @@ UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. - UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute solo es válido en C# 11 o posterior o cuando el destino es net7.0 o posterior. UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. - UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute solo es válido en C# 11 o posterior o cuando el destino es net7.0 o posterior. @@ -6729,8 +6854,8 @@ - The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. - El modificador 'partial' solo puede aparecer inmediatamente antes de 'class', 'record', 'struct', 'interface' o un método o tipo de valor devuelto de propiedad. + The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. + El modificador 'partial' solo puede aparecer inmediatamente antes de 'class', 'record', 'struct', 'interface' o un método o tipo de valor devuelto de propiedad. @@ -8832,8 +8957,8 @@ Un bloque catch() después de un bloque catch (System.Exception e) puede abarcar - Cannot define a new extension method because the compiler required type '{0}' cannot be found. Are you missing a reference to System.Core.dll? - No se puede definir un nuevo método de extensión porque no se encontró el tipo '{0}' requerido por el compilador. ¿Falta alguna referencia a System.Core.dll? + Cannot define a new extension because the compiler required type '{0}' cannot be found. Are you missing a reference to System.Core.dll? + No se puede definir un nuevo método de extensión porque no se encontró el tipo '{0}' requerido por el compilador. ¿Falta alguna referencia a System.Core.dll? @@ -8927,8 +9052,8 @@ Un bloque catch() después de un bloque catch (System.Exception e) puede abarcar - Invalid token '{0}' in class, record, struct, or interface member declaration - El token "{0}" no es válido en una clase, un registro, una estructura o una declaración de miembro de interfaz + Invalid token '{0}' in a member declaration + El token "{0}" no es válido en una clase, un registro, una estructura o una declaración de miembro de interfaz @@ -10376,7 +10501,7 @@ Indique al compilador alguna forma de diferenciar los métodos. Por ejemplo, pue Cannot open '{0}' for writing -- {1} - No se puede abrir '{0}' para escribir: '{1}' + No se puede abrir "{0}" para escribir -- {1} @@ -12741,7 +12866,7 @@ Para eliminar la advertencia puede usar /reference (establezca la propiedad Embe Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string literals or try the EXPERIMENTAL feature flag 'experimental-data-section-string-literals'. - La longitud combinada de las cadenas de usuario que el programa utiliza supera el límite permitido. Intente disminuir el uso de literales de cadena. + La longitud combinada de las cadenas de usuario que el programa utiliza supera el límite permitido. Intente reducir el uso de literales de cadena o pruebe la marca de característica EXPERIMENTAL "experimental-data-section-string-literals". @@ -13036,7 +13161,7 @@ Para eliminar la advertencia puede usar /reference (establezca la propiedad Embe '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + "{0}" se incluye con fines de evaluación y está sujeto a cambios o a que se elimine en próximas actualizaciones. Suprima este diagnóstico para continuar. @@ -13091,7 +13216,7 @@ Para eliminar la advertencia puede usar /reference (establezca la propiedad Embe Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + No se puede leer la información de depuración del método "{0}" (token 0x{1:X8}) del ensamblado "{2}": {3} diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 3ff46d0e3d3df..a39f155a10429 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -222,6 +222,11 @@ Impossible d'utiliser une collection de type dynamique dans un foreach asynchrone + + Extensions must be declared in a top-level, non-generic, static class + Extensions must be declared in a top-level, non-generic, static class + + The type '{0}' may not be used for a field of a record. Le type '{0}' ne doit pas être utilisé pour un champ d'enregistrement. @@ -373,8 +378,8 @@ - Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specifc numeric type. - Nous n’avons pas pu utiliser une constante numérique ou un modèle relationnel sur '{0}', car il hérite ou étend 'INumberBase<T>'. Utilisez un modèle de type pour vous limiter à un type numérique spécifié. + Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specific numeric type. + Nous n’avons pas pu utiliser une constante numérique ou un modèle relationnel sur '{0}', car il hérite ou étend 'INumberBase<T>'. Utilisez un modèle de type pour vous limiter à un type numérique spécifié. @@ -542,6 +547,11 @@ Un constructeur de copie '{0}' doit être public ou protégé, car l'enregistrement n'est pas sealed. + + Cannot emit this string literal into the data section because it has XXHash128 collision with another string literal: {0} + Cannot emit this string literal into the data section because it has XXHash128 collision with another string literal: {0} + + The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'. Le nom '{0}' ne correspond pas au paramètre 'Deconstruct' correspondant '{1}'. @@ -639,7 +649,7 @@ Cannot emit update; {0} '{1}' is missing. - Cannot emit update; {0} '{1}' is missing. + Impossible d’émettre la mise à jour ; {0} '{1}' est manquant. @@ -717,6 +727,11 @@ Une arborescence de l’expression ne peut pas contenir une expression de collection. + + An expression tree may not contain an extension property access + An expression tree may not contain an extension property access + + An expression tree may not contain a from-end index ('^') expression. Une arborescence de l'expression ne peut pas contenir d'expression d'index partant de la fin ('^'). @@ -762,6 +777,26 @@ Une arborescence de l'expression ne peut pas contenir d'expression with. + + Extension declarations can include only methods or properties + Extension declarations can include only methods or properties + + + + Extension declarations may not have a name. + Extension declarations may not have a name. + + + + The receiver parameter of an extension cannot have a default value + The receiver parameter of an extension cannot have a default value + + + + '{0}' does not contain a definition for '{1}' and no accessible extension member '{1}' for receiver of type '{0}' could be found (are you missing a using directive or an assembly reference?) + '{0}' does not contain a definition for '{1}' and no accessible extension member '{1}' for receiver of type '{0}' could be found (are you missing a using directive or an assembly reference?) + + '{0}': extern event cannot have initializer '{0}' : un événement extern ne peut pas avoir d'initialiseur @@ -1247,6 +1282,11 @@ L’argument diagnosticId de l’attribut « Experimental » doit être un identificateur valide + + Cannot use extension parameter '{0}' in this context. + Cannot use extension parameter '{0}' in this context. + + '{0}' is not a valid function pointer return type modifier. Valid modifiers are 'ref' and 'ref readonly'. '{0}' n'est pas un modificateur de type de retour de pointeur de fonction valide. Les modificateurs valides sont 'ref' et 'ref readonly'. @@ -1339,7 +1379,7 @@ Element type of an iterator may not be a ref struct or a type parameter allowing ref structs - Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + Le type d’élément d’un itérateur ne peut pas être un struct ref ou un paramètre de type autorisant les structs ref @@ -1387,6 +1427,16 @@ Les modèles de liste ne peuvent pas être utilisés pour une valeur de type '{0}'. Aucune propriété 'Longueur' ou 'Compte' appropriée n’a été trouvée. + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + + No overload for '{0}' matches function pointer '{1}' Aucune surcharge pour '{0}' ne correspond au pointeur de fonction '{1}' @@ -1687,6 +1737,16 @@ Le paramètre params doit avoir un type de collection valide + + '{0}': only the implementing declaration of a partial constructor can have an initializer + '{0}': only the implementing declaration of a partial constructor can have an initializer + + + + '{0}': partial event cannot have initializer + '{0}': partial event cannot have initializer + + Both partial member declarations must have identical accessibility modifiers. Les deux déclarations de membres partiels doivent avoir des modificateurs d'accessibilité identiques. @@ -1697,11 +1757,31 @@ Un membre partiel ne peut pas avoir le modificateur « abstract » + + Partial member '{0}' may not have multiple defining declarations. + Partial member '{0}' may not have multiple defining declarations. + + + + Partial member '{0}' may not have multiple implementing declarations. + Partial member '{0}' may not have multiple implementing declarations. + + Both partial member declarations, '{0}' and '{1}', must use the same tuple element names. Les deux déclarations de membres partiels, « {0} » et « {1} », doivent utiliser les mêmes noms d'éléments tuple. + + Partial member '{0}' must have a definition part. + Partial member '{0}' must have a definition part. + + + + Partial member '{0}' must have an implementation part. + Partial member '{0}' must have an implementation part. + + A partial member must be declared within a partial type Un membre partiel doit être déclaré dans un type partiel @@ -1727,6 +1807,11 @@ Les déclarations de membres partiels doivent avoir des valeurs de retour ref correspondantes. + + Both partial member declarations must have the same type. + Both partial member declarations must have the same type. + + Both partial member declarations must be unsafe or neither may be unsafe Les deux déclarations partielles de membres doivent être peu sûres ou aucune ne peut l'être. @@ -1797,11 +1882,6 @@ Les deux déclarations de propriété partielle doivent être obligatoires ou aucune ne peut être requise - - Both partial property declarations must have the same type. - Les deux déclarations de propriété partielle doivent avoir le même type. - - Property accessor '{0}' does not implement any accessor declared on the definition part L’accesseur de propriété « {0} » n’implémente aucun accesseur déclaré sur la partie définition @@ -1862,6 +1942,16 @@ '{0}' : 'readonly' peut uniquement être utilisé sur des accesseurs si la propriété ou l'indexeur a un accesseur get et un accesseur set + + An extension container can have only one receiver parameter + An extension container can have only one receiver parameter + + + + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + + The primary constructor conflicts with the synthesized copy constructor. Le constructeur principal est en conflit avec le constructeur de copie synthétisée. @@ -1884,7 +1974,7 @@ Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escape scopes than '{1}'. - Cette référence ne peut affecter '{1}' à '{0}', car '{1}' a une étendue d’échappement de valeur plus large que '{0}' permettant l’affectation via '{0}' de valeurs avec des étendues d’échappement plus restreintes que '{1}'. + Nous ne pouvons pas effectuer l’affectation de référence de « {1} » vers « {0} », car « {1} » a une étendue d’échappement de valeur plus large que « {0} » permettant l’affectation via « {0} » des valeurs avec des étendues d’échappement plus restreintes que « {1} ». @@ -2019,7 +2109,7 @@ The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. - The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + Le type 'Microsoft.CodeAnalysis.EmbeddedAttribute' doit être non générique, interne, sealed, non statique, avoir un constructeur sans paramètre, hériter de System.Attribute et être appliqué à n’importe quel type. @@ -2272,6 +2362,16 @@ Le type '{0}' doit être public pour être utilisé comme convention d'appel. + + Type parameter '{0}' has the same name as an extension parameter + Type parameter '{0}' has the same name as an extension parameter + + + + Type parameter '{0}' has the same name as an extension container type parameter + Type parameter '{0}' has the same name as an extension container type parameter + + Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. La propriété implémentée automatiquement '{0}' doit être entièrement affectée avant que le contrôle soit retourné à l’appelant. Envisagez de mettre à jour la version de langue «{1}» pour définir automatiquement la propriété par défaut. @@ -2282,6 +2382,11 @@ Le champ '{0}' doit être entièrement attribué avant que le contrôle soit retourné à l’appelant. Envisagez de mettre à jour la version de langue «{1}» pour définir automatiquement le champ par défaut. + + The extended type '{0}' must reference all the type parameters declared by the extension, but type parameter '{1}' is not referenced. + The extended type '{0}' must reference all the type parameters declared by the extension, but type parameter '{1}' is not referenced. + + Unexpected parameter list. Liste de paramètres inattendue. @@ -2372,6 +2477,16 @@ Impossible d’utiliser l’objet 'this' avant l’affectation de tous ses champs. Envisagez de mettre à jour vers la version de langage '{0}' pour définir automatiquement les champs non attribués par défaut. + + 'value': an automatically-generated parameter name conflicts with an extension parameter name + 'value': an automatically-generated parameter name conflicts with an extension parameter name + + + + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + + In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. @@ -2442,6 +2557,11 @@ modèles de propriétés étendues + + extensions + extensions + + field keyword mot-clé du champ @@ -2459,7 +2579,7 @@ first-class Span types - first-class Span types + types Span de première classe @@ -2539,7 +2659,7 @@ overload resolution priority - overload resolution priority + priorité de résolution de surcharge @@ -2552,6 +2672,11 @@ collections de params + + partial events and constructors + partial events and constructors + + positional fields in records champs positionnels dans les enregistrements @@ -2624,7 +2749,7 @@ unbound generic types in nameof operator - unbound generic types in nameof operator + types génériques indépendants dans l’opérateur nameof @@ -2714,12 +2839,12 @@ The '{0}' accessor of property '{1}' should use 'field' because the other accessor is using it. - The '{0}' accessor of property '{1}' should use 'field' because the other accessor is using it. + L’accesseur '{0}' de la propriété '{1}' doit utiliser 'field', car l’autre accesseur l’utilise. Property accessor should use 'field' because the other accessor is using it. - Property accessor should use 'field' because the other accessor is using it. + L’accesseur de propriété doit utiliser 'field', car l’autre accesseur l’utilise. @@ -2743,13 +2868,13 @@ - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - L'assembly d'analyseur '{0}' fait référence à la version '{1}' du compilateur, qui est plus récente que la version en cours d'exécution '{2}'. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + L'assembly d'analyseur '{0}' fait référence à la version '{1}' du compilateur, qui est plus récente que la version en cours d'exécution '{2}'. - The analyzer assembly references a newer version of the compiler than the currently running version. - L'assembly de l'analyseur fait référence à une version plus récente du compilateur que la version en cours d'exécution. + Analyzer assembly cannot be used because it references a newer version of the compiler than the currently running version. + L'assembly de l'analyseur fait référence à une version plus récente du compilateur que la version en cours d'exécution. @@ -2994,12 +3119,12 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + « {0} » est utilisé à des fins d’évaluation uniquement et est susceptible d’être modifié ou supprimé dans les futures mises à jour : « {1} ». Supprimez ce diagnostic pour continuer. Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + Le type est utilisé à des fins d’évaluation uniquement et est susceptible d’être modifié ou supprimé dans les futures mises à jour. Supprimez ce diagnostic pour continuer. @@ -3074,12 +3199,12 @@ 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) - 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' n’est pas pris en charge. Déplacez plutôt vers la génération basée sur InterceptableLocation de ces attributs. (https://github.com/dotnet/roslyn/issues/72133) 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) - 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' n’est pas pris en charge. Déplacez plutôt vers la génération basée sur InterceptableLocation de ces attributs. (https://github.com/dotnet/roslyn/issues/72133) @@ -3212,14 +3337,14 @@ Le paramètre a un modificateur de paramètres dans l’expression lambda mais pas dans le type délégué cible. - - Partial property declarations '{0}' and '{1}' have signature differences. - Les déclarations de propriétés partielles « {0} » et « {1} » ont des différences de signature. + + Partial member declarations '{0}' and '{1}' have signature differences. + Partial member declarations '{0}' and '{1}' have signature differences. - - Partial property declarations have signature differences. - Les déclarations de propriétés partielles présentent des différences de signature. + + Partial member declarations have signature differences. + Partial member declarations have signature differences. @@ -3289,7 +3414,7 @@ This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escape scopes than '{1}'. - Cette référence affecte '{1}' à '{0}', mais '{1}' a une étendue d’échappement de valeur plus large que '{0}' permettant l’affectation via '{0}' de valeurs avec des étendues d’échappement plus restreintes que '{1}'. + Cette opération effectue une affectation de référence de « {1} » vers « {0} », mais « {1} » a une étendue d’échappement de valeur plus large que « {0} » permettant l’affectation via « {0} » des valeurs avec des étendues d’échappement plus restreintes que « {1} ». @@ -5300,12 +5425,12 @@ Field '{0}' is never ref-assigned to, and will always have its default value (null reference) - Field '{0}' is never ref-assigned to, and will always have its default value (null reference) + Une référence n’est jamais affectée au champ « {0} » et aura toujours sa valeur par défaut (référence nulle) Field is never ref-assigned to, and will always have its default value (null reference) - Field is never ref-assigned to, and will always have its default value (null reference) + Une référence n’est jamais affectée au champ et aura toujours sa valeur par défaut (référence nulle) @@ -5379,12 +5504,12 @@ - Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or safely handling the case where 'field' is null in the 'get' accessor. Non nullable {0} « {1} » doit contenir une valeur non nulle lors de la sortie du constructeur. Pensez à ajouter le modificateur « obligatoire », ou à déclarer {0} comme nullable, ou à ajouter les attributs « [field : MaybeNull, AllowNull] ». Similar diagnostic message as 'WRN_UninitializedNonNullableField' - Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. Une propriété non nullable doit contenir une valeur non nulle lors de la sortie du constructeur. Pensez à ajouter le modificateur « obligatoire », ou à déclarer la propriété comme nullable, ou à ajouter les attributs « [field : MaybeNull, AllowNull] ». @@ -5420,12 +5545,12 @@ UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. - UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute n’est valide qu’en C# 11 ou version ultérieure, ou quand net7.0 ou version ultérieure est ciblé. UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. - UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute n’est valide qu’en C# 11 ou version ultérieure, ou quand net7.0 ou version ultérieure est ciblé. @@ -6729,8 +6854,8 @@ - The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. - Le modificateur 'partial' peut apparaître uniquement juste avant 'class', 'record', 'struct', 'interface' ou un type de retour de méthode ou de propriété. + The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. + Le modificateur 'partial' peut apparaître uniquement juste avant 'class', 'record', 'struct', 'interface' ou un type de retour de méthode ou de propriété. @@ -8832,8 +8957,8 @@ Un bloc catch() après un bloc catch (System.Exception e) peut intercepter des e - Cannot define a new extension method because the compiler required type '{0}' cannot be found. Are you missing a reference to System.Core.dll? - Impossible de définir une nouvelle méthode d'extension, car le type requis par le compilateur '{0}' est introuvable. Vous manque-t-il une référence à System.Core.dll ? + Cannot define a new extension because the compiler required type '{0}' cannot be found. Are you missing a reference to System.Core.dll? + Impossible de définir une nouvelle méthode d'extension, car le type requis par le compilateur '{0}' est introuvable. Vous manque-t-il une référence à System.Core.dll ? @@ -8927,8 +9052,8 @@ Un bloc catch() après un bloc catch (System.Exception e) peut intercepter des e - Invalid token '{0}' in class, record, struct, or interface member declaration - Jeton '{0}' non valide dans la déclaration de membre de classe, d'enregistrement, de struct ou d'interface + Invalid token '{0}' in a member declaration + Jeton '{0}' non valide dans la déclaration de membre de classe, d'enregistrement, de struct ou d'interface @@ -10376,7 +10501,7 @@ Permettez au compilateur de différencier les méthodes. Par exemple, vous pouve Cannot open '{0}' for writing -- {1} - Impossible d'ouvrir '{0}' en écriture -- '{1}' + Nous ne pouvons pas ouvrir « {0} » en écriture -- {1} @@ -12741,7 +12866,7 @@ Pour supprimer l'avertissement, vous pouvez utiliser la commande /reference (dé Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string literals or try the EXPERIMENTAL feature flag 'experimental-data-section-string-literals'. - La longueur combinée des chaînes utilisateur que le programme utilise dépasse la limite autorisée. Essayez de réduire le nombre de littéraux de chaîne. + La longueur combinée des chaînes utilisateur utilisées par le programme dépasse la limite autorisée. Essayez de réduire l’utilisation des chaînes de caractères ou essayez l’option EXPÉRIMENTALE « experimental-data-section-string-literals ». @@ -13036,7 +13161,7 @@ Pour supprimer l'avertissement, vous pouvez utiliser la commande /reference (dé '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + « {0} » est utilisé à des fins d’évaluation uniquement et est susceptible d’être modifié ou supprimé dans les futures mises à jour. Supprimez ce diagnostic pour continuer. @@ -13091,7 +13216,7 @@ Pour supprimer l'avertissement, vous pouvez utiliser la commande /reference (dé Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Nous ne pouvons pas lire les informations de débogage de la méthode « {0} » (jeton 0x{1:X8}) dans l’assembly « {2} » : {3} diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 16a6be7c5e946..d0c204cccc80f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -222,6 +222,11 @@ Non è possibile usare una raccolta di tipo dinamico in un'istruzione foreach asincrona + + Extensions must be declared in a top-level, non-generic, static class + Extensions must be declared in a top-level, non-generic, static class + + The type '{0}' may not be used for a field of a record. Il tipo '{0}' non può essere usato per un campo di un record. @@ -373,8 +378,8 @@ - Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specifc numeric type. - Non è possibile usare una costante numerica o un modello relazionale su '{0}' perché eredita da o estende 'INumberBase<T>'. Provare a usare un modello di tipo per limitare a un tipo numerico specifico. + Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specific numeric type. + Non è possibile usare una costante numerica o un modello relazionale su '{0}' perché eredita da o estende 'INumberBase<T>'. Provare a usare un modello di tipo per limitare a un tipo numerico specifico. @@ -542,6 +547,11 @@ Un costruttore di copia '{0}' deve essere pubblico o protetto perché il record non è sealed. + + Cannot emit this string literal into the data section because it has XXHash128 collision with another string literal: {0} + Cannot emit this string literal into the data section because it has XXHash128 collision with another string literal: {0} + + The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'. Il nome '{0}' non corrisponde al parametro '{1}' di 'Deconstruct' corrispondente. @@ -639,7 +649,7 @@ Cannot emit update; {0} '{1}' is missing. - Cannot emit update; {0} '{1}' is missing. + Non è possibile creare l'aggiornamento. {0} '{1}' mancante. @@ -717,6 +727,11 @@ Un albero delle espressioni non può contenere un'espressione di raccolta. + + An expression tree may not contain an extension property access + An expression tree may not contain an extension property access + + An expression tree may not contain a from-end index ('^') expression. Un albero delle espressioni non può contenere un'espressione di indice from end ('^'). @@ -762,6 +777,26 @@ Un albero delle espressioni non può contenere un'espressione with. + + Extension declarations can include only methods or properties + Extension declarations can include only methods or properties + + + + Extension declarations may not have a name. + Extension declarations may not have a name. + + + + The receiver parameter of an extension cannot have a default value + The receiver parameter of an extension cannot have a default value + + + + '{0}' does not contain a definition for '{1}' and no accessible extension member '{1}' for receiver of type '{0}' could be found (are you missing a using directive or an assembly reference?) + '{0}' does not contain a definition for '{1}' and no accessible extension member '{1}' for receiver of type '{0}' could be found (are you missing a using directive or an assembly reference?) + + '{0}': extern event cannot have initializer '{0}': l'evento extern non può avere inizializzatori @@ -1247,6 +1282,11 @@ L'argomento diagnosticId dell'attributo 'Experimental' deve essere un identificatore valido + + Cannot use extension parameter '{0}' in this context. + Cannot use extension parameter '{0}' in this context. + + '{0}' is not a valid function pointer return type modifier. Valid modifiers are 'ref' and 'ref readonly'. '{0}' non è un modificatore di tipo restituito di puntatore a funzione valido. I modificatori validi sono 'ref' e 'ref readonly'. @@ -1339,7 +1379,7 @@ Element type of an iterator may not be a ref struct or a type parameter allowing ref structs - Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + Il tipo di elemento di un iteratore non può essere uno struct di riferimento o un parametro di tipo che consente struct di riferimento @@ -1387,6 +1427,16 @@ I criteri di elenco non possono essere utilizzati per un valore di tipo '{0}'. Non è stata trovata alcuna proprietà 'Length' o 'Count' appropriata. + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + + No overload for '{0}' matches function pointer '{1}' Nessun overload per '{0}' corrisponde al puntatore a funzione '{1}' @@ -1687,6 +1737,16 @@ Il parametro params deve avere un tipo di raccolta valido + + '{0}': only the implementing declaration of a partial constructor can have an initializer + '{0}': only the implementing declaration of a partial constructor can have an initializer + + + + '{0}': partial event cannot have initializer + '{0}': partial event cannot have initializer + + Both partial member declarations must have identical accessibility modifiers. I modificatori di accessibilità devono essere identici in entrambe le dichiarazioni di membro parziale. @@ -1697,11 +1757,31 @@ Un membro parziale non può contenere il modificatore 'abstract' + + Partial member '{0}' may not have multiple defining declarations. + Partial member '{0}' may not have multiple defining declarations. + + + + Partial member '{0}' may not have multiple implementing declarations. + Partial member '{0}' may not have multiple implementing declarations. + + Both partial member declarations, '{0}' and '{1}', must use the same tuple element names. Entrambe le dichiarazioni di membro parziale '{0}' e '{1}' devono usare gli stessi nomi di elementi di tupla. + + Partial member '{0}' must have a definition part. + Partial member '{0}' must have a definition part. + + + + Partial member '{0}' must have an implementation part. + Partial member '{0}' must have an implementation part. + + A partial member must be declared within a partial type Un membro parziale deve essere dichiarato in un tipo parziale @@ -1727,6 +1807,11 @@ Le dichiarazioni di membro parziale devono contenere valori restituiti di riferimento corrispondenti. + + Both partial member declarations must have the same type. + Both partial member declarations must have the same type. + + Both partial member declarations must be unsafe or neither may be unsafe Entrambe le dichiarazioni di membro parziale devono essere di tipo unsafe, altrimenti nessuna delle due potrà esserlo @@ -1797,11 +1882,6 @@ Entrambe le dichiarazioni di proprietà parziale devono essere richieste, altrimenti nessuna delle due potrà esserlo - - Both partial property declarations must have the same type. - Il tipo deve essere identico in entrambe le dichiarazioni di proprietà parziale. - - Property accessor '{0}' does not implement any accessor declared on the definition part La funzione di accesso alle proprietà '{0}' non implementa alcuna funzione di accesso dichiarata nella parte della definizione @@ -1862,6 +1942,16 @@ '{0}': 'readonly' può essere usato su funzioni di accesso solo se la proprietà o l'indicizzatore include entrambi le funzioni di accesso get e set + + An extension container can have only one receiver parameter + An extension container can have only one receiver parameter + + + + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + + The primary constructor conflicts with the synthesized copy constructor. Il costruttore primario è in conflitto con il costruttore di copia sintetizzato. @@ -2019,7 +2109,7 @@ The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. - The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + Il tipo 'Microsoft.CodeAnalysis.EmbeddedAttribute' deve essere non generico, interno, sealed, non statico, avere un costruttore senza parametri, ereditare da System.Attribute e poter essere applicato a qualsiasi tipo. @@ -2272,6 +2362,16 @@ Il tipo '{0}' deve essere pubblico per poterlo usare come convenzione di chiamata. + + Type parameter '{0}' has the same name as an extension parameter + Type parameter '{0}' has the same name as an extension parameter + + + + Type parameter '{0}' has the same name as an extension container type parameter + Type parameter '{0}' has the same name as an extension container type parameter + + Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. La proprietà implementata automaticamente '{0}' deve essere assegnata completamente prima che il controllo sia restituito al chiamante. Provare a eseguire l'aggiornamento alla versione del linguaggio '{1}' per impostare automaticamente la proprietà come predefinita. @@ -2282,6 +2382,11 @@ Il campo '{0}' deve essere assegnato completamente prima che il controllo sia restituito al chiamante. Provare a eseguire l'aggiornamento alla versione del linguaggio '{1}' per impostare automaticamente il campo come predefinito. + + The extended type '{0}' must reference all the type parameters declared by the extension, but type parameter '{1}' is not referenced. + The extended type '{0}' must reference all the type parameters declared by the extension, but type parameter '{1}' is not referenced. + + Unexpected parameter list. Elenco parametri imprevisto. @@ -2372,6 +2477,16 @@ Impossibile utilizzare l'oggetto 'this' prima dell'assegnazione di tutti i relativi campi. Provare a eseguire l'aggiornamento alla versione del linguaggio '{0}' per impostare come predefiniti automaticamente i campi non assegnati. + + 'value': an automatically-generated parameter name conflicts with an extension parameter name + 'value': an automatically-generated parameter name conflicts with an extension parameter name + + + + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + + In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. @@ -2442,6 +2557,11 @@ criteri di proprietà estesa + + extensions + extensions + + field keyword parola chiave campo @@ -2459,7 +2579,7 @@ first-class Span types - first-class Span types + tipi Span di prima classe @@ -2539,7 +2659,7 @@ overload resolution priority - overload resolution priority + priorità di risoluzione dell'overload @@ -2552,6 +2672,11 @@ raccolte parametri + + partial events and constructors + partial events and constructors + + positional fields in records campi posizionali nei record @@ -2624,7 +2749,7 @@ unbound generic types in nameof operator - unbound generic types in nameof operator + tipi generici non collegati nell'operatore nameof @@ -2714,12 +2839,12 @@ The '{0}' accessor of property '{1}' should use 'field' because the other accessor is using it. - The '{0}' accessor of property '{1}' should use 'field' because the other accessor is using it. + La funzione di accesso '{0}' della proprietà '{1}' deve usare 'field' perché è utilizzata dall'altra funzione di accesso. Property accessor should use 'field' because the other accessor is using it. - Property accessor should use 'field' because the other accessor is using it. + La funzione di accesso delle proprietà deve usare 'field' perché è in uso dall'altra funzione di accesso. @@ -2743,13 +2868,13 @@ - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - L'assembly dell'analizzatore '{0}' fa riferimento alla versione '{1}' del compilatore, che è più recente della versione attualmente in esecuzione '{2}'. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + L'assembly dell'analizzatore '{0}' fa riferimento alla versione '{1}' del compilatore, che è più recente della versione attualmente in esecuzione '{2}'. - The analyzer assembly references a newer version of the compiler than the currently running version. - L'assembly dell'analizzatore fa riferimento alla versione del compilatore, che è più recente della versione attualmente in esecuzione. + Analyzer assembly cannot be used because it references a newer version of the compiler than the currently running version. + L'assembly dell'analizzatore fa riferimento alla versione del compilatore, che è più recente della versione attualmente in esecuzione. @@ -2994,12 +3119,12 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + "{0}" viene usato solo a scopo di valutazione e potrebbe essere modificato o rimosso in aggiornamenti futuri: "{1}". Eliminare questa diagnostica per continuare. Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + Type viene usato solo a scopo di valutazione e potrebbe essere modificato o rimosso in aggiornamenti futuri. Elimina questa diagnostica per continuare. @@ -3074,12 +3199,12 @@ 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) - 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' non è supportato. Passare alla generazione di questi attributi basata su 'InterceptableLocation'. (https://github.com/dotnet/roslyn/issues/72133) 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) - 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' non è supportato. Passare alla generazione di questi attributi basata su 'InterceptableLocation'. (https://github.com/dotnet/roslyn/issues/72133) @@ -3212,14 +3337,14 @@ Il parametro contiene un modificatore di parametri in lambda ma non nel tipo delegato di destinazione. - - Partial property declarations '{0}' and '{1}' have signature differences. - Le dichiarazioni di proprietà parziale '{0}' e '{1}' presentano differenze di firma. + + Partial member declarations '{0}' and '{1}' have signature differences. + Partial member declarations '{0}' and '{1}' have signature differences. - - Partial property declarations have signature differences. - Le dichiarazioni di proprietà parziale presentano differenze di firma. + + Partial member declarations have signature differences. + Partial member declarations have signature differences. @@ -3734,7 +3859,7 @@ target:module Compila un modulo che può essere aggiunto ad altro -t:appcontainerexe) -target:winmdobj Consente di compilare un file intermedio Windows Runtime che viene utilizzato da WinMDExp (forma breve: -t:winmdobj) --doc:<file> Genera un file di documentazione XML per generare +-doc:<file> Genera un file di documentazione XML per generare -refout:<file> Output dell'assembly di riferimento da generare -platform:<string> Limita le piattaforme in cui è possibile eseguire questo codice su x86, Itanium, x64, arm, arm64, anycpu32bitpreferred o @@ -5300,12 +5425,12 @@ target:module Compila un modulo che può essere aggiunto ad altro Field '{0}' is never ref-assigned to, and will always have its default value (null reference) - Field '{0}' is never ref-assigned to, and will always have its default value (null reference) + Il campo '{0}' non è mai assegnato come riferimento e avrà sempre il valore predefinito (riferimento Null) Field is never ref-assigned to, and will always have its default value (null reference) - Field is never ref-assigned to, and will always have its default value (null reference) + Il campo non è mai assegnato come riferimento e avrà sempre il valore predefinito (riferimento Null) @@ -5379,12 +5504,12 @@ target:module Compila un modulo che può essere aggiunto ad altro - Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or safely handling the case where 'field' is null in the 'get' accessor. L'elemento {0} '{1}' che non ammette i valori Null deve contenere un valore non Null all'uscita dal costruttore. Prendere in considerazione l'aggiunta del modificatore 'required' o la dichiarazione come {0} che ammette i valori Null, oppure l'aggiunta di attributi '[field: MaybeNull, AllowNull]'. Similar diagnostic message as 'WRN_UninitializedNonNullableField' - Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. La proprietà che non ammette i valori Null deve contenere un valore non Null all'uscita dal costruttore. Provare ad aggiungere il modificatore 'required', a dichiarare la proprietà come che ammette i valori Null, oppure ad aggiungere gli attributi '[field: MaybeNull, AllowNull]'. @@ -5420,12 +5545,12 @@ target:module Compila un modulo che può essere aggiunto ad altro UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. - UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute è valido solo in C# 11 o versioni successive o se destinato a net7.0 o versione successiva. UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. - UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute è valido solo in C# 11 o versioni successive o se destinato a net7.0 o versione successiva. @@ -6729,8 +6854,8 @@ target:module Compila un modulo che può essere aggiunto ad altro - The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. - Il modificatore 'partial' può trovarsi solo immediatamente prima di 'class', 'record', 'struct', 'interface' o del tipo restituito di un metodo o di una proprietà. + The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. + Il modificatore 'partial' può trovarsi solo immediatamente prima di 'class', 'record', 'struct', 'interface' o del tipo restituito di un metodo o di una proprietà. @@ -8832,8 +8957,8 @@ Un blocco catch() dopo un blocco catch (System.Exception e) può rilevare eccezi - Cannot define a new extension method because the compiler required type '{0}' cannot be found. Are you missing a reference to System.Core.dll? - Non è possibile definire un nuovo metodo di estensione perché non è stato trovato il tipo '{0}' richiesto dal compilatore. Probabilmente manca un riferimento. + Cannot define a new extension because the compiler required type '{0}' cannot be found. Are you missing a reference to System.Core.dll? + Non è possibile definire un nuovo metodo di estensione perché non è stato trovato il tipo '{0}' richiesto dal compilatore. Probabilmente manca un riferimento. @@ -8927,8 +9052,8 @@ Un blocco catch() dopo un blocco catch (System.Exception e) può rilevare eccezi - Invalid token '{0}' in class, record, struct, or interface member declaration - Il token '{0}' nella dichiarazione del membro di classe, record, struct o interfaccia non è valido + Invalid token '{0}' in a member declaration + Il token '{0}' nella dichiarazione del membro di classe, record, struct o interfaccia non è valido @@ -10376,7 +10501,7 @@ Impostare il compilatore in modo tale da distinguere i metodi, ad esempio assegn Cannot open '{0}' for writing -- {1} - Non è possibile aprire '{0}' per la scrittura - '{1}' + Non è possibile aprire '{0}' per la scrittura -- {1} @@ -12741,7 +12866,7 @@ Per rimuovere l'avviso, è invece possibile usare /reference (impostare la propr Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string literals or try the EXPERIMENTAL feature flag 'experimental-data-section-string-literals'. - La lunghezza combinata delle stringhe utente usate dal programma supera il limite consentito. Provare a ridurre l'uso di valori letterali stringa. + La lunghezza combinata delle stringhe utente usate dal programma supera il limite consentito. Provare a ridurre l'uso dei valori letterali stringa o provare il flag di funzionalità SPERIMENTALE "experimental-data-section-string-literals". @@ -13036,7 +13161,7 @@ Per rimuovere l'avviso, è invece possibile usare /reference (impostare la propr '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + '{0}' viene usato solo a scopo di valutazione e potrebbe essere modificato o rimosso in aggiornamenti futuri. Elimina questa diagnostica per continuare. @@ -13091,7 +13216,7 @@ Per rimuovere l'avviso, è invece possibile usare /reference (impostare la propr Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Non è possibile leggere le informazione di debug del metodo '{0}' (token 0x{1:X8}) dall'assembly '{2}': {3} diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 23518ced373c4..98ee0d333d403 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -222,6 +222,11 @@ 非同期 foreach では動的な型のコレクションを使用できません + + Extensions must be declared in a top-level, non-generic, static class + Extensions must be declared in a top-level, non-generic, static class + + The type '{0}' may not be used for a field of a record. レコードのフィールドに対して型 '{0}' を使用することはできません。 @@ -373,8 +378,8 @@ - Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specifc numeric type. - 'INumberBase<T>' を継承または拡張しているため、'{0}' で数値定数またはリレーショナル パターンを使用することはできません。指定された数値型に絞り込むために、型パターンを使用することを検討してください。 + Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specific numeric type. + 'INumberBase<T>' を継承または拡張しているため、'{0}' で数値定数またはリレーショナル パターンを使用することはできません。指定された数値型に絞り込むために、型パターンを使用することを検討してください。 @@ -542,6 +547,11 @@ コピー コンストラクター '{0}' は、レコードが sealed ではないため、public または protected にする必要があります。 + + Cannot emit this string literal into the data section because it has XXHash128 collision with another string literal: {0} + Cannot emit this string literal into the data section because it has XXHash128 collision with another string literal: {0} + + The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'. 名前 '{0}' は対応する 'Deconstruct' パラメーター '{1}' と一致しません。 @@ -639,7 +649,7 @@ Cannot emit update; {0} '{1}' is missing. - Cannot emit update; {0} '{1}' is missing. + 更新プログラムを生成できません。 {0} '{1}' がありません。 @@ -717,6 +727,11 @@ 式ツリーにコレクション式を含めることはできません。 + + An expression tree may not contain an extension property access + An expression tree may not contain an extension property access + + An expression tree may not contain a from-end index ('^') expression. 式ツリーに、from-end インデックス ('^') 式を含めることはできません。 @@ -762,6 +777,26 @@ 式ツリーは、with 式を含むことはできません + + Extension declarations can include only methods or properties + Extension declarations can include only methods or properties + + + + Extension declarations may not have a name. + Extension declarations may not have a name. + + + + The receiver parameter of an extension cannot have a default value + The receiver parameter of an extension cannot have a default value + + + + '{0}' does not contain a definition for '{1}' and no accessible extension member '{1}' for receiver of type '{0}' could be found (are you missing a using directive or an assembly reference?) + '{0}' does not contain a definition for '{1}' and no accessible extension member '{1}' for receiver of type '{0}' could be found (are you missing a using directive or an assembly reference?) + + '{0}': extern event cannot have initializer '{0}': extern イベントは初期化子を持つことができません @@ -1247,6 +1282,11 @@ 'Experimental' 属性への diagnosticId 引数は有効な識別子である必要があります + + Cannot use extension parameter '{0}' in this context. + Cannot use extension parameter '{0}' in this context. + + '{0}' is not a valid function pointer return type modifier. Valid modifiers are 'ref' and 'ref readonly'. '{0}' は有効な関数ポインターの戻り値の型修飾子ではありません。有効な修飾子は 'ref ' および 'ref readonly' です。 @@ -1339,7 +1379,7 @@ Element type of an iterator may not be a ref struct or a type parameter allowing ref structs - Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + 反復子の要素型を ref 構造体または ref 構造体を許可する型パラメーターにすることはできません @@ -1387,6 +1427,16 @@ リスト パターンは、型 '{0}' の値には使用できません。適切な 'Length' または 'Count' プロパティが見つかりませんでした。 + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + + No overload for '{0}' matches function pointer '{1}' 関数ポインター '{1}' に一致する '{0}' のオーバーロードはありません @@ -1687,6 +1737,16 @@ params パラメーターには有効なコレクションの種類が必要です + + '{0}': only the implementing declaration of a partial constructor can have an initializer + '{0}': only the implementing declaration of a partial constructor can have an initializer + + + + '{0}': partial event cannot have initializer + '{0}': partial event cannot have initializer + + Both partial member declarations must have identical accessibility modifiers. 両方の部分メンバー宣言には、同じアクセシビリティ修飾子を指定する必要があります。 @@ -1697,11 +1757,31 @@ 部分メンバーに 'abstract' 修飾子を指定することはできません + + Partial member '{0}' may not have multiple defining declarations. + Partial member '{0}' may not have multiple defining declarations. + + + + Partial member '{0}' may not have multiple implementing declarations. + Partial member '{0}' may not have multiple implementing declarations. + + Both partial member declarations, '{0}' and '{1}', must use the same tuple element names. 部分メンバー宣言 '{0}' および '{1}' は、どちらも同じタプル要素名を使用する必要があります。 + + Partial member '{0}' must have a definition part. + Partial member '{0}' must have a definition part. + + + + Partial member '{0}' must have an implementation part. + Partial member '{0}' must have an implementation part. + + A partial member must be declared within a partial type 部分メンバーは、部分型内で宣言される必要があります @@ -1727,6 +1807,11 @@ 部分メンバーの宣言には、一致する ref 戻り値が必要です。 + + Both partial member declarations must have the same type. + Both partial member declarations must have the same type. + + Both partial member declarations must be unsafe or neither may be unsafe 部分メンバー宣言は、両方とも unsafe であるか、両方とも unsafe でないかのいずれかである必要があります @@ -1797,11 +1882,6 @@ 両方の部分プロパティ宣言を必須にするか、どちらも必須にしないようにする必要があります - - Both partial property declarations must have the same type. - 両方の部分プロパティ宣言の型が同じである必要があります。 - - Property accessor '{0}' does not implement any accessor declared on the definition part プロパティ アクセサー '{0}' は、定義パーツで宣言されたアクセサーを実装しません @@ -1862,6 +1942,16 @@ '{0}': 'readonly' は、プロパティまたはインデクサーが get および set の両方のアクセサーを含む場合にのみ、アクセサーで使用できます + + An extension container can have only one receiver parameter + An extension container can have only one receiver parameter + + + + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + + The primary constructor conflicts with the synthesized copy constructor. プライマリ コンストラクターが、合成されたコピー コンストラクターと競合しています。 @@ -1884,7 +1974,7 @@ Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escape scopes than '{1}'. - '{1}' を '{0}' に参照割り当てできません。'{1}' には '{0}' よりも広い値エスケープ スコープがあり、'{0}' を使用して '{1}' より狭いエスケープ スコープを持つ値の割り当てが許可されています。 + '{1}' を '{0}' に参照割り当てできません。これは、'{1} の値エスケープ スコープが '{0} よりも広く、'{1}' よりも狭いエスケープ スコープを持つ値の '{0} による割り当てが許可されているためです。 @@ -2019,7 +2109,7 @@ The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. - The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + 型 'Microsoft.CodeAnalysis.EmbeddedAttribute' は、非ジェネリック、内部、シールド、非静的、パラメーターなしのコンストラクターを持ち、System.Attribute から継承し、任意の型に適用できる必要があります。 @@ -2272,6 +2362,16 @@ 呼び出し規則として使用する型 '{0}' はパブリックでなければなりません。 + + Type parameter '{0}' has the same name as an extension parameter + Type parameter '{0}' has the same name as an extension parameter + + + + Type parameter '{0}' has the same name as an extension container type parameter + Type parameter '{0}' has the same name as an extension container type parameter + + Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. コントロールを呼び出し元に返す前に、自動実装プロパティ '{0}' を完全に割り当てる必要があります。プロパティを自動既定値にするため '{1}' 言語バージョンに更新することを検討してください。 @@ -2282,6 +2382,11 @@ コントロールを呼び出し元に返す前に、フィールド '{0}' を完全に割り当てる必要があります。プロパティを自動既定値にするため '{1}' 言語バージョンに更新することを検討してください。 + + The extended type '{0}' must reference all the type parameters declared by the extension, but type parameter '{1}' is not referenced. + The extended type '{0}' must reference all the type parameters declared by the extension, but type parameter '{1}' is not referenced. + + Unexpected parameter list. 予期しないパラメーター リストです。 @@ -2372,6 +2477,16 @@ すべてのフィールドが割り当てられる前に、'this' オブジェクトを使用することはできません。割り当てられていないフィールドを自動既定値にするため '{0}' 言語バージョンに更新することを検討してください。 + + 'value': an automatically-generated parameter name conflicts with an extension parameter name + 'value': an automatically-generated parameter name conflicts with an extension parameter name + + + + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + + In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. @@ -2442,6 +2557,11 @@ 拡張プロパティ パターン + + extensions + extensions + + field keyword field キーワード @@ -2459,7 +2579,7 @@ first-class Span types - first-class Span types + 最初のクラスの Span 型 @@ -2539,7 +2659,7 @@ overload resolution priority - overload resolution priority + オーバーロード解決の優先順位 @@ -2552,6 +2672,11 @@ params コレクション + + partial events and constructors + partial events and constructors + + positional fields in records レコード内の位置指定フィールド @@ -2624,7 +2749,7 @@ unbound generic types in nameof operator - unbound generic types in nameof operator + nameof 演算子でバインドされていないジェネリック型 @@ -2714,12 +2839,12 @@ The '{0}' accessor of property '{1}' should use 'field' because the other accessor is using it. - The '{0}' accessor of property '{1}' should use 'field' because the other accessor is using it. + プロパティ '{1}' の '{0}' アクセサーは、他のアクセサーが使用しているため、'field' を使用する必要があります。 Property accessor should use 'field' because the other accessor is using it. - Property accessor should use 'field' because the other accessor is using it. + 他のアクセサーが使用しているため、プロパティ アクセサーは 'field' を使用する必要があります。 @@ -2743,13 +2868,13 @@ - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - アナライザー アセンブリ '{0}' は、コンパイラのバージョン '{1}' を参照しています。これは、現在実行中のバージョン '{2}' よりも新しいバージョンです。 + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + アナライザー アセンブリ '{0}' は、コンパイラのバージョン '{1}' を参照しています。これは、現在実行中のバージョン '{2}' よりも新しいバージョンです。 - The analyzer assembly references a newer version of the compiler than the currently running version. - アナライザー アセンブリが参照しるコンパイラのバージョンは、現在実行中のバージョンよりも新しいです。 + Analyzer assembly cannot be used because it references a newer version of the compiler than the currently running version. + アナライザー アセンブリが参照しるコンパイラのバージョンは、現在実行中のバージョンよりも新しいです。 @@ -2994,12 +3119,12 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + '{0}' は、評価の目的でのみ提供されています。将来の更新で変更または削除されることがあります: '{1}'。続行するには、この診断を抑制します。 Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + 種類は、評価の目的でのみ提供されています。将来の更新で変更または削除されることがあります。続行するには、この診断を非表示にします。 @@ -3074,12 +3199,12 @@ 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) - 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' はサポートされていません。代わりに、これらの属性の 'InterceptableLocation' ベースの生成に移動します。(https://github.com/dotnet/roslyn/issues/72133) 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) - 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' はサポートされていません。代わりに、これらの属性の 'InterceptableLocation' ベースの生成に移動します。(https://github.com/dotnet/roslyn/issues/72133) @@ -3212,14 +3337,14 @@ パラメーターにラムダの params 修飾子がありますが、ターゲット デリゲート型にはありません。 - - Partial property declarations '{0}' and '{1}' have signature differences. - 部分プロパティ宣言 '{0}' と '{1}' には、シグネチャの違いがあります。 + + Partial member declarations '{0}' and '{1}' have signature differences. + Partial member declarations '{0}' and '{1}' have signature differences. - - Partial property declarations have signature differences. - 部分プロパティの宣言には、シグネチャの違いがあります。 + + Partial member declarations have signature differences. + Partial member declarations have signature differences. @@ -3289,7 +3414,7 @@ This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escape scopes than '{1}'. - この参照は '{1}' に '{0}' を割り当てますが、'{1}' の値のエスケープ スコープは、'{0}' よりも狭いエスケープ スコープを持つ値の'{0}' を介した割り当てを許可する '{1}' よりも広い値のエスケープ スコープを持っています。 + この参照は '{1}' を '{0}' に割り当てますが、'{1}' は '{0}' よりも広い値のエスケープ スコープを持っているため、'{1}' よりも狭いエスケープ スコープを持つ値の '{0}' による割り当てが可能になります。 @@ -3766,7 +3891,7 @@ -nowin32manifest 既定の Win32 マニフェストを含めません -resource:<resinfo> 指定されたリソースを埋め込みます (短い形式: -res) -linkresource:<resinfo> このアセンブリに指定されたリソースをリンクします - (短い形式: -linkres) resinfo の形式: + (短い形式: -linkres) resinfo の形式: <file>[,<string name>[,public|private]] - コード生成 - @@ -3863,7 +3988,7 @@ -lib:<file list> 参照を検索する追加のディレクトリを 指定します -errorreport:<string> 内部コンパイラ エラーを処理する方法を指定します。 - prompt、send、queue、none のいずれかです。既定値は + prompt、send、queue、none のいずれかです。既定値は queue です。 -appconfig:<file> アセンブリ バインド設定を含むアプリケーション 構成ファイルを指定します @@ -5300,12 +5425,12 @@ Field '{0}' is never ref-assigned to, and will always have its default value (null reference) - Field '{0}' is never ref-assigned to, and will always have its default value (null reference) + フィールド '{0}' は参照割り当てされず、常に既定値 (null 参照) を持ちます Field is never ref-assigned to, and will always have its default value (null reference) - Field is never ref-assigned to, and will always have its default value (null reference) + フィールドは参照割り当てされず、常に既定値 (null 参照) を持ちます @@ -5379,12 +5504,12 @@ - Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or safely handling the case where 'field' is null in the 'get' accessor. null 非許容の {0} '{1}' には、コンストラクターの終了時に null 以外の値が入っていなければなりません。'required' 修飾子を追加するか、{0} を null 許容として宣言するか、'[field: MaybeNull, AllowNull]' 属性を追加することを検討してください。 Similar diagnostic message as 'WRN_UninitializedNonNullableField' - Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. null 非許容プロパティには、コンストラクターの終了時に null 以外の値が入っていなければなりません。'required' 修飾子を追加するか、プロパティを null 許容として宣言するか、'[field: MaybeNull, AllowNull]' 属性を追加することを検討してください。 @@ -5420,12 +5545,12 @@ UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. - UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute は、C# 11 以降、または net7.0 以降をターゲットにする場合にのみ有効です。 UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. - UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute は、C# 11 以降、または net7.0 以降をターゲットにする場合にのみ有効です。 @@ -6729,8 +6854,8 @@ - The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. - 'partial' 修飾子は、'class'、'record'、'struct'、'interface'、またはメソッドまだはプロパティの戻り値の型の直前にのみ指定できます。 + The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. + 'partial' 修飾子は、'class'、'record'、'struct'、'interface'、またはメソッドまだはプロパティの戻り値の型の直前にのみ指定できます。 @@ -8832,8 +8957,8 @@ AssemblyInfo.cs ファイルで RuntimeCompatibilityAttribute が false に設 - Cannot define a new extension method because the compiler required type '{0}' cannot be found. Are you missing a reference to System.Core.dll? - コンパイラで必要とされる型 '{0}' が見つからないため、新しい拡張メソッドを定義できません。System.Core.dll への参照が指定されていることを確認してください。 + Cannot define a new extension because the compiler required type '{0}' cannot be found. Are you missing a reference to System.Core.dll? + コンパイラで必要とされる型 '{0}' が見つからないため、新しい拡張メソッドを定義できません。System.Core.dll への参照が指定されていることを確認してください。 @@ -8927,8 +9052,8 @@ AssemblyInfo.cs ファイルで RuntimeCompatibilityAttribute が false に設 - Invalid token '{0}' in class, record, struct, or interface member declaration - クラス、レコード、構造体、またはインターフェイス メンバーの宣言でトークン '{0}' が無効です + Invalid token '{0}' in a member declaration + クラス、レコード、構造体、またはインターフェイス メンバーの宣言でトークン '{0}' が無効です @@ -10376,7 +10501,7 @@ C# では out と ref を区別しますが、CLR では同じと認識します Cannot open '{0}' for writing -- {1} - ファイル '{0}' を開いて書き込むことができません -- '{1}' + ファイル '{0}' を開いて書き込むことができません -- {1} @@ -12741,7 +12866,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string literals or try the EXPERIMENTAL feature flag 'experimental-data-section-string-literals'. - プログラムで使うユーザー文字列の長さの合計が許可されている制限を超えています。文字列リテラルの使用を減らしてください。 + プログラムで使用されたユーザー文字列の長さの合計が、許可されている制限を超えています。文字列リテラルの使用を減らすか、EXPERIMENTAL フラグ 'experimental-data-section-string-literals' を試してみてください。 @@ -13036,7 +13161,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + '{0}' は、評価の目的でのみ提供されています。将来の更新で変更または削除されることがあります。続行するには、この診断を非表示にします。 @@ -13091,7 +13216,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + メソッド '{0}' (トークン 0x{1:X8}) のデバッグ情報をアセンブリ '{2}': {3} から読み取ることができません diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index f07d6262bcc31..bcd95e3a7bbdf 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -222,6 +222,11 @@ 비동기 foreach에는 동적 형식 컬렉션을 사용할 수 없습니다. + + Extensions must be declared in a top-level, non-generic, static class + Extensions must be declared in a top-level, non-generic, static class + + The type '{0}' may not be used for a field of a record. '{0}' 형식은 레코드의 필드에 사용할 수 없습니다. @@ -373,8 +378,8 @@ - Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specifc numeric type. - 'INumberBase<T>'에서 상속되거나 확장되므로 '{0}' 숫자 상수 또는 관계형 패턴을 사용할 수 없습니다. 형식 패턴을 사용하여 특정 숫자 형식으로 좁히는 것이 좋습니다. + Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specific numeric type. + 'INumberBase<T>'에서 상속되거나 확장되므로 '{0}' 숫자 상수 또는 관계형 패턴을 사용할 수 없습니다. 형식 패턴을 사용하여 특정 숫자 형식으로 좁히는 것이 좋습니다. @@ -542,6 +547,11 @@ 레코드가 봉인되지 않았으므로 복사 생성자 '{0}'이(가) 퍼블릭이거나 보호되어야 합니다. + + Cannot emit this string literal into the data section because it has XXHash128 collision with another string literal: {0} + Cannot emit this string literal into the data section because it has XXHash128 collision with another string literal: {0} + + The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'. '{0}' 이름이 해당 'Deconstruct' 매개 변수 '{1}'과(와) 일치하지 않습니다. @@ -639,7 +649,7 @@ Cannot emit update; {0} '{1}' is missing. - Cannot emit update; {0} '{1}' is missing. + 업데이트를 내보낼 수 없습니다. {0} '{1}' 없습니다. @@ -717,6 +727,11 @@ 식 트리에는 컬렉션 식이 포함될 수 없습니다. + + An expression tree may not contain an extension property access + An expression tree may not contain an extension property access + + An expression tree may not contain a from-end index ('^') expression. 식 트리에는 내림차순 인덱스('^') 식을 포함할 수 없습니다. @@ -762,6 +777,26 @@ 식 트리에는 with 식이 포함될 수 없습니다. + + Extension declarations can include only methods or properties + Extension declarations can include only methods or properties + + + + Extension declarations may not have a name. + Extension declarations may not have a name. + + + + The receiver parameter of an extension cannot have a default value + The receiver parameter of an extension cannot have a default value + + + + '{0}' does not contain a definition for '{1}' and no accessible extension member '{1}' for receiver of type '{0}' could be found (are you missing a using directive or an assembly reference?) + '{0}' does not contain a definition for '{1}' and no accessible extension member '{1}' for receiver of type '{0}' could be found (are you missing a using directive or an assembly reference?) + + '{0}': extern event cannot have initializer '{0}': extern 이벤트에는 이니셜라이저를 사용할 수 없습니다. @@ -1247,6 +1282,11 @@ 'Experimental' 특성에 대한 diagnosticId 인수는 유효한 식별자여야 합니다. + + Cannot use extension parameter '{0}' in this context. + Cannot use extension parameter '{0}' in this context. + + '{0}' is not a valid function pointer return type modifier. Valid modifiers are 'ref' and 'ref readonly'. '{0}'은(는) 유효한 함수 포인터 반환 형식 한정자가 아닙니다. 유효한 한정자는 'ref' 및 'ref readonly'입니다. @@ -1339,7 +1379,7 @@ Element type of an iterator may not be a ref struct or a type parameter allowing ref structs - Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + 반복기의 요소 형식은 ref 구조체 또는 ref 구조체를 허용하는 형식 매개 변수일 수 없습니다. @@ -1387,6 +1427,16 @@ 목록 패턴은 '{0}' 형식의 값에 사용할 수 없습니다. 적합한 'Length' 또는 'Count' 속성을 찾을 수 없습니다. + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + + No overload for '{0}' matches function pointer '{1}' 함수 포인터 '{1}'과(와) 일치하는 '{0}'에 대한 오버로드가 없습니다. @@ -1687,6 +1737,16 @@ params 매개 변수는 유효한 컬렉션 형식이어야 합니다. + + '{0}': only the implementing declaration of a partial constructor can have an initializer + '{0}': only the implementing declaration of a partial constructor can have an initializer + + + + '{0}': partial event cannot have initializer + '{0}': partial event cannot have initializer + + Both partial member declarations must have identical accessibility modifiers. 두 부분 멤버 선언에는 동일한 접근성 한정자를 갖어야 합니다. @@ -1697,11 +1757,31 @@ 부분 멤버는 'abstract' 한정자를 갖을 수 없습니다. + + Partial member '{0}' may not have multiple defining declarations. + Partial member '{0}' may not have multiple defining declarations. + + + + Partial member '{0}' may not have multiple implementing declarations. + Partial member '{0}' may not have multiple implementing declarations. + + Both partial member declarations, '{0}' and '{1}', must use the same tuple element names. 두 부분 멤버 선언은 '{0}' 및 '{1}' 모두에서 동일한 튜플 요소 이름을 사용해야 합니다. + + Partial member '{0}' must have a definition part. + Partial member '{0}' must have a definition part. + + + + Partial member '{0}' must have an implementation part. + Partial member '{0}' must have an implementation part. + + A partial member must be declared within a partial type 부분 멤버 내에 부분 메서드가 선언되어야 함 @@ -1727,6 +1807,11 @@ 부분 멤버 선언에는 일치하는 참조 반환 값이 있어야 합니다. + + Both partial member declarations must have the same type. + Both partial member declarations must have the same type. + + Both partial member declarations must be unsafe or neither may be unsafe 두 부분 멤버 선언은 모두 unsafe이거나 unsafe가 아니어야 함 @@ -1797,11 +1882,6 @@ 두 부분 속성 선언이 모두 필요하거나 둘 다 필요하지 않을 수 있습니다. - - Both partial property declarations must have the same type. - 두 부분 속성 선언의 형식이 같아야 합니다. - - Property accessor '{0}' does not implement any accessor declared on the definition part 속성 접근자 '{0}'은(는) 정의 부분에 선언된 접근자를 구현하지 않음 @@ -1862,6 +1942,16 @@ '{0}': 속성 또는 인덱서에 get 접근자와 set 접근자가 둘 다 있는 경우에만 접근자에 'readonly'를 사용할 수 있습니다. + + An extension container can have only one receiver parameter + An extension container can have only one receiver parameter + + + + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + + The primary constructor conflicts with the synthesized copy constructor. 기본 생성자가 합성된 복사 생성자와 충돌합니다. @@ -2019,7 +2109,7 @@ The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. - The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + 'Microsoft.CodeAnalysis.EmbeddedAttribute' 형식은 제네릭이 아니고, 내부, sealed, static이 아니어야 하고, 매개 변수가 없는 생성자를 포함하고, System.Attribute에서 상속하며, 모든 형식에 적용할 수 있어야 합니다. @@ -2272,6 +2362,16 @@ 호출 규칙으로 사용하려면 '{0}' 형식이 public이어야 합니다. + + Type parameter '{0}' has the same name as an extension parameter + Type parameter '{0}' has the same name as an extension parameter + + + + Type parameter '{0}' has the same name as an extension container type parameter + Type parameter '{0}' has the same name as an extension container type parameter + + Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. 제어가 호출자에게 반환되기 전에 자동 구현 속성 '{0}'이(가) 완전히 할당되어야 합니다. 속성을 자동으로 기본 설정하려면 언어 버전 '{1}'(으)로 업데이트하는 것이 좋습니다. @@ -2282,6 +2382,11 @@ 제어가 호출자에게 반환되기 전에 필드 '{0}'이(가) 완전히 할당되어야 합니다. 필드를 자동으로 기본 설정하려면 언어 버전 '{1}'으로 업데이트하는 것이 좋습니다. + + The extended type '{0}' must reference all the type parameters declared by the extension, but type parameter '{1}' is not referenced. + The extended type '{0}' must reference all the type parameters declared by the extension, but type parameter '{1}' is not referenced. + + Unexpected parameter list. 예기치 않은 매개 변수 목록입니다. @@ -2372,6 +2477,16 @@ 모든 필드가 할당되기 전에는 'this' 개체를 사용할 수 없습니다. 할당되지 않은 필드의 기본값을 자동으로 설정하려면 언어 버전 '{0}'(으)로 업데이트하는 것이 좋습니다. + + 'value': an automatically-generated parameter name conflicts with an extension parameter name + 'value': an automatically-generated parameter name conflicts with an extension parameter name + + + + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + + In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. @@ -2442,6 +2557,11 @@ 확장 속성 패턴 + + extensions + extensions + + field keyword 필드 키워드 @@ -2459,7 +2579,7 @@ first-class Span types - first-class Span types + 첫 번째 클래스 범위 형식 @@ -2539,7 +2659,7 @@ overload resolution priority - overload resolution priority + 오버로드 해결 우선 순위 @@ -2552,6 +2672,11 @@ params 컬렉션 + + partial events and constructors + partial events and constructors + + positional fields in records 레코드의 위치 필드 @@ -2624,7 +2749,7 @@ unbound generic types in nameof operator - unbound generic types in nameof operator + nameof 연산자의 바인딩되지 않은 제네릭 형식 @@ -2714,12 +2839,12 @@ The '{0}' accessor of property '{1}' should use 'field' because the other accessor is using it. - The '{0}' accessor of property '{1}' should use 'field' because the other accessor is using it. + 다른 접근자가 사용하고 있으므로 속성 '{1}' '{0}' 접근자는 'field'를 사용해야 합니다. Property accessor should use 'field' because the other accessor is using it. - Property accessor should use 'field' because the other accessor is using it. + 다른 접근자가 사용하고 있으므로 속성 접근자는 'field'를 사용해야 합니다. @@ -2743,13 +2868,13 @@ - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - 분석기 어셈블리 '{0}'은(는) 컴파일러의 '{1}' 버전을 참조하며, 이 버전은 현재 실행 중인 버전 '{2}'보다 최신 버전입니다. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + 분석기 어셈블리 '{0}'은(는) 컴파일러의 '{1}' 버전을 참조하며, 이 버전은 현재 실행 중인 버전 '{2}'보다 최신 버전입니다. - The analyzer assembly references a newer version of the compiler than the currently running version. - 분석기 어셈블리는 현재 실행 중인 버전보다 최신 버전의 컴파일러를 참조합니다. + Analyzer assembly cannot be used because it references a newer version of the compiler than the currently running version. + 분석기 어셈블리는 현재 실행 중인 버전보다 최신 버전의 컴파일러를 참조합니다. @@ -2994,12 +3119,12 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + '{0}'은(는) 평가 목적으로 제공되며, 이후 업데이트에서 변경되거나 제거될 수 있습니다. '{1}'. 계속하려면 이 진단을 표시하지 않습니다. Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + 형식은 평가 목적으로 제공되며, 이후 업데이트에서 변경되거나 제거될 수 있습니다. 계속하려면 이 진단을 표시하지 않습니다. @@ -3074,12 +3199,12 @@ 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) - 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)'는 지원되지 않습니다. 대신 이러한 특성의 'InterceptableLocation' 기반 생성으로 이동합니다. (https://github.com/dotnet/roslyn/issues/72133) 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) - 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)'는 지원되지 않습니다. 대신 이러한 특성의 'InterceptableLocation' 기반 생성으로 이동합니다. (https://github.com/dotnet/roslyn/issues/72133) @@ -3212,14 +3337,14 @@ 매개 변수에 람다의 매개 변수 한정자가 있지만 대상 대리자 형식에는 없습니다. - - Partial property declarations '{0}' and '{1}' have signature differences. - 부분 속성 선언 '{0}' 및 '{1}'에는 서명 차이가 있습니다. + + Partial member declarations '{0}' and '{1}' have signature differences. + Partial member declarations '{0}' and '{1}' have signature differences. - - Partial property declarations have signature differences. - 부분 속성 선언에는 서명 차이가 있습니다. + + Partial member declarations have signature differences. + Partial member declarations have signature differences. @@ -3721,7 +3846,7 @@ Visual C# 컴파일러 옵션 - 출력 파일 - --out:<file> 출력 파일 이름 지정(기본값: +-out:<file> 출력 파일 이름 지정(기본값: 메인 클래스가 있는 파일의 기본 이름 또는 첫 번째 파일) -target:exe 콘솔 실행 파일 빌드(기본값)(Short 형식: -t:exe) @@ -5300,12 +5425,12 @@ Field '{0}' is never ref-assigned to, and will always have its default value (null reference) - Field '{0}' is never ref-assigned to, and will always have its default value (null reference) + '{0}' 필드는 ref-assign되지 않으며 항상 기본값(null 참조)을 갖습니다. Field is never ref-assigned to, and will always have its default value (null reference) - Field is never ref-assigned to, and will always have its default value (null reference) + 필드는 ref-assign되지 않으며 항상 기본값(null 참조)을 갖습니다. @@ -5379,12 +5504,12 @@ - Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or safely handling the case where 'field' is null in the 'get' accessor. null을 허용하지 않는 {0} '{1}'은(는) 생성자를 종료할 때 null이 아닌 값을 포함해야 합니다. 'required' 한정자를 추가하거나 {0}을(를) nullable로 선언하거나 '[field: MaybeNull, AllowNull]' 특성을 추가하는 것이 좋습니다. Similar diagnostic message as 'WRN_UninitializedNonNullableField' - Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. null을 허용하지 않는 속성은 생성자를 종료할 때 null이 아닌 값을 포함해야 합니다. 'required' 한정자를 추가하거나 속성을 nullable로 선언하거나 '[field: MaybeNull, AllowNull]' 특성을 추가하는 것이 좋습니다. @@ -5420,12 +5545,12 @@ UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. - UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute는 C# 11 이상 또는 net7.0 이상을 대상으로 하는 경우에만 유효합니다. UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. - UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute는 C# 11 이상 또는 net7.0 이상을 대상으로 하는 경우에만 유효합니다. @@ -6729,8 +6854,8 @@ - The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. - 'partial' 한정자는 'class', 'record', 'struct', 'interface' 또는 메서드 또는 속성 반환 형식 바로 앞에만 올 수 있습니다. + The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. + 'partial' 한정자는 'class', 'record', 'struct', 'interface' 또는 메서드 또는 속성 반환 형식 바로 앞에만 올 수 있습니다. @@ -8832,8 +8957,8 @@ catch (System.Exception e) 블록 뒤의 catch() 블록은 RuntimeCompatibilityA - Cannot define a new extension method because the compiler required type '{0}' cannot be found. Are you missing a reference to System.Core.dll? - 컴파일러에 필요한 '{0}' 형식을 찾을 수 없으므로 새 확장 메서드를 정의할 수 없습니다. System.Core.dll의 참조가 있는지 확인하세요. + Cannot define a new extension because the compiler required type '{0}' cannot be found. Are you missing a reference to System.Core.dll? + 컴파일러에 필요한 '{0}' 형식을 찾을 수 없으므로 새 확장 메서드를 정의할 수 없습니다. System.Core.dll의 참조가 있는지 확인하세요. @@ -8927,8 +9052,8 @@ catch (System.Exception e) 블록 뒤의 catch() 블록은 RuntimeCompatibilityA - Invalid token '{0}' in class, record, struct, or interface member declaration - 클래스, 레코드, 구조체 또는 인터페이스 멤버 선언에 잘못된 토큰 '{0}'이(가) 있습니다. + Invalid token '{0}' in a member declaration + 클래스, 레코드, 구조체 또는 인터페이스 멤버 선언에 잘못된 토큰 '{0}'이(가) 있습니다. @@ -10376,7 +10501,7 @@ C#에서는 out과 ref를 구분하지만 CLR에서는 동일한 것으로 간 Cannot open '{0}' for writing -- {1} - '{0}'을(를) 쓰기용으로 열 수 없습니다. '{1}' + '{0}'을(를) 쓰기용으로 열 수 없습니다. {1} @@ -12741,7 +12866,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string literals or try the EXPERIMENTAL feature flag 'experimental-data-section-string-literals'. - 프로그램에서 사용하는 사용자 문자열의 결합된 길이가 허용 한도를 초과합니다. 문자열 리터럴의 사용을 줄여 보세요. + 프로그램에서 사용하는 사용자 문자열을 합친 길이가 허용 한도를 초과합니다. 문자열 리터럴의 사용을 줄이거나 실험적 기능 플래그 'experimental-data-section-string-literals'를 사용해 보세요. @@ -13036,7 +13161,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + '{0}'은(는) 평가 목적으로 제공되며, 이후 업데이트에서 변경되거나 제거될 수 있습니다. 계속하려면 이 진단을 표시하지 않습니다. @@ -13091,7 +13216,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + '{0}' 어셈블리에서 '{2}' 메서드(토큰 0x{1:X8})의 디버그 정보를 읽을 수 없습니다.{3} diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 37aa1d6039020..913d6bb519b5e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -222,6 +222,11 @@ Nie można użyć kolekcji typu dynamicznego w asynchronicznej instrukcji foreach + + Extensions must be declared in a top-level, non-generic, static class + Extensions must be declared in a top-level, non-generic, static class + + The type '{0}' may not be used for a field of a record. Typ „{0}” nie może być używany dla pola rekordu. @@ -373,8 +378,8 @@ - Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specifc numeric type. - Nie można użyć stałej liczbowej lub wzorca relacyjnego w „{0}”, ponieważ dziedziczy on lub rozszerza element "INumberBase<T>". Rozważ użycie wzorca typu w celu zawężenia do określonego typu liczbowego. + Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specific numeric type. + Nie można użyć stałej liczbowej lub wzorca relacyjnego w „{0}”, ponieważ dziedziczy on lub rozszerza element "INumberBase<T>". Rozważ użycie wzorca typu w celu zawężenia do określonego typu liczbowego. @@ -542,6 +547,11 @@ Konstruktor kopiujący „{0}” musi być publiczny lub chroniony, ponieważ rekord nie jest zapieczętowany. + + Cannot emit this string literal into the data section because it has XXHash128 collision with another string literal: {0} + Cannot emit this string literal into the data section because it has XXHash128 collision with another string literal: {0} + + The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'. Nazwa „{0}” nie jest zgodna z odpowiednim parametrem „Deconstruct” „{1}”. @@ -639,7 +649,7 @@ Cannot emit update; {0} '{1}' is missing. - Cannot emit update; {0} '{1}' is missing. + Nie można wyemitować aktualizacji;brak {0} '{1}' . @@ -717,6 +727,11 @@ Drzewo wyrażenia nie może zawierać wyrażenia kolekcji. + + An expression tree may not contain an extension property access + An expression tree may not contain an extension property access + + An expression tree may not contain a from-end index ('^') expression. Drzewo wyrażeń nie może zawierać wyrażenia „od końca indeksu” („^”). @@ -762,6 +777,26 @@ Drzewo wyrażeń nie może zawierać wyrażenia with. + + Extension declarations can include only methods or properties + Extension declarations can include only methods or properties + + + + Extension declarations may not have a name. + Extension declarations may not have a name. + + + + The receiver parameter of an extension cannot have a default value + The receiver parameter of an extension cannot have a default value + + + + '{0}' does not contain a definition for '{1}' and no accessible extension member '{1}' for receiver of type '{0}' could be found (are you missing a using directive or an assembly reference?) + '{0}' does not contain a definition for '{1}' and no accessible extension member '{1}' for receiver of type '{0}' could be found (are you missing a using directive or an assembly reference?) + + '{0}': extern event cannot have initializer „{0}”: zdarzenie extern nie może mieć inicjatora @@ -1247,6 +1282,11 @@ Argument diagnosticId atrybutu „Experimental” musi być prawidłowym identyfikatorem + + Cannot use extension parameter '{0}' in this context. + Cannot use extension parameter '{0}' in this context. + + '{0}' is not a valid function pointer return type modifier. Valid modifiers are 'ref' and 'ref readonly'. Element „{0}” nie jest prawidłowym modyfikatorem zwracanego typu wskaźnikowego funkcji. Prawidłowe modyfikatory to „ref” i „ref readonly”. @@ -1339,7 +1379,7 @@ Element type of an iterator may not be a ref struct or a type parameter allowing ref structs - Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + Typ elementu iteratora nie może być strukturą ref ani parametrem typu umożliwiającym struktury ref @@ -1387,6 +1427,16 @@ Wzorce listy nie mogą być używane dla wartości typu „{0}”. Nie znaleziono odpowiedniej właściwości „Długość” ani „Liczba”. + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + + No overload for '{0}' matches function pointer '{1}' Żadne z przeciążeń dla elementu „{0}” nie pasuje do wskaźnika funkcji „{1}” @@ -1687,6 +1737,16 @@ Parametr params musi mieć prawidłowy typ kolekcji + + '{0}': only the implementing declaration of a partial constructor can have an initializer + '{0}': only the implementing declaration of a partial constructor can have an initializer + + + + '{0}': partial event cannot have initializer + '{0}': partial event cannot have initializer + + Both partial member declarations must have identical accessibility modifiers. Obie częściowe deklaracje elementów członkowskich muszą mieć identyczne modyfikatory dostępności. @@ -1697,11 +1757,31 @@ Częściowy element członkowski nie może mieć modyfikatora „abstract” + + Partial member '{0}' may not have multiple defining declarations. + Partial member '{0}' may not have multiple defining declarations. + + + + Partial member '{0}' may not have multiple implementing declarations. + Partial member '{0}' may not have multiple implementing declarations. + + Both partial member declarations, '{0}' and '{1}', must use the same tuple element names. Obie deklaracje częściowych elementów członkowskich, „{0}” i „{1}”, muszą korzystać z tych samych nazw elementów krotki. + + Partial member '{0}' must have a definition part. + Partial member '{0}' must have a definition part. + + + + Partial member '{0}' must have an implementation part. + Partial member '{0}' must have an implementation part. + + A partial member must be declared within a partial type Częściowy element członkowski musi być zadeklarowany w ramach częściowego typu @@ -1727,6 +1807,11 @@ Deklaracje częściowych elementów członkowskich muszą mieć pasujące wartości zwracane ref. + + Both partial member declarations must have the same type. + Both partial member declarations must have the same type. + + Both partial member declarations must be unsafe or neither may be unsafe Obie częściowe deklaracje elementów członkowskich muszą być niebezpieczne lub żadna z nich nie może być niebezpieczna @@ -1797,11 +1882,6 @@ Obie deklaracje właściwości częściowych muszą być wymagane lub żadna z nich nie może być wymagana - - Both partial property declarations must have the same type. - Obie deklaracje właściwości częściowych muszą mieć ten sam typ. - - Property accessor '{0}' does not implement any accessor declared on the definition part Właściwość accessor „{0}” nie implementuje żadnego accessora zadeklarowanego w części definiującej @@ -1862,6 +1942,16 @@ „{0}”: modyfikatora „readonly” można użyć dla metod dostępu tylko wtedy, gdy właściwość lub indeksator mają metody dostępu get i set + + An extension container can have only one receiver parameter + An extension container can have only one receiver parameter + + + + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + + The primary constructor conflicts with the synthesized copy constructor. Konstruktor podstawowy powoduje konflikt z konstruktorem syntetyzowanej kopii. @@ -2019,7 +2109,7 @@ The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. - The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + Typ "Microsoft.CodeAnalysis.EmbeddedAttribute" nie może być rodzajowy, wewnętrzny, zapieczętowany, niestatyczny, mieć konstruktor bez parametrów, dziedziczyć z elementu System.Attribute i można go zastosować do dowolnego typu. @@ -2272,6 +2362,16 @@ Typ „{0}” musi być publiczny, aby można go było używać jako konwencji wywoływania. + + Type parameter '{0}' has the same name as an extension parameter + Type parameter '{0}' has the same name as an extension parameter + + + + Type parameter '{0}' has the same name as an extension container type parameter + Type parameter '{0}' has the same name as an extension container type parameter + + Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. Automatycznie implementowana właściwość „{0}” musi być w pełni przypisana, zanim kontrolka zostanie zwrócona do obiektu wywołującego. Rozważ zaktualizowanie do wersji językowej „{1}”, aby automatycznie ustawić domyślną właściwość. @@ -2282,6 +2382,11 @@ Pole „{0}” musi być w pełni przypisane, zanim kontrolka zostanie zwrócona do obiektu wywołującego. Rozważ zaktualizowanie pola do wersji językowej „{1}”, aby automatycznie ustawić domyślne pole. + + The extended type '{0}' must reference all the type parameters declared by the extension, but type parameter '{1}' is not referenced. + The extended type '{0}' must reference all the type parameters declared by the extension, but type parameter '{1}' is not referenced. + + Unexpected parameter list. Nieoczekiwana lista parametrów. @@ -2372,6 +2477,16 @@ Nie można użyć obiektu „this” przed przypisaniem wszystkich jego pól. Rozważ zaktualizowanie nieprzypisanych pól do wersji językowej „{0}”, aby automatycznie ustawić domyślne pola niezaznaczone. + + 'value': an automatically-generated parameter name conflicts with an extension parameter name + 'value': an automatically-generated parameter name conflicts with an extension parameter name + + + + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + + In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. @@ -2442,6 +2557,11 @@ wzorce właściwości rozszerzonych + + extensions + extensions + + field keyword słowo kluczowe pola @@ -2459,7 +2579,7 @@ first-class Span types - first-class Span types + typy span pierwszej klasy @@ -2539,7 +2659,7 @@ overload resolution priority - overload resolution priority + priorytet rozwiązywania przeciążenia @@ -2552,6 +2672,11 @@ kolekcje params + + partial events and constructors + partial events and constructors + + positional fields in records pola pozycyjne w rekordach @@ -2624,7 +2749,7 @@ unbound generic types in nameof operator - unbound generic types in nameof operator + niepowiązane typy ogólne w operatorze nameof @@ -2714,12 +2839,12 @@ The '{0}' accessor of property '{1}' should use 'field' because the other accessor is using it. - The '{0}' accessor of property '{1}' should use 'field' because the other accessor is using it. + Metoda dostępu '{0}' właściwości '{1}' powinna używać wartości "field", ponieważ używa jej inna metoda dostępu. Property accessor should use 'field' because the other accessor is using it. - Property accessor should use 'field' because the other accessor is using it. + Metoda dostępu do właściwości powinna używać elementu "field", ponieważ używa go inna metoda dostępu. @@ -2743,13 +2868,13 @@ - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - Zestaw analizatora „{0}” odwołuje się do wersji „{1}” kompilatora, która jest nowsza niż obecnie uruchomiona wersja „{2}”. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + Zestaw analizatora „{0}” odwołuje się do wersji „{1}” kompilatora, która jest nowsza niż obecnie uruchomiona wersja „{2}”. - The analyzer assembly references a newer version of the compiler than the currently running version. - Zestaw analizatora odwołuje się do nowszej wersji kompilatora niż obecnie uruchomiona wersja. + Analyzer assembly cannot be used because it references a newer version of the compiler than the currently running version. + Zestaw analizatora odwołuje się do nowszej wersji kompilatora niż obecnie uruchomiona wersja. @@ -2994,12 +3119,12 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + Element „{0}” jest przeznaczony wyłącznie do celów ewaluacyjnych i może zostać zmieniony albo usunięty w przyszłych aktualizacjach: „”{1}. Wstrzymaj tę diagnostykę, aby kontynuować. Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + Typ jest przeznaczony wyłącznie do celów ewaluacyjnych i może zostać zmieniony albo usunięty w przyszłych aktualizacjach. Wstrzymaj tę diagnostykę, aby kontynuować. @@ -3074,12 +3199,12 @@ 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) - 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + Element "InterceptsLocationAttribute(string, int, int)" nie jest obsługiwany. Zamiast tego przejdź do generowania tych atrybutów opartego na opcji "InterceptableLocation". (https://github.com/dotnet/roslyn/issues/72133) 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) - 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + Element "InterceptsLocationAttribute(string, int, int)" nie jest obsługiwany. Zamiast tego przejdź do generowania tych atrybutów opartego na opcji "InterceptableLocation". (https://github.com/dotnet/roslyn/issues/72133) @@ -3212,14 +3337,14 @@ Parametr ma modyfikator params w wyrażeniu lambda, ale nie ma w docelowym typie delegata. - - Partial property declarations '{0}' and '{1}' have signature differences. - Deklaracje właściwości częściowych „{0}” i „{1}” mają różnice w sygnaturach. + + Partial member declarations '{0}' and '{1}' have signature differences. + Partial member declarations '{0}' and '{1}' have signature differences. - - Partial property declarations have signature differences. - Deklaracje właściwości częściowych różnią się sygnaturami. + + Partial member declarations have signature differences. + Partial member declarations have signature differences. @@ -3720,7 +3845,7 @@ Opcje kompilatora języka Visual C# - - PLIKI WYJŚCIOWE - + - PLIKI WYJŚCIOWE - -out:<file> Określanie nazwy pliku wyjściowego (domyślnie: nazwa podstawowa pliku z klasą główną lub pierwszym plikiem) -target:exe Kompiluj plik wykonywalny konsoli (domyślnie) (skrócona @@ -5300,12 +5425,12 @@ Field '{0}' is never ref-assigned to, and will always have its default value (null reference) - Field '{0}' is never ref-assigned to, and will always have its default value (null reference) + Pole „{0}” nigdy nie ma przypisanej wartości ref i zawsze będzie miało wartość domyślną (odwołanie o wartości null) Field is never ref-assigned to, and will always have its default value (null reference) - Field is never ref-assigned to, and will always have its default value (null reference) + Pole nigdy nie ma przypisanej wartości red i zawsze będzie miało wartość domyślną (odwołanie o wartości null) @@ -5379,12 +5504,12 @@ - Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or safely handling the case where 'field' is null in the 'get' accessor. Niedopuszczający wartości null element {0} „{1}” musi zawierać wartość inną niż null podczas kończenia działania konstruktora. Rozważ dodanie modyfikatora „required”, zadeklarowanie {0} jako dopuszczającej wartość null lub dodanie atrybutów „[field: MaybeNull, AllowNull]”. Similar diagnostic message as 'WRN_UninitializedNonNullableField' - Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. Właściwość niedopuszczająca wartości null musi zawierać wartość inną niż null podczas zamykania konstruktora. Rozważ dodanie modyfikatora „required” lub zadeklarowanie właściwości dopuszczającej wartość null lub dodanie atrybutów „[field: MaybeNull, AllowNull]”. @@ -5420,12 +5545,12 @@ UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. - UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + Atrybut UnscopedRefAttribute jest prawidłowy tylko w języku C# 11 lub nowszym albo w przypadku platformy docelowej net7.0 lub nowszej. UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. - UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + Atrybut UnscopedRefAttribute jest prawidłowy tylko w języku C# 11 lub nowszym albo w przypadku platformy docelowej net7.0 lub nowszej. @@ -6729,8 +6854,8 @@ - The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. - Modyfikator „partial” może pojawić się tylko bezpośrednio przed słowem kluczowym „class”, „record” „struct”, „interface” lub zwracanym typem metody lub właściwości. + The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. + Modyfikator „partial” może pojawić się tylko bezpośrednio przed słowem kluczowym „class”, „record” „struct”, „interface” lub zwracanym typem metody lub właściwości. @@ -8832,8 +8957,8 @@ Blok catch() po bloku catch (System.Exception e) może przechwytywać wyjątki n - Cannot define a new extension method because the compiler required type '{0}' cannot be found. Are you missing a reference to System.Core.dll? - Nie można zdefiniować nowej metody rozszerzenia, ponieważ nie można odnaleźć wymaganego przez kompilator typu „{0}”. Czy brakuje odwołania do System.Core.dll? + Cannot define a new extension because the compiler required type '{0}' cannot be found. Are you missing a reference to System.Core.dll? + Nie można zdefiniować nowej metody rozszerzenia, ponieważ nie można odnaleźć wymaganego przez kompilator typu „{0}”. Czy brakuje odwołania do System.Core.dll? @@ -8927,8 +9052,8 @@ Blok catch() po bloku catch (System.Exception e) może przechwytywać wyjątki n - Invalid token '{0}' in class, record, struct, or interface member declaration - Nieprawidłowy token „{0}” w deklaracji składowej klasy, rekordu, struktury lub interfejsu + Invalid token '{0}' in a member declaration + Nieprawidłowy token „{0}” w deklaracji składowej klasy, rekordu, struktury lub interfejsu @@ -10376,7 +10501,7 @@ Musisz umożliwić kompilatorowi rozróżnienie metod. Możesz na przykład nada Cannot open '{0}' for writing -- {1} - Nie można otworzyć „{0}” do zapisu — „{1}” + Nie można otworzyć „{0}” do zapisu — „{1}” @@ -12741,7 +12866,7 @@ Aby usunąć ostrzeżenie, możesz zamiast tego użyć opcji /reference (ustaw w Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string literals or try the EXPERIMENTAL feature flag 'experimental-data-section-string-literals'. - Całkowita długość ciągów użytkownika używanych przez program przekracza dozwolony limit. Spróbuj ograniczyć użycie literałów ciągów. + Całkowita długość ciągów użytkownika używanych przez program przekracza dozwolony limit. Spróbuj zmniejszyć użycie literałów ciągów lub spróbuj użyć flagi funkcji EXPERIMENTAL „experimental-data-section-string-literals”. @@ -13036,7 +13161,7 @@ Aby usunąć ostrzeżenie, możesz zamiast tego użyć opcji /reference (ustaw w '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + Element „{0}” jest przeznaczony wyłącznie do celów ewaluacyjnych i może zostać zmieniony albo usunięty w przyszłych aktualizacjach. Wstrzymaj tę diagnostykę, aby kontynuować. @@ -13091,7 +13216,7 @@ Aby usunąć ostrzeżenie, możesz zamiast tego użyć opcji /reference (ustaw w Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Nie można odczytać informacji debugowania metody „{0}” (token 0x{1:X8}) z zestawu „{2}”: {3} diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 06a0fb19e3111..f872c327e0b6b 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -222,6 +222,11 @@ Não é possível usar uma coleção do tipo dinâmico em uma foreach assíncrona + + Extensions must be declared in a top-level, non-generic, static class + Extensions must be declared in a top-level, non-generic, static class + + The type '{0}' may not be used for a field of a record. O tipo '{0}' não pode ser usado para um campo de um registro. @@ -373,8 +378,8 @@ - Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specifc numeric type. - Não é possível usar uma constante numérica ou padrão relacional em '{0}' porque herda ou estende 'INumberBase<T>'. Considere usar um padrão de tipo para restringir a um tipo numérico específico. + Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specific numeric type. + Não é possível usar uma constante numérica ou padrão relacional em '{0}' porque herda ou estende 'INumberBase<T>'. Considere usar um padrão de tipo para restringir a um tipo numérico específico. @@ -542,6 +547,11 @@ Um construtor de cópia '{0}' precisa ser público ou protegido porque o registro não está selado. + + Cannot emit this string literal into the data section because it has XXHash128 collision with another string literal: {0} + Cannot emit this string literal into the data section because it has XXHash128 collision with another string literal: {0} + + The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'. O nome '{0}' não corresponde ao parâmetro 'Deconstruct' '{1}'. @@ -639,7 +649,7 @@ Cannot emit update; {0} '{1}' is missing. - Cannot emit update; {0} '{1}' is missing. + Não é possível emitir a atualização; {0} '{1}' está ausente. @@ -717,6 +727,11 @@ Uma árvore de expressão não pode conter uma expressão de coleção. + + An expression tree may not contain an extension property access + An expression tree may not contain an extension property access + + An expression tree may not contain a from-end index ('^') expression. Uma árvore de expressão não pode conter uma expressão de índice de front-end ('^'). @@ -762,6 +777,26 @@ Uma árvore de expressão não pode conter uma expressão with. + + Extension declarations can include only methods or properties + Extension declarations can include only methods or properties + + + + Extension declarations may not have a name. + Extension declarations may not have a name. + + + + The receiver parameter of an extension cannot have a default value + The receiver parameter of an extension cannot have a default value + + + + '{0}' does not contain a definition for '{1}' and no accessible extension member '{1}' for receiver of type '{0}' could be found (are you missing a using directive or an assembly reference?) + '{0}' does not contain a definition for '{1}' and no accessible extension member '{1}' for receiver of type '{0}' could be found (are you missing a using directive or an assembly reference?) + + '{0}': extern event cannot have initializer '{0}': o evento externo não pode ter inicializador @@ -1247,6 +1282,11 @@ O argumento diagnosticId para o atributo 'Experimental' deve ser um identificador válido + + Cannot use extension parameter '{0}' in this context. + Cannot use extension parameter '{0}' in this context. + + '{0}' is not a valid function pointer return type modifier. Valid modifiers are 'ref' and 'ref readonly'. '{0}' não é um modificador de tipo de retorno de ponteiro de função válido. Os modificadores válidos são 'ref' e 'ref readonly'. @@ -1339,7 +1379,7 @@ Element type of an iterator may not be a ref struct or a type parameter allowing ref structs - Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + O tipo de elemento de um iterador não pode ser um struct ref ou um parâmetro de tipo que permita structs ref @@ -1387,6 +1427,16 @@ Padrões de lista não podem ser usados para um valor do tipo “{0}”. Nenhuma propriedade “Length” ou “Count” adequada foi encontrada. + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + + No overload for '{0}' matches function pointer '{1}' Nenhuma sobrecarga de '{0}' corresponde ao ponteiro de função '{1}' @@ -1687,6 +1737,16 @@ O parâmetro params deve ter um tipo de coleção válido + + '{0}': only the implementing declaration of a partial constructor can have an initializer + '{0}': only the implementing declaration of a partial constructor can have an initializer + + + + '{0}': partial event cannot have initializer + '{0}': partial event cannot have initializer + + Both partial member declarations must have identical accessibility modifiers. As duas declarações de membros parciais precisam ter modificadores de acessibilidade idênticos. @@ -1697,11 +1757,31 @@ Um membro parcial não pode ter o modificador "abstract" + + Partial member '{0}' may not have multiple defining declarations. + Partial member '{0}' may not have multiple defining declarations. + + + + Partial member '{0}' may not have multiple implementing declarations. + Partial member '{0}' may not have multiple implementing declarations. + + Both partial member declarations, '{0}' and '{1}', must use the same tuple element names. As duas declarações de membros parciais, "{0}" e "{1}", precisam usar os mesmos nomes de elementos de tupla. + + Partial member '{0}' must have a definition part. + Partial member '{0}' must have a definition part. + + + + Partial member '{0}' must have an implementation part. + Partial member '{0}' must have an implementation part. + + A partial member must be declared within a partial type Um membro parcial precisa ser declarado dentro de um tipo parcial @@ -1727,6 +1807,11 @@ As declarações de membros parciais precisam ter valores de retorno de referência correspondentes. + + Both partial member declarations must have the same type. + Both partial member declarations must have the same type. + + Both partial member declarations must be unsafe or neither may be unsafe As duas declarações de membros parciais precisam ser inseguras ou nenhuma pode ser insegura @@ -1797,11 +1882,6 @@ As duas declarações de propriedades parciais precisam ser obrigatórias ou nenhuma delas pode ser obrigatória - - Both partial property declarations must have the same type. - As duas declarações de propriedades parciais precisam ter o mesmo tipo. - - Property accessor '{0}' does not implement any accessor declared on the definition part O acessador de propriedade "{0}" não implementa nenhum acessador declarado na parte de definição @@ -1862,6 +1942,16 @@ '{0}': 'readonly' somente pode ser usado em acessadores quando a propriedade ou o indexador tem um acessador get e um set + + An extension container can have only one receiver parameter + An extension container can have only one receiver parameter + + + + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + + The primary constructor conflicts with the synthesized copy constructor. O construtor primário entra em conflito com o construtor de cópia sintetizado. @@ -1884,7 +1974,7 @@ Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escape scopes than '{1}'. - Não é possível atribuir novamente '{1}' a '{0}' porque '{1}' tem um escopo de escape de valor maior que '{0}' permitindo a atribuição por meio de '{0}' de valores com escopos de escape mais estreitos do que '{1}'. + Não foi possível atribuir com ref "{1}" a "{0}" porque "{1}" tem um escopo de escape mais amplo que "{0}", permitindo a atribuição por meio de "{0}" de valores com escopos de escape mais restritos que "{1}". @@ -2019,7 +2109,7 @@ The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. - The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + O tipo 'Microsoft.CodeAnalysis.EmbeddedAttribute' deve ser não genérico, interno, lacrado, não estático, ter um construtor sem parâmetros, herdar de System.Attribute e ser aplicado a qualquer tipo. @@ -2272,6 +2362,16 @@ O tipo '{0}' precisa ser público para ser usado como uma convenção de chamada. + + Type parameter '{0}' has the same name as an extension parameter + Type parameter '{0}' has the same name as an extension parameter + + + + Type parameter '{0}' has the same name as an extension container type parameter + Type parameter '{0}' has the same name as an extension container type parameter + + Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. A propriedade auto-implementada '{0}' deve ser totalmente atribuída antes que o controle seja devolvido ao chamador. Considere atualizar para a versão de linguagem '{1}' para auto-padrão da propriedade. @@ -2282,6 +2382,11 @@ O campo '{0}' deve ser totalmente atribuída antes que o controle seja devolvido ao chamador. Considere atualizar para a versão de linguagem '{1}' para auto-padrão do campo. + + The extended type '{0}' must reference all the type parameters declared by the extension, but type parameter '{1}' is not referenced. + The extended type '{0}' must reference all the type parameters declared by the extension, but type parameter '{1}' is not referenced. + + Unexpected parameter list. Lista de parâmetros inesperada. @@ -2372,6 +2477,16 @@ O objeto 'this' não pode ser usado antes que todos os seus campos serem atribuídos. Considere atualizar para a versão de linguagem '{0}' para auto-padrão dos campos não atribuídos. + + 'value': an automatically-generated parameter name conflicts with an extension parameter name + 'value': an automatically-generated parameter name conflicts with an extension parameter name + + + + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + + In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. @@ -2442,6 +2557,11 @@ padrões de propriedade estendida + + extensions + extensions + + field keyword campo palavra-chave @@ -2459,7 +2579,7 @@ first-class Span types - first-class Span types + tipos de Span de primeira classe @@ -2539,7 +2659,7 @@ overload resolution priority - overload resolution priority + Prioridade de resolução de sobrecarga @@ -2552,6 +2672,11 @@ coleções de params + + partial events and constructors + partial events and constructors + + positional fields in records campos posicionais nos registros @@ -2624,7 +2749,7 @@ unbound generic types in nameof operator - unbound generic types in nameof operator + tipos genéricos não associados no operador nameof @@ -2714,12 +2839,12 @@ The '{0}' accessor of property '{1}' should use 'field' because the other accessor is using it. - The '{0}' accessor of property '{1}' should use 'field' because the other accessor is using it. + O '{0}' da propriedade '{1}' deve usar 'field' porque o outro acessador o está usando. Property accessor should use 'field' because the other accessor is using it. - Property accessor should use 'field' because the other accessor is using it. + O acessador de propriedade deve usar 'field' porque o outro acessador o está usando. @@ -2743,13 +2868,13 @@ - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - O assembly do analisador '{0}' referencia a versão '{1}' do compilador, que é mais recente que a versão em execução no momento '{2}'. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + O assembly do analisador '{0}' referencia a versão '{1}' do compilador, que é mais recente que a versão em execução no momento '{2}'. - The analyzer assembly references a newer version of the compiler than the currently running version. - O assembly do analisador faz referência a uma versão mais recente do compilador do que a versão em execução no momento. + Analyzer assembly cannot be used because it references a newer version of the compiler than the currently running version. + O assembly do analisador faz referência a uma versão mais recente do compilador do que a versão em execução no momento. @@ -2994,12 +3119,12 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + '{0}' é apenas para fins de avaliação e está sujeito a alterações ou remoção em futuras atualizações: '{1}'. Suprima este diagnóstico para continuar. Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + O tipo é apenas para fins de avaliação e está sujeito a alterações ou remoção em atualizações futuras. Suprima este diagnóstico para continuar. @@ -3074,12 +3199,12 @@ 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) - 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + Não há suporte para 'InterceptsLocationAttribute(string, int, int)'. Mova para a geração baseada em 'InterceptableLocation' desses atributos. (https://github.com/dotnet/roslyn/issues/72133) 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) - 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + Não há suporte para 'InterceptsLocationAttribute(string, int, int)'. Mova para a geração baseada em 'InterceptableLocation' desses atributos. (https://github.com/dotnet/roslyn/issues/72133) @@ -3212,14 +3337,14 @@ O parâmetro tem modificador de parâmetros em lambda, mas não no tipo delegado de destino. - - Partial property declarations '{0}' and '{1}' have signature differences. - As declarações de propriedades parciais "{0}" e "{1}" têm diferenças de assinatura. + + Partial member declarations '{0}' and '{1}' have signature differences. + Partial member declarations '{0}' and '{1}' have signature differences. - - Partial property declarations have signature differences. - As declarações de propriedade parcial têm diferenças de assinatura. + + Partial member declarations have signature differences. + Partial member declarations have signature differences. @@ -3289,7 +3414,7 @@ This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escape scopes than '{1}'. - Esta referência atribui '{1}' a '{0}', mas '{1}' tem um escopo de escape de valor maior do que '{0}' permitindo a atribuição por meio de '{0}' de valores com escopos de escape mais estreitos do que '{1}'. + Com isso "{1}" é atribuído com ref a "{0}", mas "{1}" tem um escopo de escape mais amplo que "{0}", permitindo a atribuição por meio de "{0}" de valores com escopos de escape mais restritos que "{1}". @@ -5300,12 +5425,12 @@ Field '{0}' is never ref-assigned to, and will always have its default value (null reference) - Field '{0}' is never ref-assigned to, and will always have its default value (null reference) + O campo "{0}" nunca recebe uma atribuição com ref e sempre terá seu valor padrão (referência nula) Field is never ref-assigned to, and will always have its default value (null reference) - Field is never ref-assigned to, and will always have its default value (null reference) + O campo nunca recebe uma atribuição com ref e sempre terá seu valor padrão (referência nula) @@ -5379,12 +5504,12 @@ - Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or safely handling the case where 'field' is null in the 'get' accessor. A {0} não anulável ''{1}'' precisa conter um valor não nulo ao sair do construtor. Considere adicionar o modificador ''necessário'' ou declarar a {0} como anulável ou adicionar os atributos ''[field: MaybeNull, AllowNull]''. Similar diagnostic message as 'WRN_UninitializedNonNullableField' - Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. A propriedade não anulável deve conter um valor não nulo ao sair do construtor. Considere adicionar o modificador ''required'' ou declarar a propriedade como anulável ou adicionar os atributos ''[field: MaybeNull, AllowNull]''. @@ -5420,12 +5545,12 @@ UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. - UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute só é válido em C# 11 ou posterior ou ao direcionar para net7.0 ou posterior. UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. - UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute só é válido em C# 11 ou posterior ou ao direcionar para net7.0 ou posterior. @@ -6729,8 +6854,8 @@ - The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. - O modificador "partial" só pode aparecer imediatamente antes de "class", de "record", de "struct", de "interface" ou de um tipo de retorno de método ou propriedade. + The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. + O modificador "partial" só pode aparecer imediatamente antes de "class", de "record", de "struct", de "interface" ou de um tipo de retorno de método ou propriedade. @@ -8832,8 +8957,8 @@ Um bloco catch() depois de um bloco catch (System.Exception e) poderá capturar - Cannot define a new extension method because the compiler required type '{0}' cannot be found. Are you missing a reference to System.Core.dll? - Não é possível definir um novo método de extensão porque o tipo necessário de compilador "{0}" não pode ser encontrado. Está faltando uma referência a System.Core.dll? + Cannot define a new extension because the compiler required type '{0}' cannot be found. Are you missing a reference to System.Core.dll? + Não é possível definir um novo método de extensão porque o tipo necessário de compilador "{0}" não pode ser encontrado. Está faltando uma referência a System.Core.dll? @@ -8927,8 +9052,8 @@ Um bloco catch() depois de um bloco catch (System.Exception e) poderá capturar - Invalid token '{0}' in class, record, struct, or interface member declaration - Token inválido '{0}' na declaração de membro de classe, de registro, de struct ou de interface + Invalid token '{0}' in a member declaration + Token inválido '{0}' na declaração de membro de classe, de registro, de struct ou de interface @@ -10376,7 +10501,7 @@ Forneça ao compilador alguma forma de diferenciar os métodos. Por exemplo, voc Cannot open '{0}' for writing -- {1} - Não é possível abrir "{0}" para escrever -- "{1}" + Não foi possível abrir "{0}" para escrever — {1} @@ -12741,7 +12866,7 @@ Para incorporar informações de tipo de interoperabilidade para os dois assembl Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string literals or try the EXPERIMENTAL feature flag 'experimental-data-section-string-literals'. - O comprimento combinado de cadeias do usuários usadas pelo programa excede o limite permitido. Tente diminuir o uso de literais de cadeia. + O comprimento combinado de cadeias de caracteres de usuário usado pelo programa excede o limite permitido. Tente diminuir o uso de literais de cadeia de caracteres ou experimente o sinalizador de recurso EXPERIMENTAL 'experimental-data-section-string-literals'. @@ -13036,7 +13161,7 @@ Para incorporar informações de tipo de interoperabilidade para os dois assembl '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + '{0}'é apenas para fins de avaliação e está sujeito a alterações ou remoção em atualizações futuras. Suprima este diagnóstico para continuar. @@ -13091,7 +13216,7 @@ Para incorporar informações de tipo de interoperabilidade para os dois assembl Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Não foi possível ler as informações de depuração do método "{0}" (token 0x{1:X8}) do assembly "{2}": {3} diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 4dd0867102ff0..2560a8e7dba16 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -222,6 +222,11 @@ Не удается использовать коллекцию динамического типа в асинхронном операторе foreach + + Extensions must be declared in a top-level, non-generic, static class + Extensions must be declared in a top-level, non-generic, static class + + The type '{0}' may not be used for a field of a record. Тип "{0}" не может быть использован для поля записи. @@ -373,8 +378,8 @@ - Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specifc numeric type. - Невозможно использовать числовую константу или реляционный шаблон для "{0}", поскольку он наследует от "INumberBase<T>" или расширяет его. Рассмотрите возможность использовать шаблон типа, чтобы указать конкретный числовой тип. + Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specific numeric type. + Невозможно использовать числовую константу или реляционный шаблон для "{0}", поскольку он наследует от "INumberBase<T>" или расширяет его. Рассмотрите возможность использовать шаблон типа, чтобы указать конкретный числовой тип. @@ -542,6 +547,11 @@ Конструктор копий "{0}" должен быть открытым или защищенным, так как запись не запечатана. + + Cannot emit this string literal into the data section because it has XXHash128 collision with another string literal: {0} + Cannot emit this string literal into the data section because it has XXHash128 collision with another string literal: {0} + + The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'. Имя "{0}" не соответствует указанному параметру "Deconstruct" "{1}". @@ -639,7 +649,7 @@ Cannot emit update; {0} '{1}' is missing. - Cannot emit update; {0} '{1}' is missing. + Не удается создать обновление; {0} '{1}' отсутствует. @@ -717,6 +727,11 @@ Дерево выражения не может содержать выражение коллекции. + + An expression tree may not contain an extension property access + An expression tree may not contain an extension property access + + An expression tree may not contain a from-end index ('^') expression. Дерево выражений не может содержать выражение индекса, отсчитываемого с конца ("^"). @@ -762,6 +777,26 @@ Дерево выражения не может содержать выражение with. + + Extension declarations can include only methods or properties + Extension declarations can include only methods or properties + + + + Extension declarations may not have a name. + Extension declarations may not have a name. + + + + The receiver parameter of an extension cannot have a default value + The receiver parameter of an extension cannot have a default value + + + + '{0}' does not contain a definition for '{1}' and no accessible extension member '{1}' for receiver of type '{0}' could be found (are you missing a using directive or an assembly reference?) + '{0}' does not contain a definition for '{1}' and no accessible extension member '{1}' for receiver of type '{0}' could be found (are you missing a using directive or an assembly reference?) + + '{0}': extern event cannot have initializer "{0}": внешнее событие не может иметь инициализатор @@ -1247,6 +1282,11 @@ Аргумент diagnosticId атрибута "Experimental" должен быть допустимым идентификатором + + Cannot use extension parameter '{0}' in this context. + Cannot use extension parameter '{0}' in this context. + + '{0}' is not a valid function pointer return type modifier. Valid modifiers are 'ref' and 'ref readonly'. "{0}" не является допустимым модификатором типа для возвращаемого значения указателя на функцию. Допустимые модификаторы: ref и ref readonly. @@ -1339,7 +1379,7 @@ Element type of an iterator may not be a ref struct or a type parameter allowing ref structs - Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + Тип элемента итератора не может быть структурой ссылок или параметром типа, разрешая структуры ссылок @@ -1387,6 +1427,16 @@ Шаблоны списка не могут использоваться для значения типа {0}. Подходящее свойство \"Length\" или \"Count\" не найдено. + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + + No overload for '{0}' matches function pointer '{1}' Нет перегруженного метода для "{0}", который соответствует указателю на функцию "{1}". @@ -1687,6 +1737,16 @@ Параметр params должен иметь допустимый тип коллекции. + + '{0}': only the implementing declaration of a partial constructor can have an initializer + '{0}': only the implementing declaration of a partial constructor can have an initializer + + + + '{0}': partial event cannot have initializer + '{0}': partial event cannot have initializer + + Both partial member declarations must have identical accessibility modifiers. У обоих объявлений частичного члена должны быть идентичные модификаторы доступа. @@ -1697,11 +1757,31 @@ У частичного члена не может быть модификатора "abstract" + + Partial member '{0}' may not have multiple defining declarations. + Partial member '{0}' may not have multiple defining declarations. + + + + Partial member '{0}' may not have multiple implementing declarations. + Partial member '{0}' may not have multiple implementing declarations. + + Both partial member declarations, '{0}' and '{1}', must use the same tuple element names. Оба определения частичного члена "{0}" и "{1}" должны использовать одинаковые имена элементов кортежа. + + Partial member '{0}' must have a definition part. + Partial member '{0}' must have a definition part. + + + + Partial member '{0}' must have an implementation part. + Partial member '{0}' must have an implementation part. + + A partial member must be declared within a partial type Частичный член должен быть объявлен из частичного типа @@ -1727,6 +1807,11 @@ У объявлений частичного члена должны совпадать возвращаемые значения "ref". + + Both partial member declarations must have the same type. + Both partial member declarations must have the same type. + + Both partial member declarations must be unsafe or neither may be unsafe Оба объявления частичного члена должны быть небезопасными или оба не должны быть небезопасными @@ -1797,11 +1882,6 @@ Оба объявления частичного члена должны быть обязательными или оба не должны быть обязательными - - Both partial property declarations must have the same type. - Оба объявления частичного свойства должны быть одинакового типа. - - Property accessor '{0}' does not implement any accessor declared on the definition part Метод доступа "{0}" не реализует методы доступа, объявленные для части определения @@ -1862,6 +1942,16 @@ "{0}": readonly можно использовать для методов доступа, только если свойство или индексатор имеет оба метода доступа, get и set. + + An extension container can have only one receiver parameter + An extension container can have only one receiver parameter + + + + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + + The primary constructor conflicts with the synthesized copy constructor. Первичный конструктор конфликтует с синтезированным конструктором копий. @@ -1884,7 +1974,7 @@ Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escape scopes than '{1}'. - Не удается присвоить по ссылке "{1}" "{0}", потому что "{1}" имеет более широкую область выхода, чем "{0}", что позволяет присваивать через "{0}" значения с более узкими областями выхода, чем "{1}". + Невозможно присвоить ссылку "{1}" на "{0}", так как "{1}" имеет более широкую область экранирования значения, чем "{0}", что позволяет назначать через "{0}" значения с более узкой областью экранирования, чем "{1}". @@ -2019,7 +2109,7 @@ The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. - The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + Тип "Microsoft.CodeAnalysis.EmbeddedAttribute" должен быть неуниверсанным, внутренним, запечатанным, нестатическим, иметь конструктор без параметров, наследовать от System.Attribute и иметь возможность применяться к любому типу. @@ -2272,6 +2362,16 @@ Тип "{0}" должен быть открытым для использования в качестве соглашения о вызовах. + + Type parameter '{0}' has the same name as an extension parameter + Type parameter '{0}' has the same name as an extension parameter + + + + Type parameter '{0}' has the same name as an extension container type parameter + Type parameter '{0}' has the same name as an extension container type parameter + + Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. Автоматически реализуемое свойство "{0}" должно быть полностью назначено перед возвратом контроля вызывающему элементу. Попробуйте обновить до языковой версии "{1}", чтобы автоматически применить значение по умолчанию к этому свойству. @@ -2282,6 +2382,11 @@ Поле '{0}' должно быть полностью назначенным перед возвратом контроля вызывающему элементу. Попробуйте обновить поле до языковой версии "{1}", чтобы автоматически применить значение по умолчанию. + + The extended type '{0}' must reference all the type parameters declared by the extension, but type parameter '{1}' is not referenced. + The extended type '{0}' must reference all the type parameters declared by the extension, but type parameter '{1}' is not referenced. + + Unexpected parameter list. Неожиданный список параметров. @@ -2372,6 +2477,16 @@ Нельзя использовать объект "this", пока не будут назначены все его поля. Попробуйте обновить до языковой версии "{0}", чтобы автоматически применить значения по умолчанию к неназначенным полям. + + 'value': an automatically-generated parameter name conflicts with an extension parameter name + 'value': an automatically-generated parameter name conflicts with an extension parameter name + + + + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + + In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. @@ -2442,6 +2557,11 @@ шаблоны расширенных свойств + + extensions + extensions + + field keyword ключевое слово поля @@ -2459,7 +2579,7 @@ first-class Span types - first-class Span types + типы диапазона первого класса @@ -2539,7 +2659,7 @@ overload resolution priority - overload resolution priority + приоритет разрешения перегрузки @@ -2552,6 +2672,11 @@ коллекции params + + partial events and constructors + partial events and constructors + + positional fields in records позиционные поля в записях @@ -2624,7 +2749,7 @@ unbound generic types in nameof operator - unbound generic types in nameof operator + не привязанные универсальные типы в операторе nameof @@ -2714,12 +2839,12 @@ The '{0}' accessor of property '{1}' should use 'field' because the other accessor is using it. - The '{0}' accessor of property '{1}' should use 'field' because the other accessor is using it. + Метод '{0}' доступа к '{1}' должен использовать "field", так как он используется другим методом доступа. Property accessor should use 'field' because the other accessor is using it. - Property accessor should use 'field' because the other accessor is using it. + Метод доступа к свойству должен использовать "field", так как он используется другим методом доступа. @@ -2743,13 +2868,13 @@ - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - Сборка анализатора "{0}" ссылается на версию "{1}" компилятора, являющуюся более новой, чем версия "{2}". + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + Сборка анализатора "{0}" ссылается на версию "{1}" компилятора, являющуюся более новой, чем версия "{2}". - The analyzer assembly references a newer version of the compiler than the currently running version. - Сборка анализатора ссылается на более новую версию компилятора, чем установленная сейчас. + Analyzer assembly cannot be used because it references a newer version of the compiler than the currently running version. + Сборка анализатора ссылается на более новую версию компилятора, чем установленная сейчас. @@ -2994,12 +3119,12 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + "{0}" предназначен только для оценки и может быть изменен или удален в будущих обновлениях: "{1}". Чтобы продолжить, скройте эту диагностику. Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + Тип предназначен только для оценки и может быть изменен или удален в будущих обновлениях. Чтобы продолжить, скройте эту диагностику. @@ -3074,12 +3199,12 @@ 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) - 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + Атрибут InterceptsLocationAttribute(string, int, int)" не поддерживается. Вместо этого перейдите в поколение этих атрибутов на основе InterceptableLocation. (https://github.com/dotnet/roslyn/issues/72133) 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) - 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + Атрибут InterceptsLocationAttribute(string, int, int)" не поддерживается. Вместо этого перейдите в поколение этих атрибутов на основе InterceptableLocation. (https://github.com/dotnet/roslyn/issues/72133) @@ -3212,14 +3337,14 @@ У параметра есть модификатор params в лямбде, но не в типе целевого делегата. - - Partial property declarations '{0}' and '{1}' have signature differences. - У объявлений частичного свойства "{0}" и "{1}" разные сигнатуры. + + Partial member declarations '{0}' and '{1}' have signature differences. + Partial member declarations '{0}' and '{1}' have signature differences. - - Partial property declarations have signature differences. - У объявлений частичного свойств и разные сигнатуры. + + Partial member declarations have signature differences. + Partial member declarations have signature differences. @@ -3289,7 +3414,7 @@ This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escape scopes than '{1}'. - Это присваивает по ссылке "{1}" "{0}", но "{1}" имеет более широкую область выхода, чем "{0}", что позволяет присваивать через "{0}" значения с более узкими областями выхода, чем "{1}". + Эта ссылка присваивает "{1}" значение "{0}", но "{1}" имеет более широкую область действия значения, чем "{0}", позволяя назначать через "{0}" значения с более узкой областью действия, чем "{1}". @@ -3718,164 +3843,164 @@ accessibility errors with what assembly they came from. - Параметры компилятора Visual C# + Параметры компилятора Visual C# - - ВЫХОДНЫЕ ФАЙЛЫ - --out:<file> Укажите имя выходного файла (по умолчанию: базовое имя - файл с основным классом или первый файл) --target:exe Создать исполняемый файл консоли (по умолчанию) (сокращение - форма: -t:exe) --target:winexe Создать исполняемый файл Windows (краткая форма: - -t:winexe) --target:library Создать библиотеку (краткая форма: -t:library) --target:module Создать модуль, который можно добавить к другому - сборка (краткая форма: -t:модуль) --target:appcontainerexe Создать исполняемый файл Appcontainer (краткая форма: - -t:appcontainerexe) --target:winmdobj Создать промежуточный файл среды выполнения Windows, который - потребляется WinMDExp (краткая форма: -t:winmdobj) --doc:<file> Файл XML-документации для создания --refout:<file> Ссылка на выходные данные сборки для создания --platform:<string> Ограничить платформы, на которых может работать этот код: x86, - Itanium, x64, arm, arm64, anycpu32bitpreferred или - любой процессор. По умолчанию используется любой процессор. + - ВЫХОДНЫЕ ФАЙЛЫ - +-out:<file> Укажите имя выходного файла (по умолчанию: базовое имя + файл с основным классом или первый файл) +-target:exe Создать исполняемый файл консоли (по умолчанию) (сокращение + форма: -t:exe) +-target:winexe Создать исполняемый файл Windows (краткая форма: + -t:winexe) +-target:library Создать библиотеку (краткая форма: -t:library) +-target:module Создать модуль, который можно добавить к другому + сборка (краткая форма: -t:модуль) +-target:appcontainerexe Создать исполняемый файл Appcontainer (краткая форма: + -t:appcontainerexe) +-target:winmdobj Создать промежуточный файл среды выполнения Windows, который + потребляется WinMDExp (краткая форма: -t:winmdobj) +-doc:<file> Файл XML-документации для создания +-refout:<file> Ссылка на выходные данные сборки для создания +-platform:<string> Ограничить платформы, на которых может работать этот код: x86, + Itanium, x64, arm, arm64, anycpu32bitpreferred или + любой процессор. По умолчанию используется любой процессор. - - ВХОДНЫЕ ФАЙЛЫ - ---recurse:<wildcard> Включить все файлы в текущем каталоге и - подкаталогах в соответствии с подстановочными - знаками --reference:<alias>=<file> Ссылка на метаданные из указанного файла сборки - с использованием заданного псевдонима (краткая форма: -r) --reference:<file list> Ссылочные метаданные из указанных файлов + - ВХОДНЫЕ ФАЙЛЫ - +--recurse:<wildcard> Включить все файлы в текущем каталоге и + подкаталогах в соответствии с подстановочными + знаками +-reference:<alias>=<file> Ссылка на метаданные из указанного файла сборки + с использованием заданного псевдонима (краткая форма: -r) +-reference:<file list> Ссылочные метаданные из указанных файлов сборки (краткая форма: -r) --addmodule:<file list> Связать указанные модули с этой сборкой --link:<file list> Внедрить метаданные из указанных файлов - сборки взаимодействия (краткая форма: -l) --analyzer:<file list> Запустить анализаторы из этой сборки - (Краткая форма: -а) --additionalfile:<file list> Дополнительные файлы, не влияющие напрямую на генерацию +-addmodule:<file list> Связать указанные модули с этой сборкой +-link:<file list> Внедрить метаданные из указанных файлов + сборки взаимодействия (краткая форма: -l) +-analyzer:<file list> Запустить анализаторы из этой сборки + (Краткая форма: -а) +-additionalfile:<file list> Дополнительные файлы, не влияющие напрямую на генерацию кода, но которые могут использоваться анализаторами для создания ошибок и предупреждений. --embed Встроить все исходные файлы в PDB. --embed:<file list> Встроить определенные файлы в PDB. +-embed Встроить все исходные файлы в PDB. +-embed:<file list> Встроить определенные файлы в PDB. - - РЕСУРСЫ - --win32res:<file> Укажите файл ресурсов Win32 (.res) --win32icon:<file> Использовать этот значок для вывода --win32manifest:<file> Укажите файл манифеста Win32 (.xml) --nowin32manifest Не включать манифест Win32 по умолчанию --resource:<resinfo> Встроить указанный ресурс (краткая форма: -res) --linkresource:<resinfo> Связать указанный ресурс с этой сборкой + - РЕСУРСЫ - +-win32res:<file> Укажите файл ресурсов Win32 (.res) +-win32icon:<file> Использовать этот значок для вывода +-win32manifest:<file> Укажите файл манифеста Win32 (.xml) +-nowin32manifest Не включать манифест Win32 по умолчанию +-resource:<resinfo> Встроить указанный ресурс (краткая форма: -res) +-linkresource:<resinfo> Связать указанный ресурс с этой сборкой (Короткая форма: -linkres) Где формат resinfo - равен <file>[,<string name>[,public|private]] + равен <file>[,<string name>[,public|private]] - - ГЕНЕРАЦИЯ КОДА - --debug[+|-] Выдать отладочную информацию + - ГЕНЕРАЦИЯ КОДА - +-debug[+|-] Выдать отладочную информацию -debug:{full|pdbonly|portable|embedded} - Укажите тип отладки («полный» по умолчанию, - «портативный» — это кроссплатформенный формат, - 'встроенный' – это кроссплатформенный формат, встроенный в - целевой файл .dll или .exe) --optimize[+|-] Включить оптимизацию (краткая форма: -o) --optimize[+|-] Производство детерминированной сборки - (включая GUID версии модуля и метку времени) --refonly Изготовить эталонную сборку вместо основной продукции --instrument:TestCoverage Создать сборку, предназначенную для сбора + Укажите тип отладки («полный» по умолчанию, + «портативный» — это кроссплатформенный формат, + 'встроенный' – это кроссплатформенный формат, встроенный в + целевой файл .dll или .exe) +-optimize[+|-] Включить оптимизацию (краткая форма: -o) +-optimize[+|-] Производство детерминированной сборки + (включая GUID версии модуля и метку времени) +-refonly Изготовить эталонную сборку вместо основной продукции +-instrument:TestCoverage Создать сборку, предназначенную для сбора сведений об охвате --sourcelink:<file> Информация об исходной ссылке для встраивания в PDB. +-sourcelink:<file> Информация об исходной ссылке для встраивания в PDB. - - ОШИБКИ И ПРЕДУПРЕЖДЕНИЯ - --warnaserror[+|-] Сообщить обо всех предупреждениях как об ошибках --warnaserror[+|-]:<warn list> Сообщать об определенных предупреждениях как об ошибках - (используйте "nullable" для всех предупреждений об отсутствии значений) --warn:<n> Установить уровень предупреждения (0 или выше) (краткая форма: -w) --nowarn:<warn list> Отключить определенные предупреждающие сообщения - (используйте "nullable" для всех предупреждений об отсутствии значений) --ruleset:<file> Укажите файл набора правил, который отключает определенную - диагностики. --errorlog:<file>[,version=<sarif_version>] - Укажите файл для регистрации всего компилятора и анализатора - диагностики. - sarif_version:{1|2|2.1} По умолчанию 1. 2 и 2.1 - оба означают SARIF версии 2.1.0. --reportanalyzer Сообщать дополнительную информацию об анализаторе, такую как + - ОШИБКИ И ПРЕДУПРЕЖДЕНИЯ - +-warnaserror[+|-] Сообщить обо всех предупреждениях как об ошибках +-warnaserror[+|-]:<warn list> Сообщать об определенных предупреждениях как об ошибках + (используйте "nullable" для всех предупреждений об отсутствии значений) +-warn:<n> Установить уровень предупреждения (0 или выше) (краткая форма: -w) +-nowarn:<warn list> Отключить определенные предупреждающие сообщения + (используйте "nullable" для всех предупреждений об отсутствии значений) +-ruleset:<file> Укажите файл набора правил, который отключает определенную + диагностики. +-errorlog:<file>[,version=<sarif_version>] + Укажите файл для регистрации всего компилятора и анализатора + диагностики. + sarif_version:{1|2|2.1} По умолчанию 1. 2 и 2.1 + оба означают SARIF версии 2.1.0. +-reportanalyzer Сообщать дополнительную информацию об анализаторе, такую как время выполнения. --skipanalyzers[+|-] Пропустить выполнение диагностических анализаторов. +-skipanalyzers[+|-] Пропустить выполнение диагностических анализаторов. - - ЯЗЫК - --checked[+|-] Генерировать проверки переполнения --unsafe[+|-] Разрешить «небезопасный» код --define:<symbol list> Определить символ(ы) условной компиляции (краткая + - ЯЗЫК - +-checked[+|-] Генерировать проверки переполнения +-unsafe[+|-] Разрешить «небезопасный» код +-define:<symbol list> Определить символ(ы) условной компиляции (краткая форма: -d) --langversion:? Показать допустимые значения для языковой версии --langversion:<string> Укажите языковую версию, например - `latest` (последняя версия, включая дополнительные версии), - `default` (то же, что и `последняя`), - `latestmajor` (последняя версия, исключая дополнительные версии), - `preview` (последняя версия, включая функции в неподдерживаемой предварительной версии), - или специальные версии, такие как «6» или «7.1» --nullable[+|-] Указать параметр контекста, допускающий значение null, enable|disable. +-langversion:? Показать допустимые значения для языковой версии +-langversion:<string> Укажите языковую версию, например + `latest` (последняя версия, включая дополнительные версии), + `default` (то же, что и `последняя`), + `latestmajor` (последняя версия, исключая дополнительные версии), + `preview` (последняя версия, включая функции в неподдерживаемой предварительной версии), + или специальные версии, такие как «6» или «7.1» +-nullable[+|-] Указать параметр контекста, допускающий значение null, enable|disable. -nullable:{enable|disable|warnings|annotations} Укажите параметр контекста, допускающий значение NULL, enable|disable|warnings|annotations. - - БЕЗОПАСНОСТЬ - --delaysign[+|-] Отложить подписание сборки, используя только открытый - части ключа строгого имени --publicsign[+|-] Общедоступная подпись сборки с использованием только общедоступной - части ключа строгого имени --keyfile:<file> Укажите файл ключа со строгим именем --keycontainer:<string> Укажите контейнер ключей строгого имени --highentropyva[+|-] Включить высокоэнтропийный ASLR + - БЕЗОПАСНОСТЬ - +-delaysign[+|-] Отложить подписание сборки, используя только открытый + части ключа строгого имени +-publicsign[+|-] Общедоступная подпись сборки с использованием только общедоступной + части ключа строгого имени +-keyfile:<file> Укажите файл ключа со строгим именем +-keycontainer:<string> Укажите контейнер ключей строгого имени +-highentropyva[+|-] Включить высокоэнтропийный ASLR - - РАЗНОЕ - -@<file> Прочтите файл ответов, чтобы узнать о дополнительных параметрах --help Показать это сообщение об использовании (краткая форма: -?) --nologo Подавить сообщение об авторских правах компилятора --nologo Не включать автоматически файл CSC.RSP --parallel[+|-] Параллельная сборка. --version Показать номер версии компилятора и выйти. + - РАЗНОЕ - +@<file> Прочтите файл ответов, чтобы узнать о дополнительных параметрах +-help Показать это сообщение об использовании (краткая форма: -?) +-nologo Подавить сообщение об авторских правах компилятора +-nologo Не включать автоматически файл CSC.RSP +-parallel[+|-] Параллельная сборка. +-version Показать номер версии компилятора и выйти. - - РАСШИРЕННЫЙ - --baseaddress:<address> Базовый адрес для создаваемой библиотеки + - РАСШИРЕННЫЙ - +-baseaddress:<address> Базовый адрес для создаваемой библиотеки -checksumalgorithm:<alg> Указать алгоритм вычисления контрольной суммы исходного файла, - хранящегося в PDB. Поддерживаемые значения: - SHA1 или SHA256 (по умолчанию). --codepage:<n> Укажите кодовую страницу для использования при открытии исходных - файлов --utf8output Выводить сообщения компилятора в кодировке UTF-8 --main:<type> Укажите тип, который содержит точку входа - (игнорировать все другие возможные точки входа) (короткая - форма: -m) --fullpaths Компилятор создает полные пути --filealign:<n> Укажите выравнивание, используемое для разделов - выходного файла --pathmap:<K1>=<V1>,<K2>=<V2>,... - Укажите сопоставление для имен исходных путей, выводимых с помощью + хранящегося в PDB. Поддерживаемые значения: + SHA1 или SHA256 (по умолчанию). +-codepage:<n> Укажите кодовую страницу для использования при открытии исходных + файлов +-utf8output Выводить сообщения компилятора в кодировке UTF-8 +-main:<type> Укажите тип, который содержит точку входа + (игнорировать все другие возможные точки входа) (короткая + форма: -m) +-fullpaths Компилятор создает полные пути +-filealign:<n> Укажите выравнивание, используемое для разделов + выходного файла +-pathmap:<K1>=<V1>,<K2>=<V2>,... + Укажите сопоставление для имен исходных путей, выводимых с помощью . - компилятора. --pdb:<file> Указать имя файла отладочной информации (по умолчанию: - имя выходного файла с расширением .pdb) --errorendlocation Строка вывода и столбец конечного местоположения + компилятора. +-pdb:<file> Указать имя файла отладочной информации (по умолчанию: + имя выходного файла с расширением .pdb) +-errorendlocation Строка вывода и столбец конечного местоположения каждой ошибки --preferreduilang Укажите предпочтительное имя языка вывода. --nosdkpath Отключить поиск стандартных библиотечных сборок по пути SDK по умолчанию. --nostdlib[+|-] Не ссылаться на стандартную библиотеку (mscorlib.dll) --subsystemversion:<string> Укажите версию подсистемы этой сборки --lib:<file list> Указать дополнительные каталоги для поиска - ссылок --errorreport:<string> Укажите, как обрабатывать внутренние ошибки компилятора: +-preferreduilang Укажите предпочтительное имя языка вывода. +-nosdkpath Отключить поиск стандартных библиотечных сборок по пути SDK по умолчанию. +-nostdlib[+|-] Не ссылаться на стандартную библиотеку (mscorlib.dll) +-subsystemversion:<string> Укажите версию подсистемы этой сборки +-lib:<file list> Указать дополнительные каталоги для поиска + ссылок +-errorreport:<string> Укажите, как обрабатывать внутренние ошибки компилятора: запросить, отправить, поставить в очередь или никаких действий. Значение по умолчанию - очередь. --appconfig:<file> Указать файл конфигурации приложения - содержащий параметры привязки сборки --moduleassemblyname:<string> Название сборки, частью которой будет - этот модуль --modulename:<string> Укажите имя исходного модуля --generatedfilesout:<dir> Поместить файлы, сгенерированные во время компиляции, в - указанный каталог. --reportivts[+|-] Вывести информацию обо всех IVT, предоставленных этой - сборке по всем зависимостям и аннотировать ошибки доступности - сторонних сборок с указанием того, из какой сборки они произошли.. + очередь. +-appconfig:<file> Указать файл конфигурации приложения + содержащий параметры привязки сборки +-moduleassemblyname:<string> Название сборки, частью которой будет + этот модуль +-modulename:<string> Укажите имя исходного модуля +-generatedfilesout:<dir> Поместить файлы, сгенерированные во время компиляции, в + указанный каталог. +-reportivts[+|-] Вывести информацию обо всех IVT, предоставленных этой + сборке по всем зависимостям и аннотировать ошибки доступности + сторонних сборок с указанием того, из какой сборки они произошли.. Visual C# Compiler Options @@ -5301,12 +5426,12 @@ Field '{0}' is never ref-assigned to, and will always have its default value (null reference) - Field '{0}' is never ref-assigned to, and will always have its default value (null reference) + Поле "{0}" никогда не имеет ссылки и всегда будет иметь значение по умолчанию (нулевая ссылка) Field is never ref-assigned to, and will always have its default value (null reference) - Field is never ref-assigned to, and will always have its default value (null reference) + Поле не содержит ссылки и всегда будет иметь значение по умолчанию (нулевая ссылка) @@ -5380,12 +5505,12 @@ - Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or safely handling the case where 'field' is null in the 'get' accessor. {0} "{1}", не допускающий значения NULL, должен содержать значение, отличное от NULL, при выходе из конструктора. Рассмотрите возможность добавить модификатор "required", объявить {0} как допускающее значение NULL или добавить атрибуты "[field: MaybeNull, AllowNull]". Similar diagnostic message as 'WRN_UninitializedNonNullableField' - Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. Свойство, не допускающее значения NULL, должно содержать значение, отличное от NULL, при выходе из конструктора. Рассмотрите возможность добавить модификатор "required", объявить свойство как допускающее значение NULL или добавить атрибуты "[field: MaybeNull, AllowNull]". @@ -5421,12 +5546,12 @@ UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. - UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute допустим только в C# 11 или более поздней версии или при нацелии на net7.0 или более позднюю версию. UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. - UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute допустим только в C# 11 или более поздней версии или при нацелии на net7.0 или более позднюю версию. @@ -6730,8 +6855,8 @@ - The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. - Модификатор "partial" может использоваться только перед ключевыми словами "class", "record", "struct" и "interface", а также перед возвращаемым типом метода или свойства. + The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. + Модификатор "partial" может использоваться только перед ключевыми словами "class", "record", "struct" и "interface", а также перед возвращаемым типом метода или свойства. @@ -8833,8 +8958,8 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep - Cannot define a new extension method because the compiler required type '{0}' cannot be found. Are you missing a reference to System.Core.dll? - Не удается определить новый метод расширения, так как не найден требуемый компилятором тип "{0}". Возможно, отсутствует ссылка на System.Core.dll + Cannot define a new extension because the compiler required type '{0}' cannot be found. Are you missing a reference to System.Core.dll? + Не удается определить новый метод расширения, так как не найден требуемый компилятором тип "{0}". Возможно, отсутствует ссылка на System.Core.dll @@ -8928,8 +9053,8 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep - Invalid token '{0}' in class, record, struct, or interface member declaration - Недопустимый токен "{0}" в объявлении класса, записи, структуры или элемента интерфейса + Invalid token '{0}' in a member declaration + Недопустимый токен "{0}" в объявлении класса, записи, структуры или элемента интерфейса @@ -10377,7 +10502,7 @@ Give the compiler some way to differentiate the methods. For example, you can gi Cannot open '{0}' for writing -- {1} - Не удается открыть "{0}" для записи — "{1}". + Не удается открыть "{0}" для записи — {1} @@ -12742,7 +12867,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string literals or try the EXPERIMENTAL feature flag 'experimental-data-section-string-literals'. - Общая длина пользовательских строк, используемых программой, превышает допустимый предел. Попробуйте сократить использование строковых литералов. + Объединенная длина пользовательских строк, используемых программой, превышает допустимый предел. Попробуйте уменьшить использование строковых литералов или попробуйте ЭКСПЕРИМЕНТАЛЬНЫЙ флаг функции "experimental-data-section-string-literals". @@ -13037,7 +13162,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + "{0}" предназначен только для оценки и может быть изменен или удален в будущих обновлениях. Чтобы продолжить, скройте эту диагностику. @@ -13092,7 +13217,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Не удается прочитать отладочную информацию метода "{0}"' (токен 0x{1:X8}) из сборки "{2}": {3} diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 119a36a92f6ef..ba1a21169d1da 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -222,6 +222,11 @@ Zaman uyumsuz bir foreach içinde dinamik tür koleksiyonu oluşturulamaz + + Extensions must be declared in a top-level, non-generic, static class + Extensions must be declared in a top-level, non-generic, static class + + The type '{0}' may not be used for a field of a record. '{0}' türü, kayıt alanı için kullanılamaz. @@ -373,8 +378,8 @@ - Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specifc numeric type. - 'INumberBase<T>' öğesinden devraldığı veya genişlediği için '{0}' öğesinde sayısal bir sabit veya ilişkisel desen kullanılamaz. Belirli bir sayısal türe daraltmak için bir tür deseni kullanmayı düşünün. + Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specific numeric type. + 'INumberBase<T>' öğesinden devraldığı veya genişlediği için '{0}' öğesinde sayısal bir sabit veya ilişkisel desen kullanılamaz. Belirli bir sayısal türe daraltmak için bir tür deseni kullanmayı düşünün. @@ -542,6 +547,11 @@ Kayıt mühürlü olmadığından, '{0}' kopya oluşturucusu genel veya korumalı olmalıdır. + + Cannot emit this string literal into the data section because it has XXHash128 collision with another string literal: {0} + Cannot emit this string literal into the data section because it has XXHash128 collision with another string literal: {0} + + The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'. '{0}' adı ilgili '{1}' 'Deconstruct' parametresiyle eşleşmiyor. @@ -639,7 +649,7 @@ Cannot emit update; {0} '{1}' is missing. - Cannot emit update; {0} '{1}' is missing. + Güncelleştirme gönderilemiyor; {0} '{1}' eksik. @@ -717,6 +727,11 @@ İfade ağacı bir koleksiyon ifadesi içermeyebilir. + + An expression tree may not contain an extension property access + An expression tree may not contain an extension property access + + An expression tree may not contain a from-end index ('^') expression. İfade ağacı, sondan dizin ('^') ifadesi içeremez. @@ -762,6 +777,26 @@ İfade ağacı, with ifadesi içeremez. + + Extension declarations can include only methods or properties + Extension declarations can include only methods or properties + + + + Extension declarations may not have a name. + Extension declarations may not have a name. + + + + The receiver parameter of an extension cannot have a default value + The receiver parameter of an extension cannot have a default value + + + + '{0}' does not contain a definition for '{1}' and no accessible extension member '{1}' for receiver of type '{0}' could be found (are you missing a using directive or an assembly reference?) + '{0}' does not contain a definition for '{1}' and no accessible extension member '{1}' for receiver of type '{0}' could be found (are you missing a using directive or an assembly reference?) + + '{0}': extern event cannot have initializer '{0}': dış etkinliğin başlatıcısı olamaz @@ -1247,6 +1282,11 @@ 'Experimental' özniteliğinin diagnosticId bağımsız değişkeni geçerli bir tanımlayıcı olmalıdır + + Cannot use extension parameter '{0}' in this context. + Cannot use extension parameter '{0}' in this context. + + '{0}' is not a valid function pointer return type modifier. Valid modifiers are 'ref' and 'ref readonly'. '{0}', geçerli bir işlev işaretçisi dönüş türü değiştiricisi değil. Geçerli değiştiriciler: 'ref' ve 'ref readonly'. @@ -1339,7 +1379,7 @@ Element type of an iterator may not be a ref struct or a type parameter allowing ref structs - Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + Bir iterator öğesinin öğe türü bir başvuru yapısı veya başvuru yapı birimlerine izin veren bir tür parametresi olamaz @@ -1387,6 +1427,16 @@ Liste desenleri, '{0}' türündeki bir değer için kullanılamaz. Uygun 'Length' veya 'Count' özelliği bulunamadı. + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + + No overload for '{0}' matches function pointer '{1}' '{0}' için aşırı yüklemelerin hiçbiri '{1}' işlev işaretçisiyle eşleşmiyor @@ -1687,6 +1737,16 @@ Params parametresi geçerli bir koleksiyon türüne sahip olmalıdır + + '{0}': only the implementing declaration of a partial constructor can have an initializer + '{0}': only the implementing declaration of a partial constructor can have an initializer + + + + '{0}': partial event cannot have initializer + '{0}': partial event cannot have initializer + + Both partial member declarations must have identical accessibility modifiers. Kısmi üye bildirimlerinin ikisi de aynı erişilebilirlik değiştiricilerine sahip olmalıdır. @@ -1697,11 +1757,31 @@ Kısmi üyede 'abstract' değiştiricisi olamaz + + Partial member '{0}' may not have multiple defining declarations. + Partial member '{0}' may not have multiple defining declarations. + + + + Partial member '{0}' may not have multiple implementing declarations. + Partial member '{0}' may not have multiple implementing declarations. + + Both partial member declarations, '{0}' and '{1}', must use the same tuple element names. Kısmi üye bildirimlerinin ikisi de ('{0}' ve '{1}') aynı tanımlama grubu adını kullanmalıdır. + + Partial member '{0}' must have a definition part. + Partial member '{0}' must have a definition part. + + + + Partial member '{0}' must have an implementation part. + Partial member '{0}' must have an implementation part. + + A partial member must be declared within a partial type Kısmi metot, kısmi tür içinde bildirilmelidir @@ -1727,6 +1807,11 @@ Kısmi üye bildirimlerinde eşleşen başvuru dönüş değerleri olmalıdır. + + Both partial member declarations must have the same type. + Both partial member declarations must have the same type. + + Both partial member declarations must be unsafe or neither may be unsafe Kısmi üye bildirimlerinin ikisi de güvensiz olmalı veya hiçbiri güvensiz olmamalıdır @@ -1797,11 +1882,6 @@ Kısmi özellik bildirimlerinin ikisi de gerekli olmalı veya hiçbiri gerekli olmamalıdır - - Both partial property declarations must have the same type. - Kısmi özellik bildirimlerini ikisi de aynı dönüş türüne sahip olmalıdır. - - Property accessor '{0}' does not implement any accessor declared on the definition part '{0}' özellik erişimcisi, tanım bölümünde bildirilen hiçbir erişimciyi uygulamaz @@ -1862,6 +1942,16 @@ '{0}': 'readonly' erişimcilerde yalnızca özellik veya dizin oluşturucusu hem alma hem ayarlama erişimcisine sahipse kullanılabilir + + An extension container can have only one receiver parameter + An extension container can have only one receiver parameter + + + + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + + The primary constructor conflicts with the synthesized copy constructor. Birincil oluşturucu, sentezlenmiş kopya oluşturucusuyla çakışıyor. @@ -1884,7 +1974,7 @@ Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escape scopes than '{1}'. - '{1}' başvuru değeri, '{0}' olarak atanamaz çünkü '{1}' değeri '{0}' değerinden daha geniş bir değer kaçış kapsamına sahip olduğundan '{1}' değerinden daha dar kaçış kapsamlarına sahip '{0}' değeri üzerinden atamaya izin verir. + '{1}' değeri '{0}' değerinden daha geniş bir değer kaçış kapsamına sahip olduğundan '{1}' değerinden daha dar kaçış kapsamlarına sahip '{0}' değeri üzerinden atamaya izin verdiği için '{1}' başvuru değeri, '{0}' olarak atanamaz. @@ -2019,7 +2109,7 @@ The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. - The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + 'Microsoft.CodeAnalysis.EmbeddedAttribute' türü genel olmayan, iç, korumalı, statik olmayan, parametresiz bir oluşturucuya sahip, System.Attribute'tan devralınmalıdır ve herhangi bir türe uygulanmalıdır. @@ -2272,6 +2362,16 @@ '{0}' türünün bir çağırma kuralı olarak kullanılabilmesi için genel olması gerekir. + + Type parameter '{0}' has the same name as an extension parameter + Type parameter '{0}' has the same name as an extension parameter + + + + Type parameter '{0}' has the same name as an extension container type parameter + Type parameter '{0}' has the same name as an extension container type parameter + + Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. Denetim çağırana döndürülmeden önce otomatik uygulanan '{0}' özelliği tam olarak atanmalıdır. Özelliği otomatik olarak varsayılan durumuna getirmek için '{1}' dil sürümüne güncelleştirmeyi düşünün. @@ -2282,6 +2382,11 @@ Denetim çağırana döndürülmeden önce '{0}' alanı tam olarak atanmalıdır. Alanı otomatik olarak varsayılan durumuna getirmek için '{1}' dil sürümüne güncelleştirmeyi düşünün. + + The extended type '{0}' must reference all the type parameters declared by the extension, but type parameter '{1}' is not referenced. + The extended type '{0}' must reference all the type parameters declared by the extension, but type parameter '{1}' is not referenced. + + Unexpected parameter list. Beklenmeyen parametre listesi. @@ -2372,6 +2477,16 @@ 'this' nesnesi, tüm alanları atanmadan önce kullanılamaz. Atanmamış alanları otomatik olarak varsayılan durumuna getirmek için '{0}' dil sürümüne güncelleştirmeyi düşünün. + + 'value': an automatically-generated parameter name conflicts with an extension parameter name + 'value': an automatically-generated parameter name conflicts with an extension parameter name + + + + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + + In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. @@ -2442,6 +2557,11 @@ genişletilmiş özellik desenleri + + extensions + extensions + + field keyword alan anahtar sözcüğü @@ -2459,7 +2579,7 @@ first-class Span types - first-class Span types + birinci sınıf Yayılma türleri @@ -2539,7 +2659,7 @@ overload resolution priority - overload resolution priority + aşırı yükleme çözümlemesi önceliği @@ -2552,6 +2672,11 @@ params koleksiyonları + + partial events and constructors + partial events and constructors + + positional fields in records kayıtlardaki konumsal alanlar @@ -2624,7 +2749,7 @@ unbound generic types in nameof operator - unbound generic types in nameof operator + nameof işlecindeki bağlı olmayan genel türler @@ -2714,12 +2839,12 @@ The '{0}' accessor of property '{1}' should use 'field' because the other accessor is using it. - The '{0}' accessor of property '{1}' should use 'field' because the other accessor is using it. + Diğer '{0}' erişimci tarafından '{1}' için özellik erişimcisi 'field' kullanamıyor. Property accessor should use 'field' because the other accessor is using it. - Property accessor should use 'field' because the other accessor is using it. + Diğer erişimci tarafından kullanılıyor olduğundan özellik erişimcisi 'field' kullanamıyor. @@ -2743,13 +2868,13 @@ - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - '{0}' çözümleyici bütünleştirilmiş kodu, derleyicinin şu anda çalışan '{2}' sürümünden daha yeni olan '{1}' sürümüne başvurur. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + '{0}' çözümleyici bütünleştirilmiş kodu, derleyicinin şu anda çalışan '{2}' sürümünden daha yeni olan '{1}' sürümüne başvurur. - The analyzer assembly references a newer version of the compiler than the currently running version. - Çözümleyici bütünleştirilmiş kodu, derleyicinin şu anda çalışandan daha yeni bir sürümüne başvurur. + Analyzer assembly cannot be used because it references a newer version of the compiler than the currently running version. + Çözümleyici bütünleştirilmiş kodu, derleyicinin şu anda çalışandan daha yeni bir sürümüne başvurur. @@ -2994,12 +3119,12 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + '{0}' yalnızca değerlendirme amaçlıdır ve gelecekteki güncelleştirmelerde değiştirilebilir veya kaldırılabilir: '{1}'. Devam etmek için bu tanılamayı durdurun. Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + Tür, yalnızca değerlendirme amaçlıdır ve gelecekteki güncelleştirmelerde değiştirilebilir veya kaldırılabilir. Devam etmek için bu tanılamayı gizleyin. @@ -3074,12 +3199,12 @@ 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) - 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' desteklenmiyor. Bunun yerine bu özniteliklerin 'InterceptableLocation' tabanlı nesline gidin. (https://github.com/dotnet/roslyn/issues/72133) 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) - 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' desteklenmiyor. Bunun yerine bu özniteliklerin 'InterceptableLocation' tabanlı nesline gidin. (https://github.com/dotnet/roslyn/issues/72133) @@ -3212,14 +3337,14 @@ Parametre, lambda içinde parametre değiştiricisi içeriyor ancak hedef temsilci türünde içermiyor. - - Partial property declarations '{0}' and '{1}' have signature differences. - '{0}' ve '{1}' kısmi özellik bildirimlerinde imza farklılıkları var. + + Partial member declarations '{0}' and '{1}' have signature differences. + Partial member declarations '{0}' and '{1}' have signature differences. - - Partial property declarations have signature differences. - Kısmi özellik bildirimlerinde imza farklılıkları var. + + Partial member declarations have signature differences. + Partial member declarations have signature differences. @@ -3784,7 +3909,7 @@ bir derleme üretir -sourcelink:<file> PDB dosyasına eklenecek kaynak bağlantısı bilgileri. - - HATALAR VE UYARILAR - + - HATALAR VE UYARILAR - -warnaserror[+|-] Tüm uyarıları hata olarak bildirir. -warnaserror[+|-]:<warn list> Belirli uyarıları hata olarak bildirir (tüm null atanabilirlik uyarıları için "nullable" kullanın) @@ -3802,7 +3927,7 @@ raporlar. -skipanalyzers[+|-] Tanılama çözümleyicilerinin yürütülmesini atlar. - - DİL - + - DİL - -checked[+|-] Taşma denetimleri oluştur -unsafe[+|-] 'Güvenli olmayan' koda izin ver -define:<symbol list> Koşullu derleme sembollerini tanımlar (Kısa @@ -3827,7 +3952,7 @@ -keycontainer:<string> Tanımlayıcı ad anahtarı kapsayıcısını belirtir. -highentropyva[+|-] Yüksek entropili ASLR’yi etkinleştirir. - - DİĞER - + - DİĞER - @<file> Daha fazla seçenek için yanıt dosyasını okur -help Bu kullanım iletisini görüntüler (Kısa biçimi: -?) -nologo Derleyici telif hakkı iletisini gizler @@ -3835,7 +3960,7 @@ -parallel[+|-] Eş zamanlı derleme. -version Derleyici sürüm numarasını görüntüler ve çıkar. - - GELİŞMİŞ - + - GELİŞMİŞ - -baseaddress:<address> Oluşturulacak kitaplığın temel adresi -checksumalgorithm:<alg> PDB’de depolanan sağlama toplamı kaynak dosyasını hesaplamak için kullanılan algoritmayı belirtir. Desteklenen değerler şunlardır: @@ -5300,12 +5425,12 @@ Field '{0}' is never ref-assigned to, and will always have its default value (null reference) - Field '{0}' is never ref-assigned to, and will always have its default value (null reference) + '{0}' alanı hiçbir zaman başvuru olarak atanmaz ve her zaman kendi varsayılan değerini alır (boş başvuru) Field is never ref-assigned to, and will always have its default value (null reference) - Field is never ref-assigned to, and will always have its default value (null reference) + Alan hiçbir zaman başvuru olarak atanmaz ve her zaman kendi varsayılan değerini alır (boş başvuru) @@ -5379,12 +5504,12 @@ - Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or safely handling the case where 'field' is null in the 'get' accessor. Null atanamaz {0} '{1}', oluşturucudan çıkış yaparken null olmayan bir değer içermelidir. 'required' tanımlayıcısını eklemeyi, {0} null atanabilir olarak bildirmeyi veya '[field: MaybeNull, AllowNull]' özniteliklerini eklemeyi düşünün. Similar diagnostic message as 'WRN_UninitializedNonNullableField' - Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. Null atanamaz özelliği, oluşturucudan çıkış yaparken null olmayan bir değer içermelidir. 'required' tanımlayıcısını eklemeyi, özelliği null atanabilir olarak bildirmeyi veya '[field: MaybeNull, AllowNull]' özniteliklerini eklemeyi düşünün. @@ -5420,12 +5545,12 @@ UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. - UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute yalnızca C# 11 veya sonraki sürümde veya net7.0 veya üzeri hedeflendiğinde geçerlidir. UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. - UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute yalnızca C# 11 veya sonraki sürümde veya net7.0 veya üzeri hedeflendiğinde geçerlidir. @@ -6729,8 +6854,8 @@ - The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. - 'partial' değiştiricisi yalnızca 'class', 'record', 'struct', 'interface' ifadelerinden veya metot ya da özellik dönüş türünden hemen önce gelebilir. + The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. + 'partial' değiştiricisi yalnızca 'class', 'record', 'struct', 'interface' ifadelerinden veya metot ya da özellik dönüş türünden hemen önce gelebilir. @@ -8832,8 +8957,8 @@ RuntimeCompatibilityAttribute AssemblyInfo.cs dosyasında false olarak ayarlanm - Cannot define a new extension method because the compiler required type '{0}' cannot be found. Are you missing a reference to System.Core.dll? - Derleyicinin gerektirdiği '{0}' türü bulunamadığından yeni bir genişletme yöntemi tanımlanamıyor. Bir System.Core.dll başvurusu eksik olabilir mi? + Cannot define a new extension because the compiler required type '{0}' cannot be found. Are you missing a reference to System.Core.dll? + Derleyicinin gerektirdiği '{0}' türü bulunamadığından yeni bir genişletme yöntemi tanımlanamıyor. Bir System.Core.dll başvurusu eksik olabilir mi? @@ -8927,8 +9052,8 @@ RuntimeCompatibilityAttribute AssemblyInfo.cs dosyasında false olarak ayarlanm - Invalid token '{0}' in class, record, struct, or interface member declaration - Sınıf, kayıt, yapı veya arabirim üye bildiriminde '{0}' belirteci geçersiz + Invalid token '{0}' in a member declaration + Sınıf, kayıt, yapı veya arabirim üye bildiriminde '{0}' belirteci geçersiz @@ -10376,7 +10501,7 @@ Derleyiciye yöntemleri ayrıştırma yolu verin. Örneğin, bunlara farklı adl Cannot open '{0}' for writing -- {1} - '{0}' yazma için açılamıyor -- '{1}' + '{0}' yazma için açılamıyor -- {1} @@ -12741,7 +12866,7 @@ Uyarıyı kaldırmak için, /reference kullanabilirsiniz (Birlikte Çalışma T Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string literals or try the EXPERIMENTAL feature flag 'experimental-data-section-string-literals'. - Program tarafından kullanılan kullanıcı dizelerinin toplam uzunluğu, izin verilen sınırı aşıyor. Dize sabit değerlerinin kullanımını azaltmayı deneyin. + Program tarafından kullanılan kullanıcı dizelerinin toplam uzunluğu, izin verilen sınırı aşıyor. Dize değişmezlerini daha az kullanmayı deneyin veya 'experimental-data-section-string-literals' EXPERIMENTAL özellik bayrağını deneyin. @@ -13036,7 +13161,7 @@ Uyarıyı kaldırmak için, /reference kullanabilirsiniz (Birlikte Çalışma T '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + '{0}' yalnızca değerlendirme amaçlıdır ve gelecekteki güncelleştirmelerde değiştirilebilir veya kaldırılabilir. Devam etmek için bu tanılamayı gizleyin. @@ -13091,7 +13216,7 @@ Uyarıyı kaldırmak için, /reference kullanabilirsiniz (Birlikte Çalışma T Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + '{2}' bütünleştirilmiş kodundan '{0}' metodunun (belirteç 0x{1:X8}) hata ayıklama bilgileri okunamıyor: {3} diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index f9e48d62ef9fa..84be676053c62 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -222,6 +222,11 @@ 无法在异步 foreach 中使用动态类型集合 + + Extensions must be declared in a top-level, non-generic, static class + Extensions must be declared in a top-level, non-generic, static class + + The type '{0}' may not be used for a field of a record. 类型“{0}”不能用于记录的字段。 @@ -373,8 +378,8 @@ - Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specifc numeric type. - 无法对 "{0}" 使用数值常量或关系模式,因为它继承自或扩展了 "INumberBase<T>"。请考虑使用类型模式缩小到具体的数值类型。 + Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specific numeric type. + 无法对 "{0}" 使用数值常量或关系模式,因为它继承自或扩展了 "INumberBase<T>"。请考虑使用类型模式缩小到具体的数值类型。 @@ -542,6 +547,11 @@ 复制构造函数“{0}”必须是公共的或受保护的,因为该记录未密封。 + + Cannot emit this string literal into the data section because it has XXHash128 collision with another string literal: {0} + Cannot emit this string literal into the data section because it has XXHash128 collision with another string literal: {0} + + The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'. 名称“{0}”与相应 "Deconstruct" 参数“{1}”不匹配。 @@ -639,7 +649,7 @@ Cannot emit update; {0} '{1}' is missing. - Cannot emit update; {0} '{1}' is missing. + 无法发出更新;缺少 {0} '{1}' 。 @@ -717,6 +727,11 @@ 表达式树不能包含集合表达式。 + + An expression tree may not contain an extension property access + An expression tree may not contain an extension property access + + An expression tree may not contain a from-end index ('^') expression. 表达式树不能包含 from-end 索引("^")表达式。 @@ -762,6 +777,26 @@ 表达式树不能包含 with 表达式。 + + Extension declarations can include only methods or properties + Extension declarations can include only methods or properties + + + + Extension declarations may not have a name. + Extension declarations may not have a name. + + + + The receiver parameter of an extension cannot have a default value + The receiver parameter of an extension cannot have a default value + + + + '{0}' does not contain a definition for '{1}' and no accessible extension member '{1}' for receiver of type '{0}' could be found (are you missing a using directive or an assembly reference?) + '{0}' does not contain a definition for '{1}' and no accessible extension member '{1}' for receiver of type '{0}' could be found (are you missing a using directive or an assembly reference?) + + '{0}': extern event cannot have initializer “{0}”: 外部事件不能有初始值设定项 @@ -1247,6 +1282,11 @@ “Experimental” 属性的 diagnosticId 参数必须是有效的标识符 + + Cannot use extension parameter '{0}' in this context. + Cannot use extension parameter '{0}' in this context. + + '{0}' is not a valid function pointer return type modifier. Valid modifiers are 'ref' and 'ref readonly'. “{0}”不是有效的函数指针返回类型修饰符。有效的修饰符为 "ref" 和 "ref readonly"。 @@ -1339,7 +1379,7 @@ Element type of an iterator may not be a ref struct or a type parameter allowing ref structs - Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + 迭代器的元素类型不能是 ref 结构或允许 ref 结构的类型参数 @@ -1387,6 +1427,16 @@ 列表模式不能用于 '{0}' 类型的值。找不到合适的 \"Length\" 或 \"Count\" 属性。 + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + + No overload for '{0}' matches function pointer '{1}' “{0}”没有与函数指针“{1}”匹配的重载 @@ -1687,6 +1737,16 @@ Params 参数必须具有有效的集合类型 + + '{0}': only the implementing declaration of a partial constructor can have an initializer + '{0}': only the implementing declaration of a partial constructor can have an initializer + + + + '{0}': partial event cannot have initializer + '{0}': partial event cannot have initializer + + Both partial member declarations must have identical accessibility modifiers. 这两个分部成员声明必须具有相同的可访问性修饰符。 @@ -1697,11 +1757,31 @@ 分部成员不能具有 "abstract" 修饰符 + + Partial member '{0}' may not have multiple defining declarations. + Partial member '{0}' may not have multiple defining declarations. + + + + Partial member '{0}' may not have multiple implementing declarations. + Partial member '{0}' may not have multiple implementing declarations. + + Both partial member declarations, '{0}' and '{1}', must use the same tuple element names. 这两个分部成员声明(“{0}”和“{1}”)都必须使用相同的元组元素名称。 + + Partial member '{0}' must have a definition part. + Partial member '{0}' must have a definition part. + + + + Partial member '{0}' must have an implementation part. + Partial member '{0}' must have an implementation part. + + A partial member must be declared within a partial type 分部成员必须在分部类型内声明 @@ -1727,6 +1807,11 @@ 分部成员声明必须具有匹配的引用返回值。 + + Both partial member declarations must have the same type. + Both partial member declarations must have the same type. + + Both partial member declarations must be unsafe or neither may be unsafe 这两个分部成员声明必须都是或者都不是不安全声明 @@ -1797,11 +1882,6 @@ 这两个分部属性声明必须都是或者都不是必需声明 - - Both partial property declarations must have the same type. - 这两个分部属性声明必须具有相同的类型。 - - Property accessor '{0}' does not implement any accessor declared on the definition part 属性访问器“{0}”未实现在定义部分上声明的任何访问器 @@ -1862,6 +1942,16 @@ “{0}”: 仅当属性或索引器同时具有 get 访问器和 set 访问器时,才能对访问器使用 "readonly" + + An extension container can have only one receiver parameter + An extension container can have only one receiver parameter + + + + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + + The primary constructor conflicts with the synthesized copy constructor. 主构造函数与合成的复制构造函数冲突。 @@ -1884,7 +1974,7 @@ Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escape scopes than '{1}'. - 无法将 "{1}" ref-assign 给 "{0}",因为 "{1}" 比 "{0}" 具有更广的值转义范围,允许通过转义范围比 "{1}" 更窄的值的 "{0}" 进行赋值。 + 无法将“{1}”ref-assign 给“{0}”,因为“{1}”比“{0}”具有更广的值转义范围,允许通过转义范围比“{1}”更窄的值的“{0}”进行赋值。 @@ -2019,7 +2109,7 @@ The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. - The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + 类型 “Microsoft.CodeAnalysis.EmbeddedAttribute” 必须是非泛型、内部、密封的非静态构造函数、具有无参数构造函数、从 System.Attribute 继承,并且能够应用于任何类型。 @@ -2272,6 +2362,16 @@ 类型“{0}”必须是公共的,才能用作调用约定。 + + Type parameter '{0}' has the same name as an extension parameter + Type parameter '{0}' has the same name as an extension parameter + + + + Type parameter '{0}' has the same name as an extension container type parameter + Type parameter '{0}' has the same name as an extension container type parameter + + Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. 必须先完全分配自动实现的属性'{0}',然后才能将控件返回到调用方。请考虑更新到语言版本'{1}'以自动默认属性。 @@ -2282,6 +2382,11 @@ 必须先完全分配字段 '{0}' ,然后才能将控件返回给调用方。请考虑更新到语言版本 '{1}' 以自动默认字段。 + + The extended type '{0}' must reference all the type parameters declared by the extension, but type parameter '{1}' is not referenced. + The extended type '{0}' must reference all the type parameters declared by the extension, but type parameter '{1}' is not referenced. + + Unexpected parameter list. 意外的参数列表。 @@ -2372,6 +2477,16 @@ 在分配“this”对象的所有字段之前,无法使用该对象。请考虑更新到语言版本 '{0}' 以自动默认未分配的字段。 + + 'value': an automatically-generated parameter name conflicts with an extension parameter name + 'value': an automatically-generated parameter name conflicts with an extension parameter name + + + + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + + In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. @@ -2442,6 +2557,11 @@ 扩展的属性模式 + + extensions + extensions + + field keyword 字段关键字 @@ -2459,7 +2579,7 @@ first-class Span types - first-class Span types + 一流范围类型 @@ -2539,7 +2659,7 @@ overload resolution priority - overload resolution priority + 重载解析优先级 @@ -2552,6 +2672,11 @@ Params 集合 + + partial events and constructors + partial events and constructors + + positional fields in records 记录中的位置字段 @@ -2624,7 +2749,7 @@ unbound generic types in nameof operator - unbound generic types in nameof operator + nameof 运算符中的未绑定泛型类型 @@ -2714,12 +2839,12 @@ The '{0}' accessor of property '{1}' should use 'field' because the other accessor is using it. - The '{0}' accessor of property '{1}' should use 'field' because the other accessor is using it. + 属性 '{1}' 的 '{0}' 访问器应使用“field”,因为其他访问器正在使用它。 Property accessor should use 'field' because the other accessor is using it. - Property accessor should use 'field' because the other accessor is using it. + 属性访问器应使用 “field”,因为另一个访问器正在使用它。 @@ -2743,13 +2868,13 @@ - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - 分析器程序集“{0}”引用了编译器的版本“{1}”,该版本高于当前正在运行的版本“{2}”。 + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + 分析器程序集“{0}”引用了编译器的版本“{1}”,该版本高于当前正在运行的版本“{2}”。 - The analyzer assembly references a newer version of the compiler than the currently running version. - 分析器程序集引用的编译器版本高于当前正在运行的版本。 + Analyzer assembly cannot be used because it references a newer version of the compiler than the currently running version. + 分析器程序集引用的编译器版本高于当前正在运行的版本。 @@ -2994,12 +3119,12 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + “{0}”仅用于评估,在将来的更新中可能会被更改或删除:“{1}”。取消此诊断以继续。 Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + 类型仅用于评估,在将来的更新中可能会被更改或删除。取消此诊断以继续。 @@ -3074,12 +3199,12 @@ 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) - 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 不支持 “InterceptsLocationAttribute(string, int, int)”。改为移动到基于 “InterceptableLocation” 的这些属性的生成。(https://github.com/dotnet/roslyn/issues/72133) 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) - 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 不支持 “InterceptsLocationAttribute(string, int, int)”。改为移动到基于 “InterceptableLocation” 的这些属性的生成。(https://github.com/dotnet/roslyn/issues/72133) @@ -3212,14 +3337,14 @@ 参数在 lambda 中具有参数修饰符,但在目标委托类型中没有参数修饰符。 - - Partial property declarations '{0}' and '{1}' have signature differences. - 分部属性声明“{0}”和“{1}”具有签名差异。 + + Partial member declarations '{0}' and '{1}' have signature differences. + Partial member declarations '{0}' and '{1}' have signature differences. - - Partial property declarations have signature differences. - 分部属性声明具有签名差异。 + + Partial member declarations have signature differences. + Partial member declarations have signature differences. @@ -3289,7 +3414,7 @@ This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escape scopes than '{1}'. - 它会将 "{1}" ref-assign 给 "{0}",但 "{1}" 比 "{0}" 具有更广的值转义范围,允许通过转义范围比 "{1}" 更窄的值的 "{0}" 进行赋值。 + 它会将“{1}”ref-assign 给“{0}”,但“{1}”比“{0}”具有更广的值转义范围,允许通过转义范围比“{1}”更窄的值的“{0}”进行赋值。 @@ -5300,12 +5425,12 @@ Field '{0}' is never ref-assigned to, and will always have its default value (null reference) - Field '{0}' is never ref-assigned to, and will always have its default value (null reference) + 字段“{0}”永远不会被 ref-assign,并且始终具有其默认值(null 引用) Field is never ref-assigned to, and will always have its default value (null reference) - Field is never ref-assigned to, and will always have its default value (null reference) + 字段永远不会被 ref-assign,并将始终具有其默认值(null 引用) @@ -5379,12 +5504,12 @@ - Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or safely handling the case where 'field' is null in the 'get' accessor. 在退出构造函数时,不可为 null 的 {0} ‘{1}’ 必须包含非 null 值。请考虑添加 ‘required’ 修饰符,或将 {0} 声明为可为 null,或添加 ‘[field: MaybeNull, AllowNull]’ 特性。 Similar diagnostic message as 'WRN_UninitializedNonNullableField' - Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. 退出构造函数时,不可为 null 的属性必须包含非 null 值。请考虑添加 ‘required’ 修饰符,或将属性声明为可为 null,或添加 ‘[field: MaybeNull, AllowNull]’ 特性。 @@ -5420,12 +5545,12 @@ UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. - UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute 仅在 C# 11 或更高版本中或面向 net7.0 或更高版本时有效。 UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. - UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute 仅在 C# 11 或更高版本中或面向 net7.0 或更高版本时有效。 @@ -6729,8 +6854,8 @@ - The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. - "partial" 修饰符的后面只能紧跟 "class"、"record"、"struct"、"interface" 或者方法或属性返回类型。 + The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. + "partial" 修饰符的后面只能紧跟 "class"、"record"、"struct"、"interface" 或者方法或属性返回类型。 @@ -8832,8 +8957,8 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep - Cannot define a new extension method because the compiler required type '{0}' cannot be found. Are you missing a reference to System.Core.dll? - 无法定义新的扩展方法,因为找不到编译器需要的类型“{0}”。是否缺少对 System.Core.dll 的引用? + Cannot define a new extension because the compiler required type '{0}' cannot be found. Are you missing a reference to System.Core.dll? + 无法定义新的扩展方法,因为找不到编译器需要的类型“{0}”。是否缺少对 System.Core.dll 的引用? @@ -8927,8 +9052,8 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep - Invalid token '{0}' in class, record, struct, or interface member declaration - 类、记录、结构或接口成员声明中的标记“{0}”无效 + Invalid token '{0}' in a member declaration + 类、记录、结构或接口成员声明中的标记“{0}”无效 @@ -10376,7 +10501,7 @@ Give the compiler some way to differentiate the methods. For example, you can gi Cannot open '{0}' for writing -- {1} - 无法打开“{0}”进行写入 --“{1}” + 无法打开“{0}”以进行写入 - {1} @@ -12741,7 +12866,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string literals or try the EXPERIMENTAL feature flag 'experimental-data-section-string-literals'. - 该程序中的所有用户字符串在合并后,长度超出限制。请尝试减少字符串字面量的使用。 + 该程序所使用的用户字符串的合并后长度超出所允许的限制。请尝试减少字符串文本的使用,或试用 EXPERIMENTAL 功能标志 ‘experimental-data-section-string-literals’。 @@ -13036,7 +13161,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + “{0}”仅用于评估,在将来的更新中可能会被更改或删除。取消此诊断以继续。 @@ -13091,7 +13216,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + 无法从程序集“{2}”读取方法“{0}”(令牌 0x{1:X8})的调试信息: {3} diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 5714faaef282e..99af651bab5ec 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -222,6 +222,11 @@ 無法在非同步 foreach 中使用動態類型的集合 + + Extensions must be declared in a top-level, non-generic, static class + Extensions must be declared in a top-level, non-generic, static class + + The type '{0}' may not be used for a field of a record. 類型 '{0}' 不可用於記錄的欄位。 @@ -373,8 +378,8 @@ - Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specifc numeric type. - 無法在 '{0}' 上使用數值常數或關聯式模式,因為它繼承自或延伸 'INumberBase<T>'。請考慮使用類型模式來縮小為特定數數值型別。 + Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specific numeric type. + 無法在 '{0}' 上使用數值常數或關聯式模式,因為它繼承自或延伸 'INumberBase<T>'。請考慮使用類型模式來縮小為特定數數值型別。 @@ -542,6 +547,11 @@ 因為記錄不是密封的,所以複製建構函式 '{0}' 必須是公用或受保護。 + + Cannot emit this string literal into the data section because it has XXHash128 collision with another string literal: {0} + Cannot emit this string literal into the data section because it has XXHash128 collision with another string literal: {0} + + The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'. 名稱 '{0}' 與對應的 'Deconstruct' 參數 '{1}' 不相符。 @@ -639,7 +649,7 @@ Cannot emit update; {0} '{1}' is missing. - Cannot emit update; {0} '{1}' is missing. + 無法發出更新;遺漏 {0} '{1}' 。 @@ -717,6 +727,11 @@ 運算式樹狀架構不得包含集合運算式。 + + An expression tree may not contain an extension property access + An expression tree may not contain an extension property access + + An expression tree may not contain a from-end index ('^') expression. 運算式樹狀架構不可包含 from-end index ('^') 運算式。 @@ -762,6 +777,26 @@ 運算式樹狀架構不得包含 with 運算式。 + + Extension declarations can include only methods or properties + Extension declarations can include only methods or properties + + + + Extension declarations may not have a name. + Extension declarations may not have a name. + + + + The receiver parameter of an extension cannot have a default value + The receiver parameter of an extension cannot have a default value + + + + '{0}' does not contain a definition for '{1}' and no accessible extension member '{1}' for receiver of type '{0}' could be found (are you missing a using directive or an assembly reference?) + '{0}' does not contain a definition for '{1}' and no accessible extension member '{1}' for receiver of type '{0}' could be found (are you missing a using directive or an assembly reference?) + + '{0}': extern event cannot have initializer '{0}': 外部事件不可有初始設定式 @@ -1247,6 +1282,11 @@ 'Experimental' 屬性的 diagnosticId 引數必須是有效的識別碼 + + Cannot use extension parameter '{0}' in this context. + Cannot use extension parameter '{0}' in this context. + + '{0}' is not a valid function pointer return type modifier. Valid modifiers are 'ref' and 'ref readonly'. '{0}'不是有效的函式指標傳回型別修飾元。有效的修飾元為 'ref' 與 'ref readonly'。 @@ -1339,7 +1379,7 @@ Element type of an iterator may not be a ref struct or a type parameter allowing ref structs - Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + iterator 的元素類型不能是 ref 結構或允許 ref 結構的類型參數 @@ -1387,6 +1427,16 @@ 清單模式不能用於型別 '{0}' 的值。找不到適當的 'Length' 或 'Count' 屬性。 + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + + No overload for '{0}' matches function pointer '{1}' '{0}' 沒有任何多載符合函式指標 '{1}' @@ -1687,6 +1737,16 @@ params 參數必須具有有效的集合型別 + + '{0}': only the implementing declaration of a partial constructor can have an initializer + '{0}': only the implementing declaration of a partial constructor can have an initializer + + + + '{0}': partial event cannot have initializer + '{0}': partial event cannot have initializer + + Both partial member declarations must have identical accessibility modifiers. 兩個部分成員宣告都必須具有完全相同的協助工具修飾元。 @@ -1697,11 +1757,31 @@ 部分成員不能有 'abstract' 修飾元 + + Partial member '{0}' may not have multiple defining declarations. + Partial member '{0}' may not have multiple defining declarations. + + + + Partial member '{0}' may not have multiple implementing declarations. + Partial member '{0}' may not have multiple implementing declarations. + + Both partial member declarations, '{0}' and '{1}', must use the same tuple element names. 兩個部份成員宣告 '{0}' 和 '{1}' 都必須使用相同的 Tuple 元素名稱。 + + Partial member '{0}' must have a definition part. + Partial member '{0}' must have a definition part. + + + + Partial member '{0}' must have an implementation part. + Partial member '{0}' must have an implementation part. + + A partial member must be declared within a partial type 部分成員必須在部分型別內宣告 @@ -1727,6 +1807,11 @@ 部分成員宣告必須有相符的參考傳回值。 + + Both partial member declarations must have the same type. + Both partial member declarations must have the same type. + + Both partial member declarations must be unsafe or neither may be unsafe 兩個部分成員宣告皆必須為非受控,或者皆不為非受控 @@ -1797,11 +1882,6 @@ 兩個部分屬性宣告都必須是必要項,或者都不是必要項 - - Both partial property declarations must have the same type. - 兩個部分屬性宣告都必須有相同型別。 - - Property accessor '{0}' does not implement any accessor declared on the definition part 屬性存取子 '{0}' 未實作定義部分上宣告的任何存取子 @@ -1862,6 +1942,16 @@ '{0}': 只有在屬性或索引子同時具有 get 和 set 存取子時,才能在存取子上使用 'readonly' + + An extension container can have only one receiver parameter + An extension container can have only one receiver parameter + + + + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + + The primary constructor conflicts with the synthesized copy constructor. 主要建構函式與合成的複製建構函式相衝突。 @@ -1884,7 +1974,7 @@ Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escape scopes than '{1}'. - 無法參考指派 '{1}' 給 '{0}',因為 '{1}' 具有比 '{0}' 更寬的值逸出範圍,允許透過 '{0}' 的值指派,其逸出範圍比 '{1}' 更窄。 + 無法參考指派 '{1}' 給 '{0}',因為 '{1}' 具有比 '{0}' 更寬的值逸出範圍,允許透過 '{0}' 具有比 '{1}' 更窄的值逸出範圍指派。 @@ -2019,7 +2109,7 @@ The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. - The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + 類型 'Microsoft.CodeAnalysis.EmbeddedAttribute' 必須是非泛型、內部、密封、非靜態、具有無參數建構函式、繼承自 System.Attribute,而且可以套用到任何類型。 @@ -2272,6 +2362,16 @@ 類型 '{0}' 必須是公用,才能用為呼叫慣例。 + + Type parameter '{0}' has the same name as an extension parameter + Type parameter '{0}' has the same name as an extension parameter + + + + Type parameter '{0}' has the same name as an extension container type parameter + Type parameter '{0}' has the same name as an extension container type parameter + + Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. 在控制項傳回呼叫者之前,必須先完全指派自動實作屬性 '{0}'。請考慮更新至語言版本 '{1}' 以自動預設屬性。 @@ -2282,6 +2382,11 @@ 在控制項傳回呼叫者之前,必須先完全指派欄位 '{0}'。請考慮更新至語言版本 '{1}' 以自動預設欄位。 + + The extended type '{0}' must reference all the type parameters declared by the extension, but type parameter '{1}' is not referenced. + The extended type '{0}' must reference all the type parameters declared by the extension, but type parameter '{1}' is not referenced. + + Unexpected parameter list. 未預期的參數清單。 @@ -2372,6 +2477,16 @@ 在指派 'this' 物件的所有欄位之前,無法使用該物件。請考慮更新語言版本 '{0}',以自動預設未指派的欄位。 + + 'value': an automatically-generated parameter name conflicts with an extension parameter name + 'value': an automatically-generated parameter name conflicts with an extension parameter name + + + + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + + In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. @@ -2442,6 +2557,11 @@ 擴充屬性模式 + + extensions + extensions + + field keyword 欄位關鍵字 @@ -2459,7 +2579,7 @@ first-class Span types - first-class Span types + 第一類 Span 類型 @@ -2539,7 +2659,7 @@ overload resolution priority - overload resolution priority + 多載解析優先順序 @@ -2552,6 +2672,11 @@ 參數集合 + + partial events and constructors + partial events and constructors + + positional fields in records 記錄中的位置欄位 @@ -2624,7 +2749,7 @@ unbound generic types in nameof operator - unbound generic types in nameof operator + 運算子 nameof 中的未系結泛型型別 @@ -2714,12 +2839,12 @@ The '{0}' accessor of property '{1}' should use 'field' because the other accessor is using it. - The '{0}' accessor of property '{1}' should use 'field' because the other accessor is using it. + 屬性 '{1}' 的 '{0}' 存取子應該使用 『field』,因為其他存取子正在使用它。 Property accessor should use 'field' because the other accessor is using it. - Property accessor should use 'field' because the other accessor is using it. + 屬性存取子應該使用 『field』,因為其他存取子正在使用它。 @@ -2743,13 +2868,13 @@ - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - 分析程式組件 '{0}' 參考編譯器的版本 '{1}' ,比目前執行的版本 '{2}' 還要新。 + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + 分析程式組件 '{0}' 參考編譯器的版本 '{1}' ,比目前執行的版本 '{2}' 還要新。 - The analyzer assembly references a newer version of the compiler than the currently running version. - 分析程式組件參考的編譯器版本比目前執行的版本新。 + Analyzer assembly cannot be used because it references a newer version of the compiler than the currently running version. + 分析程式組件參考的編譯器版本比目前執行的版本新。 @@ -2994,12 +3119,12 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + '{0}' 僅供評估用。後續更新: '{1}' 時可能會有所變更或移除。抑制此診斷以繼續。 Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + 類型僅供評估之用,可能會在未來更新中變更或移除。抑制此診斷以繼續。 @@ -3074,12 +3199,12 @@ 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) - 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 不支援 'InterceptsLocationAttribute(字串、int、int)'。改為移至以 『InterceptableLocation』 為基礎的這些屬性產生。(https://github.com/dotnet/roslyn/issues/72133) 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) - 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 不支援 'InterceptsLocationAttribute(字串、int、int)'。改為移至以 『InterceptableLocation』 為基礎的這些屬性產生。(https://github.com/dotnet/roslyn/issues/72133) @@ -3212,14 +3337,14 @@ 參數在 Lambda 中具有參數修飾元,但不在目標委派類型中。 - - Partial property declarations '{0}' and '{1}' have signature differences. - 部分屬性宣告 '{0}' 和 '{1}' 有簽章差異。 + + Partial member declarations '{0}' and '{1}' have signature differences. + Partial member declarations '{0}' and '{1}' have signature differences. - - Partial property declarations have signature differences. - 部分屬性宣告有簽章差異。 + + Partial member declarations have signature differences. + Partial member declarations have signature differences. @@ -3289,7 +3414,7 @@ This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escape scopes than '{1}'. - 此參考指派 '{1}' 給 '{0}' 但 '{1}' 具有比 '{0}' 更寬的值逸出範圍,允許透過 '{0}' 的值指派,其逸出範圍比 '{1}' 更窄。 + 這會將 '{1}' 參考指派給 '{0}',但 '{1}' 具有比 '{0}' 更寬的值逸出範圍,允許透過 '{0}' 具有比 '{1}' 更窄的值逸出範圍指派。 @@ -3721,7 +3846,7 @@ Visual C# 編譯器選項 - OUTPUT FILES - --out:<file> 指定輸出檔案名稱 (預設: +-out:<file> 指定輸出檔案名稱 (預設: 具有主要類別或第一個檔案的檔案基礎名稱) -target:exe 建置主控台可執行檔 (預設) (簡短 形式: -t:exe) @@ -3838,7 +3963,7 @@ strument:TestCoverage 產生檢測要收集 - ADVANCED - -baseaddress:<address> 要建置程式庫的基底位址 -checksumalgorithm:<alg> 指定計算儲存在 PDB 中 - 來源檔案總和檢查碼的演算法。支援的值為: + 來源檔案總和檢查碼的演算法。支援的值為: SHA1 或 SHA256 (預設)。 -codepage:<n> 指定開啟來源 檔案時所要使用的字碼頁 @@ -5300,12 +5425,12 @@ strument:TestCoverage 產生檢測要收集 Field '{0}' is never ref-assigned to, and will always have its default value (null reference) - Field '{0}' is never ref-assigned to, and will always have its default value (null reference) + 從未參考指派至欄位 '{0}',並會一律使用其預設值 (Null 參考) Field is never ref-assigned to, and will always have its default value (null reference) - Field is never ref-assigned to, and will always have its default value (null reference) + 從未參考指派至欄位,並會一律使用其預設值 (Null 參考) @@ -5379,12 +5504,12 @@ strument:TestCoverage 產生檢測要收集 - Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or safely handling the case where 'field' is null in the 'get' accessor. 退出建構函式時,不可為 Null {0} '{1}' 必須包含不可為 Null 值。請考慮新增 'required' 修飾元,或將 {0} 宣告為可為 Null,或新增 '[field: MaybeNull, AllowNull]' 屬性。 Similar diagnostic message as 'WRN_UninitializedNonNullableField' - Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. 退出建構函式時,不可為 Null 屬性必須包含不可為 Null 值。請考慮新增 'required' 修飾元,或將屬性宣告為可為 Null,或新增 '[field: MaybeNull, AllowNull]' 屬性。 @@ -5420,12 +5545,12 @@ strument:TestCoverage 產生檢測要收集 UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. - UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute 只在 C# 11 或更新版本中有效,或以 net7.0 或更新版本為目標時有效。 UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. - UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute 只在 C# 11 或更新版本中有效,或以 net7.0 或更新版本為目標時有效。 @@ -6729,8 +6854,8 @@ strument:TestCoverage 產生檢測要收集 - The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. - 'partial' 修飾元只能直接出現在 'class'、'record'、'struct'、'interface' 或方法或屬性傳回型別之前。 + The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. + 'partial' 修飾元只能直接出現在 'class'、'record'、'struct'、'interface' 或方法或屬性傳回型別之前。 @@ -8832,8 +8957,8 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep - Cannot define a new extension method because the compiler required type '{0}' cannot be found. Are you missing a reference to System.Core.dll? - 無法定義新的擴充方法,因為找不到編譯器的必要類型 '{0}'。是否遺漏了 System.Core.dll 的參考? + Cannot define a new extension because the compiler required type '{0}' cannot be found. Are you missing a reference to System.Core.dll? + 無法定義新的擴充方法,因為找不到編譯器的必要類型 '{0}'。是否遺漏了 System.Core.dll 的參考? @@ -8927,8 +9052,8 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep - Invalid token '{0}' in class, record, struct, or interface member declaration - 類別、記錄、結構或介面成員宣告中的語彙基元 '{0}' 無效 + Invalid token '{0}' in a member declaration + 類別、記錄、結構或介面成員宣告中的語彙基元 '{0}' 無效 @@ -10376,7 +10501,7 @@ Give the compiler some way to differentiate the methods. For example, you can gi Cannot open '{0}' for writing -- {1} - 無法開啟 '{0}' 進行寫入 -- '{1}' + 無法開啟 '{0}' 進行寫入 -- {1} @@ -12741,7 +12866,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string literals or try the EXPERIMENTAL feature flag 'experimental-data-section-string-literals'. - 程式所使用的使用者字串加起來長度超過允許限制。請嘗試減少使用字串常值。 + 程式所使用的使用者字串加起來長度超過允許限制。嘗試減少使用字串文字,或嘗試實驗性功能旗標 'experimental-data-section-string-literals'。 @@ -13036,7 +13161,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + '{0}' 僅供評估之用,可能會在未來更新中變更或移除。抑制此診斷以繼續。 @@ -13091,7 +13216,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + 無法從組件 '{2}' 讀取方法 '{0}' (權杖 0x{1:X8}) 的偵錯資訊: {3} diff --git a/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs b/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs index 31372989a3f2c..bd8a95b57f441 100644 --- a/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs +++ b/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs @@ -15497,11 +15497,11 @@ class C {} "); var notAnalyzer = dir.CreateFile("random.txt"); - // not suppresssed + // not suppressed var output = VerifyOutput(dir, src, additionalFlags: new[] { "/analyzer:" + notAnalyzer.Path }, expectedWarningCount: 1, includeCurrentAssemblyAsAnalyzerReference: false); Assert.Contains("warning CS8034", output, StringComparison.Ordinal); - // supressed + // suppressed VerifyOutput(dir, src, additionalFlags: new[] { "/analyzer:" + notAnalyzer.Path, "/nowarn:CS8034" }, expectedWarningCount: 0, includeCurrentAssemblyAsAnalyzerReference: false); // elevated @@ -15521,11 +15521,11 @@ class C {} "); var notAnalyzer = dir.CreateFile("random.txt"); - // not suppresssed + // not suppressed var output = VerifyOutput(dir, src, additionalFlags: new[] { "/analyzer:" + notAnalyzer.Path }, expectedWarningCount: 1, includeCurrentAssemblyAsAnalyzerReference: false); Assert.Contains("warning CS8034", output, StringComparison.Ordinal); - // suppresssed via global analyzer config + // suppressed via global analyzer config VerifyOutput(dir, src, additionalFlags: new[] { "/analyzer:" + notAnalyzer.Path, "/analyzerConfig:" + globalconfig.Path }, includeCurrentAssemblyAsAnalyzerReference: false); } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDynamicTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDynamicTests.cs index 2331a9abfa16a..a044cf3259317 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDynamicTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDynamicTests.cs @@ -1370,7 +1370,7 @@ .locals init (C.<>c__DisplayClass11_0 V_0, //CS$<>8__locals0 IL_02b5: ldloc.0 IL_02b6: ldfld ""dynamic C.<>c__DisplayClass11_0.dyn"" IL_02bb: stloc.2 - IL_02bc: ldsfld ""System.Runtime.CompilerServices.CallSite> C.<>o__11.<>p__12"" + IL_02bc: ldsfld ""System.Runtime.CompilerServices.CallSite> C.<>o__11.<>p__9"" IL_02c1: brtrue.s IL_02e2 IL_02c3: ldc.i4.0 IL_02c4: ldstr ""event"" @@ -1378,16 +1378,16 @@ .locals init (C.<>c__DisplayClass11_0 V_0, //CS$<>8__locals0 IL_02ce: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" IL_02d3: call ""System.Runtime.CompilerServices.CallSiteBinder Microsoft.CSharp.RuntimeBinder.Binder.IsEvent(Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, System.Type)"" IL_02d8: call ""System.Runtime.CompilerServices.CallSite> System.Runtime.CompilerServices.CallSite>.Create(System.Runtime.CompilerServices.CallSiteBinder)"" - IL_02dd: stsfld ""System.Runtime.CompilerServices.CallSite> C.<>o__11.<>p__12"" - IL_02e2: ldsfld ""System.Runtime.CompilerServices.CallSite> C.<>o__11.<>p__12"" + IL_02dd: stsfld ""System.Runtime.CompilerServices.CallSite> C.<>o__11.<>p__9"" + IL_02e2: ldsfld ""System.Runtime.CompilerServices.CallSite> C.<>o__11.<>p__9"" IL_02e7: ldfld ""System.Func System.Runtime.CompilerServices.CallSite>.Target"" - IL_02ec: ldsfld ""System.Runtime.CompilerServices.CallSite> C.<>o__11.<>p__12"" + IL_02ec: ldsfld ""System.Runtime.CompilerServices.CallSite> C.<>o__11.<>p__9"" IL_02f1: ldloc.2 IL_02f2: callvirt ""bool System.Func.Invoke(System.Runtime.CompilerServices.CallSite, object)"" IL_02f7: stloc.3 IL_02f8: ldloc.3 IL_02f9: brtrue.s IL_0348 - IL_02fb: ldsfld ""System.Runtime.CompilerServices.CallSite> C.<>o__11.<>p__11"" + IL_02fb: ldsfld ""System.Runtime.CompilerServices.CallSite> C.<>o__11.<>p__8"" IL_0300: brtrue.s IL_0331 IL_0302: ldc.i4.0 IL_0303: ldstr ""event"" @@ -1403,10 +1403,10 @@ .locals init (C.<>c__DisplayClass11_0 V_0, //CS$<>8__locals0 IL_0321: stelem.ref IL_0322: call ""System.Runtime.CompilerServices.CallSiteBinder Microsoft.CSharp.RuntimeBinder.Binder.GetMember(Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, System.Type, System.Collections.Generic.IEnumerable)"" IL_0327: call ""System.Runtime.CompilerServices.CallSite> System.Runtime.CompilerServices.CallSite>.Create(System.Runtime.CompilerServices.CallSiteBinder)"" - IL_032c: stsfld ""System.Runtime.CompilerServices.CallSite> C.<>o__11.<>p__11"" - IL_0331: ldsfld ""System.Runtime.CompilerServices.CallSite> C.<>o__11.<>p__11"" + IL_032c: stsfld ""System.Runtime.CompilerServices.CallSite> C.<>o__11.<>p__8"" + IL_0331: ldsfld ""System.Runtime.CompilerServices.CallSite> C.<>o__11.<>p__8"" IL_0336: ldfld ""System.Func System.Runtime.CompilerServices.CallSite>.Target"" - IL_033b: ldsfld ""System.Runtime.CompilerServices.CallSite> C.<>o__11.<>p__11"" + IL_033b: ldsfld ""System.Runtime.CompilerServices.CallSite> C.<>o__11.<>p__8"" IL_0340: ldloc.2 IL_0341: callvirt ""object System.Func.Invoke(System.Runtime.CompilerServices.CallSite, object)"" IL_0346: stloc.s V_4 diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStringConcat.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStringConcat.cs index 7716182596f00..4624f248f0d10 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStringConcat.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStringConcat.cs @@ -361,7 +361,7 @@ .maxstack 5 "); } - [ConditionalFact(typeof(WindowsDesktopOnly), Reason = ConditionalSkipReason.TestExecutionNeedsDesktopTypes)] + [Fact] [WorkItem(37830, "https://github.com/dotnet/roslyn/issues/37830")] public void ConcatMerge_MarshalByRefObject() { @@ -405,7 +405,7 @@ static void Main() } } "; - var comp = CompileAndVerify(source, expectedOutput: @"test_field: 2"); + var comp = CompileAndVerify(source, targetFramework: TargetFramework.NetFramework, expectedOutput: ExecutionConditionUtil.IsWindowsDesktop ? @"test_field: 2" : null); comp.VerifyDiagnostics(); // Note: we use ldfld on the field, but not ldflda, because the type is MarshalByRefObject comp.VerifyIL("Test.Main", @" @@ -2104,5 +2104,98 @@ .locals init (T2 V_0, IL_0084: ret }"); } + + [Fact] + public void ConcatNullConditionalAccesses() + { + var source = """ + C c = null; + + System.Console.WriteLine(string.Concat(c?.Prop, "a") + "b"); + + class C + { + public string Prop { get; } + } + """; + + var verifier = CompileAndVerify(source, expectedOutput: "ab"); + verifier.VerifyIL("", """ + { + // Code size 29 (0x1d) + .maxstack 2 + IL_0000: ldnull + IL_0001: dup + IL_0002: brtrue.s IL_0008 + IL_0004: pop + IL_0005: ldnull + IL_0006: br.s IL_000d + IL_0008: call "string C.Prop.get" + IL_000d: ldstr "ab" + IL_0012: call "string string.Concat(string, string)" + IL_0017: call "void System.Console.WriteLine(string)" + IL_001c: ret + } + """); + } + + [Fact] + public void CompoundAdditionDirectConcatOptimization() + { + var source = """ + string s1 = "a"; + string s2 = "b"; + string s3 = "c"; + string s4 = "d"; + + s1 += $"{s2}{s3}{s4}"; + + System.Console.WriteLine(s1); + """; + + var verifier = CompileAndVerify(source, expectedOutput: "abcd"); + verifier.VerifyIL("", """ + { + // Code size 37 (0x25) + .maxstack 4 + .locals init (string V_0, //s2 + string V_1, //s3 + string V_2) //s4 + IL_0000: ldstr "a" + IL_0005: ldstr "b" + IL_000a: stloc.0 + IL_000b: ldstr "c" + IL_0010: stloc.1 + IL_0011: ldstr "d" + IL_0016: stloc.2 + IL_0017: ldloc.0 + IL_0018: ldloc.1 + IL_0019: ldloc.2 + IL_001a: call "string string.Concat(string, string, string, string)" + IL_001f: call "void System.Console.WriteLine(string)" + IL_0024: ret + } + """); + } + + [Fact] + public void ConstantCharPlusNull() + { + var source = """ + const char c = 'a'; + System.Console.WriteLine(c + (string)null); + """; + + var verifier = CompileAndVerify(source, expectedOutput: "a"); + verifier.VerifyIL("", """ + { + // Code size 11 (0xb) + .maxstack 1 + IL_0000: ldstr "a" + IL_0005: call "void System.Console.WriteLine(string)" + IL_000a: ret + } + """); + } } } diff --git a/src/Compilers/CSharp/Test/Emit/Emit/CompilationEmitTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/CompilationEmitTests.cs index 5058dc3912928..c4dca4e0d2899 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/CompilationEmitTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/CompilationEmitTests.cs @@ -574,8 +574,8 @@ internal static void Main() VerifyMethods(output, "C", new[] { "void C.Main()", "C..ctor()" }); VerifyMvid(output, hasMvidSection: false); - verifyEntryPoint(metadataOutput, expectZero: true); - VerifyMethods(metadataOutput, "C", new[] { "C..ctor()" }); + verifyEntryPoint(metadataOutput, expectZero: false); + VerifyMethods(metadataOutput, "C", new[] { "void C.Main()", "C..ctor()" }); VerifyMvid(metadataOutput, hasMvidSection: true); } diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EmitMetadataTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EmitMetadataTests.cs index 234d9f222229f..c8577b654b471 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EmitMetadataTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EmitMetadataTests.cs @@ -3175,6 +3175,27 @@ .maxstack 1 """); } + [Fact] + public void DataSectionStringLiterals_HashCollision() + { + var emitOptions = new EmitOptions + { + // Take only the first byte of each string as its hash to simulate collisions. + TestOnly_DataToHexViaXxHash128 = static (data) => data[0].ToString(), + }; + var source = """ + System.Console.Write("a"); + System.Console.Write("b"); + System.Console.Write("aa"); + """; + CreateCompilation(source, + parseOptions: TestOptions.Regular.WithFeature("experimental-data-section-string-literals", "0")) + .VerifyEmitDiagnostics(emitOptions, + // (3,22): error CS9274: Cannot emit this string literal into the data section because it has XXHash128 collision with another string literal: a + // System.Console.Write("aa"); + Diagnostic(ErrorCode.ERR_DataSectionStringLiteralHashCollision, @"""aa""").WithArguments("a").WithLocation(3, 22)); + } + [Fact] public void DataSectionStringLiterals_SynthesizedTypes() { @@ -3507,5 +3528,224 @@ public class InvalidOperationException(); // warning CS8021: No value for RuntimeMetadataVersion found. No assembly containing System.Object was found nor was a value for RuntimeMetadataVersion specified through options. Diagnostic(ErrorCode.WRN_NoRuntimeMetadataVersion).WithLocation(1, 1)); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76707")] + public void EmitMetadataOnly_Exe() + { + CompileAndVerify(""" + System.Console.WriteLine("a"); + """, + options: TestOptions.ReleaseExe.WithMetadataImportOptions(MetadataImportOptions.All), + emitOptions: EmitOptions.Default.WithEmitMetadataOnly(true), + symbolValidator: static (ModuleSymbol module) => + { + Assert.NotEqual(0, module.GetMetadata().Module.PEReaderOpt.PEHeaders.CorHeader.EntryPointTokenOrRelativeVirtualAddress); + var main = module.GlobalNamespace.GetMember("Program.
$"); + Assert.Equal(Accessibility.Private, main.DeclaredAccessibility); + }) + .VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76707")] + public void EmitMetadataOnly_Exe_AsyncMain() + { + CompileAndVerify(""" + using System.Threading.Tasks; + static class Program + { + static async Task Main() + { + await Task.Yield(); + System.Console.WriteLine("a"); + } + } + """, + options: TestOptions.ReleaseExe.WithMetadataImportOptions(MetadataImportOptions.All), + emitOptions: EmitOptions.Default.WithEmitMetadataOnly(true), + symbolValidator: static (ModuleSymbol module) => + { + Assert.NotEqual(0, module.GetMetadata().Module.PEReaderOpt.PEHeaders.CorHeader.EntryPointTokenOrRelativeVirtualAddress); + var main = module.GlobalNamespace.GetMember("Program.
"); + Assert.Equal(Accessibility.Private, main.DeclaredAccessibility); + }) + .VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76707")] + public void EmitMetadataOnly_Exe_NoMain() + { + var emitResult = CreateCompilation(""" + class Program; + """, + options: TestOptions.ReleaseExe) + .Emit(new MemoryStream(), options: EmitOptions.Default.WithEmitMetadataOnly(true)); + Assert.False(emitResult.Success); + emitResult.Diagnostics.Verify( + // error CS5001: Program does not contain a static 'Main' method suitable for an entry point + Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76707")] + public void EmitMetadataOnly_Exe_PrivateMain_ExcludePrivateMembers() + { + CompileAndVerify(""" + static class Program + { + private static void Main() { } + } + """, + options: TestOptions.ReleaseExe.WithMetadataImportOptions(MetadataImportOptions.All), + emitOptions: EmitOptions.Default + .WithEmitMetadataOnly(true) + .WithIncludePrivateMembers(false), + symbolValidator: static (ModuleSymbol module) => + { + Assert.NotEqual(0, module.GetMetadata().Module.PEReaderOpt.PEHeaders.CorHeader.EntryPointTokenOrRelativeVirtualAddress); + var main = module.GlobalNamespace.GetMember("Program.Main"); + Assert.Equal(Accessibility.Private, main.DeclaredAccessibility); + }) + .VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76707")] + public void EmitMetadataOnly_Exe_PrivateMain_ExcludePrivateMembers_AsyncMain() + { + CompileAndVerify(""" + using System.Threading.Tasks; + static class Program + { + private static async Task Main() + { + await Task.Yield(); + } + } + """, + options: TestOptions.ReleaseExe.WithMetadataImportOptions(MetadataImportOptions.All), + emitOptions: EmitOptions.Default + .WithEmitMetadataOnly(true) + .WithIncludePrivateMembers(false), + symbolValidator: static (ModuleSymbol module) => + { + Assert.NotEqual(0, module.GetMetadata().Module.PEReaderOpt.PEHeaders.CorHeader.EntryPointTokenOrRelativeVirtualAddress); + var main = module.GlobalNamespace.GetMember("Program.
"); + Assert.Equal(Accessibility.Private, main.DeclaredAccessibility); + }) + .VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76707")] + public void ExcludePrivateMembers_PrivateMain() + { + using var peStream = new MemoryStream(); + using var metadataStream = new MemoryStream(); + var comp = CreateCompilation(""" + static class Program + { + private static void Main() { } + } + """, + options: TestOptions.ReleaseExe); + var emitResult = comp.Emit( + peStream: peStream, + metadataPEStream: metadataStream, + options: EmitOptions.Default.WithIncludePrivateMembers(false)); + Assert.True(emitResult.Success); + emitResult.Diagnostics.Verify(); + + verify(peStream); + verify(metadataStream); + + CompileAndVerify(comp).VerifyDiagnostics(); + + static void verify(Stream stream) + { + stream.Position = 0; + Assert.NotEqual(0, new PEHeaders(stream).CorHeader.EntryPointTokenOrRelativeVirtualAddress); + + stream.Position = 0; + var reference = AssemblyMetadata.CreateFromStream(stream).GetReference(); + var comp = CreateCompilation("", references: [reference], + options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + var main = comp.GetMember("Program.Main"); + Assert.Equal(Accessibility.Private, main.DeclaredAccessibility); + } + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76707")] + public void ExcludePrivateMembers_PrivateMain_AsyncMain() + { + using var peStream = new MemoryStream(); + using var metadataStream = new MemoryStream(); + var comp = CreateCompilation(""" + using System.Threading.Tasks; + static class Program + { + private static async Task Main() + { + await Task.Yield(); + } + } + """, + options: TestOptions.ReleaseExe); + var emitResult = comp.Emit( + peStream: peStream, + metadataPEStream: metadataStream, + options: EmitOptions.Default.WithIncludePrivateMembers(false)); + Assert.True(emitResult.Success); + emitResult.Diagnostics.Verify(); + + verify(peStream); + verify(metadataStream); + + CompileAndVerify(comp).VerifyDiagnostics(); + + static void verify(Stream stream) + { + stream.Position = 0; + Assert.NotEqual(0, new PEHeaders(stream).CorHeader.EntryPointTokenOrRelativeVirtualAddress); + + stream.Position = 0; + var reference = AssemblyMetadata.CreateFromStream(stream).GetReference(); + var comp = CreateCompilation("", references: [reference], + options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + var main = comp.GetMember("Program.
"); + Assert.Equal(Accessibility.Private, main.DeclaredAccessibility); + } + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76707")] + public void ExcludePrivateMembers_DebugEntryPoint() + { + using var peStream = new MemoryStream(); + using var metadataStream = new MemoryStream(); + + { + var comp = CreateCompilation(""" + static class Program + { + static void M1() { } + static void M2() { } + } + """).VerifyDiagnostics(); + var emitResult = comp.Emit( + peStream: peStream, + metadataPEStream: metadataStream, + debugEntryPoint: comp.GetMember("Program.M1").GetPublicSymbol(), + options: EmitOptions.Default.WithIncludePrivateMembers(false)); + Assert.True(emitResult.Success); + emitResult.Diagnostics.Verify(); + } + + { + // M1 should be emitted (it's the debug entry-point), M2 shouldn't (private members are excluded). + metadataStream.Position = 0; + var reference = AssemblyMetadata.CreateFromStream(metadataStream).GetReference(); + var comp = CreateCompilation("", references: [reference], + options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + var m1 = comp.GetMember("Program.M1"); + Assert.Equal(Accessibility.Private, m1.DeclaredAccessibility); + Assert.Null(comp.GetMember("Program.M2")); + } + } } } diff --git a/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenCallTests.cs b/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenCallTests.cs index 26e0d88f23509..e65f4aca1a281 100644 --- a/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenCallTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenCallTests.cs @@ -31078,7 +31078,7 @@ .locals init (int V_0, [ConditionalFact(typeof(CoreClrOnly))] [WorkItem(63221, "https://github.com/dotnet/roslyn/issues/63221")] - public void GenericTypeParameterAsReceiver_ImpicitRangeIndexer_RangeExpression_Class() + public void GenericTypeParameterAsReceiver_ImplicitRangeIndexer_RangeExpression_Class() { var source = @" using System; @@ -31219,7 +31219,7 @@ .locals init (T& V_0, [ConditionalFact(typeof(CoreClrOnly))] [WorkItem(63221, "https://github.com/dotnet/roslyn/issues/63221")] - public void GenericTypeParameterAsReceiver_ImpicitRangeIndexer_RangeExpression_Struct() + public void GenericTypeParameterAsReceiver_ImplicitRangeIndexer_RangeExpression_Struct() { var source = @" using System; @@ -31319,7 +31319,7 @@ .locals init (T& V_0, [ConditionalFact(typeof(CoreClrOnly))] [WorkItem(63221, "https://github.com/dotnet/roslyn/issues/63221")] - public void GenericTypeParameterAsReceiver_ImpicitRangeIndexer_RangeExpression_Class_Ref() + public void GenericTypeParameterAsReceiver_ImplicitRangeIndexer_RangeExpression_Class_Ref() { var source = @" using System; @@ -31461,7 +31461,7 @@ .locals init (T& V_0, [ConditionalFact(typeof(CoreClrOnly))] [WorkItem(63221, "https://github.com/dotnet/roslyn/issues/63221")] - public void GenericTypeParameterAsReceiver_ImpicitRangeIndexer_RangeExpression_Struct_Ref() + public void GenericTypeParameterAsReceiver_ImplicitRangeIndexer_RangeExpression_Struct_Ref() { var source = @" using System; @@ -31561,7 +31561,7 @@ .locals init (T& V_0, [ConditionalFact(typeof(CoreClrOnly))] [WorkItem(63221, "https://github.com/dotnet/roslyn/issues/63221")] - public void GenericTypeParameterAsReceiver_ImpicitRangeIndexer_RangeExpression_Class_Async_01() + public void GenericTypeParameterAsReceiver_ImplicitRangeIndexer_RangeExpression_Class_Async_01() { var source = @" using System; @@ -31856,7 +31856,7 @@ .locals init (int V_0, [ConditionalFact(typeof(CoreClrOnly))] [WorkItem(63221, "https://github.com/dotnet/roslyn/issues/63221")] - public void GenericTypeParameterAsReceiver_ImpicitRangeIndexer_RangeExpression_Struct_Async_01() + public void GenericTypeParameterAsReceiver_ImplicitRangeIndexer_RangeExpression_Struct_Async_01() { var source = @" using System; @@ -32026,7 +32026,7 @@ .locals init (int V_0, [ConditionalFact(typeof(CoreClrOnly))] [WorkItem(63221, "https://github.com/dotnet/roslyn/issues/63221")] - public void GenericTypeParameterAsReceiver_ImpicitRangeIndexer_RangeValue_Class() + public void GenericTypeParameterAsReceiver_ImplicitRangeIndexer_RangeValue_Class() { var source = @" using System; @@ -32201,7 +32201,7 @@ .locals init (T V_0, [ConditionalFact(typeof(CoreClrOnly))] [WorkItem(63221, "https://github.com/dotnet/roslyn/issues/63221")] - public void GenericTypeParameterAsReceiver_ImpicitRangeIndexer_RangeValue_Struct() + public void GenericTypeParameterAsReceiver_ImplicitRangeIndexer_RangeValue_Struct() { var source = @" using System; @@ -32318,7 +32318,7 @@ .locals init (System.Range V_0, [ConditionalFact(typeof(CoreClrOnly))] [WorkItem(63221, "https://github.com/dotnet/roslyn/issues/63221")] - public void GenericTypeParameterAsReceiver_ImpicitRangeIndexer_RangeValue_Class_Ref() + public void GenericTypeParameterAsReceiver_ImplicitRangeIndexer_RangeValue_Class_Ref() { var source = @" using System; @@ -32494,7 +32494,7 @@ .locals init (T V_0, [ConditionalFact(typeof(CoreClrOnly))] [WorkItem(63221, "https://github.com/dotnet/roslyn/issues/63221")] - public void GenericTypeParameterAsReceiver_ImpicitRangeIndexer_RangeValue_Struct_Ref() + public void GenericTypeParameterAsReceiver_ImplicitRangeIndexer_RangeValue_Struct_Ref() { var source = @" using System; @@ -32611,7 +32611,7 @@ .locals init (System.Range V_0, [ConditionalFact(typeof(CoreClrOnly))] [WorkItem(63221, "https://github.com/dotnet/roslyn/issues/63221")] - public void GenericTypeParameterAsReceiver_ImpicitRangeIndexer_RangeValue_Class_Async_01() + public void GenericTypeParameterAsReceiver_ImplicitRangeIndexer_RangeValue_Class_Async_01() { var source = @" using System; @@ -32946,7 +32946,7 @@ .locals init (int V_0, [ConditionalFact(typeof(CoreClrOnly))] [WorkItem(63221, "https://github.com/dotnet/roslyn/issues/63221")] - public void GenericTypeParameterAsReceiver_ImpicitRangeIndexer_RangeValue_Struct_Async_01() + public void GenericTypeParameterAsReceiver_ImplicitRangeIndexer_RangeValue_Struct_Async_01() { var source = @" using System; diff --git a/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenSpanBasedStringConcatTests.cs b/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenSpanBasedStringConcatTests.cs index f0d02647d79a9..3d023b0cff388 100644 --- a/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenSpanBasedStringConcatTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenSpanBasedStringConcatTests.cs @@ -586,15 +586,40 @@ static void Main() var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net80); comp.MakeMemberMissing(SpecialMember.System_Object__ToString); - // Although we don't use object.ToString() or char.ToString() in the final codegen we still need object.ToString() during lowering. - // Moreover, we previously reported these errors anyway, so this is not a behavioral change - comp.VerifyEmitDiagnostics( - // (13,47): error CS0656: Missing compiler required member 'System.Object.ToString' - // static string M1(string s, char c) => s + c; - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "c").WithArguments("System.Object", "ToString").WithLocation(13, 47), - // (14,43): error CS0656: Missing compiler required member 'System.Object.ToString' - // static string M2(string s, char c) => c + s; - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "c").WithArguments("System.Object", "ToString").WithLocation(14, 43)); + // We don't use object.ToString() or char.ToString() in the final codegen. + var verifier = CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsCoreClr ? "sccs" : null, verify: Verification.FailsPEVerify); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("Test.M1", """ + { + // Code size 21 (0x15) + .maxstack 2 + .locals init (char V_0) + IL_0000: ldarg.0 + IL_0001: call "System.ReadOnlySpan string.op_Implicit(string)" + IL_0006: ldarg.1 + IL_0007: stloc.0 + IL_0008: ldloca.s V_0 + IL_000a: newobj "System.ReadOnlySpan..ctor(ref readonly char)" + IL_000f: call "string string.Concat(System.ReadOnlySpan, System.ReadOnlySpan)" + IL_0014: ret + } + """); + + verifier.VerifyIL("Test.M2", """ + { + // Code size 21 (0x15) + .maxstack 2 + .locals init (char V_0) + IL_0000: ldarg.1 + IL_0001: stloc.0 + IL_0002: ldloca.s V_0 + IL_0004: newobj "System.ReadOnlySpan..ctor(ref readonly char)" + IL_0009: ldarg.0 + IL_000a: call "System.ReadOnlySpan string.op_Implicit(string)" + IL_000f: call "string string.Concat(System.ReadOnlySpan, System.ReadOnlySpan)" + IL_0014: ret + } + """); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/66827")] @@ -1479,22 +1504,19 @@ public void M() // Code size 50 (0x32) .maxstack 3 .locals init (char V_0, - char V_1, - char V_2) - IL_0000: ldc.i4.s 97 - IL_0002: stloc.0 - IL_0003: ldloca.s V_0 - IL_0005: newobj "System.ReadOnlySpan..ctor(ref readonly char)" + char V_1) + IL_0000: ldstr "a" + IL_0005: call "System.ReadOnlySpan string.op_Implicit(string)" IL_000a: ldarg.0 IL_000b: ldfld "char C.c" - IL_0010: stloc.1 - IL_0011: ldloca.s V_1 + IL_0010: stloc.0 + IL_0011: ldloca.s V_0 IL_0013: newobj "System.ReadOnlySpan..ctor(ref readonly char)" IL_0018: ldarg.0 IL_0019: call "ref char C.GetC()" IL_001e: ldind.u2 - IL_001f: stloc.2 - IL_0020: ldloca.s V_2 + IL_001f: stloc.1 + IL_0020: ldloca.s V_1 IL_0022: newobj "System.ReadOnlySpan..ctor(ref readonly char)" IL_0027: call "string string.Concat(System.ReadOnlySpan, System.ReadOnlySpan, System.ReadOnlySpan)" IL_002c: call "void System.Console.Write(string)" @@ -1546,23 +1568,20 @@ private char SneakyLocalChange(ref char local) .maxstack 4 .locals init (char V_0, //c char V_1, - char V_2, - char V_3) + char V_2) IL_0000: ldc.i4.s 97 IL_0002: stloc.0 - IL_0003: ldc.i4.s 97 - IL_0005: stloc.1 - IL_0006: ldloca.s V_1 - IL_0008: newobj "System.ReadOnlySpan..ctor(ref readonly char)" + IL_0003: ldstr "a" + IL_0008: call "System.ReadOnlySpan string.op_Implicit(string)" IL_000d: ldloc.0 - IL_000e: stloc.2 - IL_000f: ldloca.s V_2 + IL_000e: stloc.1 + IL_000f: ldloca.s V_1 IL_0011: newobj "System.ReadOnlySpan..ctor(ref readonly char)" IL_0016: ldarg.0 IL_0017: ldloca.s V_0 IL_0019: call "char C.SneakyLocalChange(ref char)" - IL_001e: stloc.3 - IL_001f: ldloca.s V_3 + IL_001e: stloc.2 + IL_001f: ldloca.s V_2 IL_0021: newobj "System.ReadOnlySpan..ctor(ref readonly char)" IL_0026: call "string string.Concat(System.ReadOnlySpan, System.ReadOnlySpan, System.ReadOnlySpan)" IL_002b: ret @@ -2117,24 +2136,80 @@ static void Main() var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net80); comp.MakeMemberMissing(SpecialMember.System_Object__ToString); - // Although we don't use object.ToString() or char.ToString() in the final codegen we still need object.ToString() during lowering. - // Moreover, we previously reported these errors anyway, so this is not a behavioral change - comp.VerifyEmitDiagnostics( - // (15,43): error CS0656: Missing compiler required member 'System.Object.ToString' - // static string M1(string s, char c) => c + s + s; - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "c").WithArguments("System.Object", "ToString").WithLocation(15, 43), - // (16,47): error CS0656: Missing compiler required member 'System.Object.ToString' - // static string M2(string s, char c) => s + c + s; - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "c").WithArguments("System.Object", "ToString").WithLocation(16, 47), - // (17,51): error CS0656: Missing compiler required member 'System.Object.ToString' - // static string M3(string s, char c) => s + s + c; - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "c").WithArguments("System.Object", "ToString").WithLocation(17, 51), - // (18,43): error CS0656: Missing compiler required member 'System.Object.ToString' - // static string M4(string s, char c) => c + s + c; - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "c").WithArguments("System.Object", "ToString").WithLocation(18, 43), - // (18,51): error CS0656: Missing compiler required member 'System.Object.ToString' - // static string M4(string s, char c) => c + s + c; - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "c").WithArguments("System.Object", "ToString").WithLocation(18, 51)); + var verifier = CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsCoreClr ? "cssscsssccsc" : null, verify: Verification.FailsPEVerify); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("Test.M1", """ + { + // Code size 27 (0x1b) + .maxstack 3 + .locals init (char V_0) + IL_0000: ldarg.1 + IL_0001: stloc.0 + IL_0002: ldloca.s V_0 + IL_0004: newobj "System.ReadOnlySpan..ctor(ref readonly char)" + IL_0009: ldarg.0 + IL_000a: call "System.ReadOnlySpan string.op_Implicit(string)" + IL_000f: ldarg.0 + IL_0010: call "System.ReadOnlySpan string.op_Implicit(string)" + IL_0015: call "string string.Concat(System.ReadOnlySpan, System.ReadOnlySpan, System.ReadOnlySpan)" + IL_001a: ret + } + """); + verifier.VerifyIL("Test.M2", """ + { + // Code size 27 (0x1b) + .maxstack 3 + .locals init (char V_0) + IL_0000: ldarg.0 + IL_0001: call "System.ReadOnlySpan string.op_Implicit(string)" + IL_0006: ldarg.1 + IL_0007: stloc.0 + IL_0008: ldloca.s V_0 + IL_000a: newobj "System.ReadOnlySpan..ctor(ref readonly char)" + IL_000f: ldarg.0 + IL_0010: call "System.ReadOnlySpan string.op_Implicit(string)" + IL_0015: call "string string.Concat(System.ReadOnlySpan, System.ReadOnlySpan, System.ReadOnlySpan)" + IL_001a: ret + } + """); + verifier.VerifyIL("Test.M3", """ + { + // Code size 27 (0x1b) + .maxstack 3 + .locals init (char V_0) + IL_0000: ldarg.0 + IL_0001: call "System.ReadOnlySpan string.op_Implicit(string)" + IL_0006: ldarg.0 + IL_0007: call "System.ReadOnlySpan string.op_Implicit(string)" + IL_000c: ldarg.1 + IL_000d: stloc.0 + IL_000e: ldloca.s V_0 + IL_0010: newobj "System.ReadOnlySpan..ctor(ref readonly char)" + IL_0015: call "string string.Concat(System.ReadOnlySpan, System.ReadOnlySpan, System.ReadOnlySpan)" + IL_001a: ret + } + """); + verifier.VerifyIL("Test.M4", """ + { + // Code size 30 (0x1e) + .maxstack 3 + .locals init (char V_0, + char V_1) + IL_0000: ldarg.1 + IL_0001: stloc.0 + IL_0002: ldloca.s V_0 + IL_0004: newobj "System.ReadOnlySpan..ctor(ref readonly char)" + IL_0009: ldarg.0 + IL_000a: call "System.ReadOnlySpan string.op_Implicit(string)" + IL_000f: ldarg.1 + IL_0010: stloc.1 + IL_0011: ldloca.s V_1 + IL_0013: newobj "System.ReadOnlySpan..ctor(ref readonly char)" + IL_0018: call "string string.Concat(System.ReadOnlySpan, System.ReadOnlySpan, System.ReadOnlySpan)" + IL_001d: ret + } + """); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/66827")] @@ -3369,28 +3444,25 @@ public void M() .maxstack 4 .locals init (char V_0, char V_1, - char V_2, - char V_3) - IL_0000: ldc.i4.s 97 - IL_0002: stloc.0 - IL_0003: ldloca.s V_0 - IL_0005: newobj "System.ReadOnlySpan..ctor(ref readonly char)" + char V_2) + IL_0000: ldstr "a" + IL_0005: call "System.ReadOnlySpan string.op_Implicit(string)" IL_000a: ldarg.0 IL_000b: ldfld "char C.c" - IL_0010: stloc.1 - IL_0011: ldloca.s V_1 + IL_0010: stloc.0 + IL_0011: ldloca.s V_0 IL_0013: newobj "System.ReadOnlySpan..ctor(ref readonly char)" IL_0018: ldarg.0 IL_0019: call "ref char C.GetC()" IL_001e: ldind.u2 - IL_001f: stloc.2 - IL_0020: ldloca.s V_2 + IL_001f: stloc.1 + IL_0020: ldloca.s V_1 IL_0022: newobj "System.ReadOnlySpan..ctor(ref readonly char)" IL_0027: ldarg.0 IL_0028: call "ref char C.GetC2()" IL_002d: ldind.u2 - IL_002e: stloc.3 - IL_002f: ldloca.s V_3 + IL_002e: stloc.2 + IL_002f: ldloca.s V_2 IL_0031: newobj "System.ReadOnlySpan..ctor(ref readonly char)" IL_0036: call "string string.Concat(System.ReadOnlySpan, System.ReadOnlySpan, System.ReadOnlySpan, System.ReadOnlySpan)" IL_003b: call "void System.Console.Write(string)" @@ -4754,39 +4826,158 @@ static void Main() var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net80); comp.MakeMemberMissing(SpecialMember.System_Object__ToString); - // Although we don't use object.ToString() or char.ToString() in the final codegen we still need object.ToString() during lowering. - // Moreover, we previously reported these errors anyway, so this is not a behavioral change - comp.VerifyEmitDiagnostics( - // (18,43): error CS0656: Missing compiler required member 'System.Object.ToString' - // static string M1(string s, char c) => c + s + s + s; - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "c").WithArguments("System.Object", "ToString").WithLocation(18, 43), - // (19,47): error CS0656: Missing compiler required member 'System.Object.ToString' - // static string M2(string s, char c) => s + c + s + s; - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "c").WithArguments("System.Object", "ToString").WithLocation(19, 47), - // (20,51): error CS0656: Missing compiler required member 'System.Object.ToString' - // static string M3(string s, char c) => s + s + c + s; - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "c").WithArguments("System.Object", "ToString").WithLocation(20, 51), - // (21,55): error CS0656: Missing compiler required member 'System.Object.ToString' - // static string M4(string s, char c) => s + s + s + c; - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "c").WithArguments("System.Object", "ToString").WithLocation(21, 55), - // (22,43): error CS0656: Missing compiler required member 'System.Object.ToString' - // static string M5(string s, char c) => c + s + c + s; - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "c").WithArguments("System.Object", "ToString").WithLocation(22, 43), - // (22,51): error CS0656: Missing compiler required member 'System.Object.ToString' - // static string M5(string s, char c) => c + s + c + s; - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "c").WithArguments("System.Object", "ToString").WithLocation(22, 51), - // (23,47): error CS0656: Missing compiler required member 'System.Object.ToString' - // static string M6(string s, char c) => s + c + s + c; - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "c").WithArguments("System.Object", "ToString").WithLocation(23, 47), - // (23,55): error CS0656: Missing compiler required member 'System.Object.ToString' - // static string M6(string s, char c) => s + c + s + c; - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "c").WithArguments("System.Object", "ToString").WithLocation(23, 55), - // (24,43): error CS0656: Missing compiler required member 'System.Object.ToString' - // static string M7(string s, char c) => c + s + s + c; - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "c").WithArguments("System.Object", "ToString").WithLocation(24, 43), - // (24,55): error CS0656: Missing compiler required member 'System.Object.ToString' - // static string M7(string s, char c) => c + s + s + c; - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "c").WithArguments("System.Object", "ToString").WithLocation(24, 55)); + // We don't use object.ToString() or char.ToString() in the final codegen. + var verifier = CompileAndVerify(compilation: comp, expectedOutput: ExecutionConditionUtil.IsCoreClr ? "csssscsssscssssccscsscsccssc" : null, verify: Verification.FailsPEVerify); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("Test.M1", """ + { + // Code size 33 (0x21) + .maxstack 4 + .locals init (char V_0) + IL_0000: ldarg.1 + IL_0001: stloc.0 + IL_0002: ldloca.s V_0 + IL_0004: newobj "System.ReadOnlySpan..ctor(ref readonly char)" + IL_0009: ldarg.0 + IL_000a: call "System.ReadOnlySpan string.op_Implicit(string)" + IL_000f: ldarg.0 + IL_0010: call "System.ReadOnlySpan string.op_Implicit(string)" + IL_0015: ldarg.0 + IL_0016: call "System.ReadOnlySpan string.op_Implicit(string)" + IL_001b: call "string string.Concat(System.ReadOnlySpan, System.ReadOnlySpan, System.ReadOnlySpan, System.ReadOnlySpan)" + IL_0020: ret + } + """); + + verifier.VerifyIL("Test.M2", """ + { + // Code size 33 (0x21) + .maxstack 4 + .locals init (char V_0) + IL_0000: ldarg.0 + IL_0001: call "System.ReadOnlySpan string.op_Implicit(string)" + IL_0006: ldarg.1 + IL_0007: stloc.0 + IL_0008: ldloca.s V_0 + IL_000a: newobj "System.ReadOnlySpan..ctor(ref readonly char)" + IL_000f: ldarg.0 + IL_0010: call "System.ReadOnlySpan string.op_Implicit(string)" + IL_0015: ldarg.0 + IL_0016: call "System.ReadOnlySpan string.op_Implicit(string)" + IL_001b: call "string string.Concat(System.ReadOnlySpan, System.ReadOnlySpan, System.ReadOnlySpan, System.ReadOnlySpan)" + IL_0020: ret + } + """); + + verifier.VerifyIL("Test.M3", """ + { + // Code size 33 (0x21) + .maxstack 4 + .locals init (char V_0) + IL_0000: ldarg.0 + IL_0001: call "System.ReadOnlySpan string.op_Implicit(string)" + IL_0006: ldarg.0 + IL_0007: call "System.ReadOnlySpan string.op_Implicit(string)" + IL_000c: ldarg.1 + IL_000d: stloc.0 + IL_000e: ldloca.s V_0 + IL_0010: newobj "System.ReadOnlySpan..ctor(ref readonly char)" + IL_0015: ldarg.0 + IL_0016: call "System.ReadOnlySpan string.op_Implicit(string)" + IL_001b: call "string string.Concat(System.ReadOnlySpan, System.ReadOnlySpan, System.ReadOnlySpan, System.ReadOnlySpan)" + IL_0020: ret + } + """); + + verifier.VerifyIL("Test.M4", """ + { + // Code size 33 (0x21) + .maxstack 4 + .locals init (char V_0) + IL_0000: ldarg.0 + IL_0001: call "System.ReadOnlySpan string.op_Implicit(string)" + IL_0006: ldarg.0 + IL_0007: call "System.ReadOnlySpan string.op_Implicit(string)" + IL_000c: ldarg.0 + IL_000d: call "System.ReadOnlySpan string.op_Implicit(string)" + IL_0012: ldarg.1 + IL_0013: stloc.0 + IL_0014: ldloca.s V_0 + IL_0016: newobj "System.ReadOnlySpan..ctor(ref readonly char)" + IL_001b: call "string string.Concat(System.ReadOnlySpan, System.ReadOnlySpan, System.ReadOnlySpan, System.ReadOnlySpan)" + IL_0020: ret + } + """); + + verifier.VerifyIL("Test.M5", """ + { + // Code size 36 (0x24) + .maxstack 4 + .locals init (char V_0, + char V_1) + IL_0000: ldarg.1 + IL_0001: stloc.0 + IL_0002: ldloca.s V_0 + IL_0004: newobj "System.ReadOnlySpan..ctor(ref readonly char)" + IL_0009: ldarg.0 + IL_000a: call "System.ReadOnlySpan string.op_Implicit(string)" + IL_000f: ldarg.1 + IL_0010: stloc.1 + IL_0011: ldloca.s V_1 + IL_0013: newobj "System.ReadOnlySpan..ctor(ref readonly char)" + IL_0018: ldarg.0 + IL_0019: call "System.ReadOnlySpan string.op_Implicit(string)" + IL_001e: call "string string.Concat(System.ReadOnlySpan, System.ReadOnlySpan, System.ReadOnlySpan, System.ReadOnlySpan)" + IL_0023: ret + } + """); + + verifier.VerifyIL("Test.M6", """ + { + // Code size 36 (0x24) + .maxstack 4 + .locals init (char V_0, + char V_1) + IL_0000: ldarg.0 + IL_0001: call "System.ReadOnlySpan string.op_Implicit(string)" + IL_0006: ldarg.1 + IL_0007: stloc.0 + IL_0008: ldloca.s V_0 + IL_000a: newobj "System.ReadOnlySpan..ctor(ref readonly char)" + IL_000f: ldarg.0 + IL_0010: call "System.ReadOnlySpan string.op_Implicit(string)" + IL_0015: ldarg.1 + IL_0016: stloc.1 + IL_0017: ldloca.s V_1 + IL_0019: newobj "System.ReadOnlySpan..ctor(ref readonly char)" + IL_001e: call "string string.Concat(System.ReadOnlySpan, System.ReadOnlySpan, System.ReadOnlySpan, System.ReadOnlySpan)" + IL_0023: ret + } + """); + + verifier.VerifyIL("Test.M7", """ + { + // Code size 36 (0x24) + .maxstack 4 + .locals init (char V_0, + char V_1) + IL_0000: ldarg.1 + IL_0001: stloc.0 + IL_0002: ldloca.s V_0 + IL_0004: newobj "System.ReadOnlySpan..ctor(ref readonly char)" + IL_0009: ldarg.0 + IL_000a: call "System.ReadOnlySpan string.op_Implicit(string)" + IL_000f: ldarg.0 + IL_0010: call "System.ReadOnlySpan string.op_Implicit(string)" + IL_0015: ldarg.1 + IL_0016: stloc.1 + IL_0017: ldloca.s V_1 + IL_0019: newobj "System.ReadOnlySpan..ctor(ref readonly char)" + IL_001e: call "string string.Concat(System.ReadOnlySpan, System.ReadOnlySpan, System.ReadOnlySpan, System.ReadOnlySpan)" + IL_0023: ret + } + """); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/66827")] diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs index ce58d22354c8a..c96a7e29d4da4 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs @@ -1083,29 +1083,14 @@ static void G() {} Row(10, TableIndex.CustomAttribute, EditAndContinueOperation.Default),// add new row ]); - // https://github.com/dotnet/roslyn/issues/73513 - if (RuntimeUtilities.IsCoreClr9OrHigherRuntime) - { - g.VerifyCustomAttributes( - [ - new CustomAttributeRow(Handle(8, TableIndex.MethodDef), Handle(3, TableIndex.MethodDef)), - new CustomAttributeRow(Handle(8, TableIndex.MethodDef), Handle(5, TableIndex.MethodDef)), - new CustomAttributeRow(Handle(8, TableIndex.MethodDef), Handle(6, TableIndex.MethodDef)), - new CustomAttributeRow(Handle(10, TableIndex.MethodDef), Handle(4, TableIndex.MethodDef)), - new CustomAttributeRow(Handle(10, TableIndex.MethodDef), Handle(7, TableIndex.MethodDef)), - ]); - } - else - { - g.VerifyCustomAttributes( - [ - new CustomAttributeRow(Handle(8, TableIndex.MethodDef), Handle(3, TableIndex.MethodDef)), - new CustomAttributeRow(Handle(10, TableIndex.MethodDef), Handle(4, TableIndex.MethodDef)), - new CustomAttributeRow(Handle(8, TableIndex.MethodDef), Handle(5, TableIndex.MethodDef)), - new CustomAttributeRow(Handle(8, TableIndex.MethodDef), Handle(6, TableIndex.MethodDef)), - new CustomAttributeRow(Handle(10, TableIndex.MethodDef), Handle(7, TableIndex.MethodDef)), - ]); - } + g.VerifyCustomAttributes( + [ + new CustomAttributeRow(Handle(8, TableIndex.MethodDef), Handle(3, TableIndex.MethodDef)), + new CustomAttributeRow(Handle(8, TableIndex.MethodDef), Handle(5, TableIndex.MethodDef)), + new CustomAttributeRow(Handle(8, TableIndex.MethodDef), Handle(6, TableIndex.MethodDef)), + new CustomAttributeRow(Handle(10, TableIndex.MethodDef), Handle(4, TableIndex.MethodDef)), + new CustomAttributeRow(Handle(10, TableIndex.MethodDef), Handle(7, TableIndex.MethodDef)), + ]); }) .Verify(); } @@ -1484,32 +1469,15 @@ [A7]void H() { } Handle(9, TableIndex.CustomAttribute), ]); - // https://github.com/dotnet/roslyn/issues/73513 - if (RuntimeUtilities.IsCoreClr9OrHigherRuntime) - { - g.VerifyCustomAttributes( - [ - new CustomAttributeRow(Handle(0, TableIndex.MethodDef), Handle(0, TableIndex.MemberRef)), // F [A2] delete - new CustomAttributeRow(Handle(0, TableIndex.MethodDef), Handle(0, TableIndex.MemberRef)), // H [A5] delete - new CustomAttributeRow(Handle(9, TableIndex.MethodDef), Handle(2, TableIndex.MethodDef)), // F [A1] -> [A2] - new CustomAttributeRow(Handle(10, TableIndex.MethodDef), Handle(4, TableIndex.MethodDef)),// G [A3] -> [A4] - new CustomAttributeRow(Handle(10, TableIndex.MethodDef), Handle(3, TableIndex.MethodDef)),// G [A3] add with RowId 9 - new CustomAttributeRow(Handle(11, TableIndex.MethodDef), Handle(7, TableIndex.MethodDef)),// H [A6] -> [A7] - ]); - } - else - { - g.VerifyCustomAttributes( - [ - new CustomAttributeRow(Handle(9, TableIndex.MethodDef), Handle(2, TableIndex.MethodDef)), // F [A1] -> [A2] - new CustomAttributeRow(Handle(0, TableIndex.MethodDef), Handle(0, TableIndex.MemberRef)), // F [A2] delete - new CustomAttributeRow(Handle(10, TableIndex.MethodDef), Handle(4, TableIndex.MethodDef)),// G [A3] -> [A4] - new CustomAttributeRow(Handle(11, TableIndex.MethodDef), Handle(7, TableIndex.MethodDef)),// H [A6] -> [A7] - new CustomAttributeRow(Handle(0, TableIndex.MethodDef), Handle(0, TableIndex.MemberRef)), // H [A5] delete - new CustomAttributeRow(Handle(10, TableIndex.MethodDef), Handle(3, TableIndex.MethodDef)),// G [A3] add with RowId 9 - ]); - - } + g.VerifyCustomAttributes( + [ + new CustomAttributeRow(Handle(0, TableIndex.MethodDef), Handle(0, TableIndex.MemberRef)), // F [A2] delete + new CustomAttributeRow(Handle(0, TableIndex.MethodDef), Handle(0, TableIndex.MemberRef)), // H [A5] delete + new CustomAttributeRow(Handle(9, TableIndex.MethodDef), Handle(2, TableIndex.MethodDef)), // F [A1] -> [A2] + new CustomAttributeRow(Handle(10, TableIndex.MethodDef), Handle(4, TableIndex.MethodDef)),// G [A3] -> [A4] + new CustomAttributeRow(Handle(10, TableIndex.MethodDef), Handle(3, TableIndex.MethodDef)),// G [A3] add with RowId 9 + new CustomAttributeRow(Handle(11, TableIndex.MethodDef), Handle(7, TableIndex.MethodDef)),// H [A6] -> [A7] + ]); }) .AddGeneration( source: common + """ @@ -1551,32 +1519,15 @@ void G() { } Handle(11, TableIndex.CustomAttribute), ]); - // https://github.com/dotnet/roslyn/issues/73513 - if (RuntimeUtilities.IsCoreClr9OrHigherRuntime) - { - g.VerifyCustomAttributes( - [ - new CustomAttributeRow(Handle(0, TableIndex.MethodDef), Handle(0, TableIndex.MemberRef)), // G [A4] delete - new CustomAttributeRow(Handle(0, TableIndex.MethodDef), Handle(0, TableIndex.MemberRef)), // G [A3] delete - new CustomAttributeRow(Handle(11, TableIndex.MethodDef), Handle(5, TableIndex.MethodDef)), // H [A5] - new CustomAttributeRow(Handle(11, TableIndex.MethodDef), Handle(6, TableIndex.MethodDef)), // H [A6] - new CustomAttributeRow(Handle(11, TableIndex.MethodDef), Handle(7, TableIndex.MethodDef)), // H [A7] add with RowId 10 - new CustomAttributeRow(Handle(11, TableIndex.MethodDef), Handle(8, TableIndex.MethodDef)), // H [A8] add with RowId 11 - ]); - } - else - { - g.VerifyCustomAttributes( - [ - new CustomAttributeRow(Handle(0, TableIndex.MethodDef), Handle(0, TableIndex.MemberRef)), // G [A4] delete - new CustomAttributeRow(Handle(11, TableIndex.MethodDef), Handle(5, TableIndex.MethodDef)), // H [A5] - new CustomAttributeRow(Handle(11, TableIndex.MethodDef), Handle(6, TableIndex.MethodDef)), // H [A6] - new CustomAttributeRow(Handle(0, TableIndex.MethodDef), Handle(0, TableIndex.MemberRef)), // G [A3] delete - new CustomAttributeRow(Handle(11, TableIndex.MethodDef), Handle(7, TableIndex.MethodDef)), // H [A7] add with RowId 10 - new CustomAttributeRow(Handle(11, TableIndex.MethodDef), Handle(8, TableIndex.MethodDef)), // H [A8] add with RowId 11 - ]); - - } + g.VerifyCustomAttributes( + [ + new CustomAttributeRow(Handle(0, TableIndex.MethodDef), Handle(0, TableIndex.MemberRef)), // G [A4] delete + new CustomAttributeRow(Handle(0, TableIndex.MethodDef), Handle(0, TableIndex.MemberRef)), // G [A3] delete + new CustomAttributeRow(Handle(11, TableIndex.MethodDef), Handle(5, TableIndex.MethodDef)), // H [A5] + new CustomAttributeRow(Handle(11, TableIndex.MethodDef), Handle(6, TableIndex.MethodDef)), // H [A6] + new CustomAttributeRow(Handle(11, TableIndex.MethodDef), Handle(7, TableIndex.MethodDef)), // H [A7] add with RowId 10 + new CustomAttributeRow(Handle(11, TableIndex.MethodDef), Handle(8, TableIndex.MethodDef)), // H [A8] add with RowId 11 + ]); }) .AddGeneration( source: common + """ @@ -1744,23 +1695,11 @@ [A4] void G() { } Handle(5, TableIndex.CustomAttribute), ]); - // https://github.com/dotnet/roslyn/issues/73513 - if (RuntimeUtilities.IsCoreClr9OrHigherRuntime) - { - g.VerifyCustomAttributes( - [ - new CustomAttributeRow(Handle(5, TableIndex.MethodDef), Handle(3, TableIndex.MethodDef)), // G: [A2] -> [A4] - new CustomAttributeRow(Handle(6, TableIndex.MethodDef), Handle(4, TableIndex.MethodDef)), // F: [A1] -> [A3] - ]); - } - else - { - g.VerifyCustomAttributes( - [ - new CustomAttributeRow(Handle(6, TableIndex.MethodDef), Handle(4, TableIndex.MethodDef)), // F: [A1] -> [A3] - new CustomAttributeRow(Handle(5, TableIndex.MethodDef), Handle(3, TableIndex.MethodDef)), // G: [A2] -> [A4] - ]); - } + g.VerifyCustomAttributes( + [ + new CustomAttributeRow(Handle(5, TableIndex.MethodDef), Handle(3, TableIndex.MethodDef)), // G: [A2] -> [A4] + new CustomAttributeRow(Handle(6, TableIndex.MethodDef), Handle(4, TableIndex.MethodDef)), // F: [A1] -> [A3] + ]); }) .Verify(); } @@ -3251,23 +3190,15 @@ class C g.VerifyTypeDefNames("E", "C", "D"); g.VerifyMethodDefNames(); - // https://github.com/dotnet/roslyn/issues/73513 - if (RuntimeUtilities.IsCoreClr9OrHigherRuntime) - { - g.VerifyCustomAttributes( - [ - new CustomAttributeRow(Handle(1, TableIndex.Property), Handle(5, TableIndex.MethodDef)), // X - new CustomAttributeRow(Handle(2, TableIndex.Field), Handle(2, TableIndex.MethodDef)), // E.A - new CustomAttributeRow(Handle(3, TableIndex.Field), Handle(4, TableIndex.MethodDef)), // _x - new CustomAttributeRow(Handle(14, TableIndex.TypeDef), Handle(1, TableIndex.MethodDef)), // E - new CustomAttributeRow(Handle(15, TableIndex.TypeDef), Handle(3, TableIndex.MethodDef)), // C - new CustomAttributeRow(Handle(16, TableIndex.TypeDef), Handle(6, TableIndex.MethodDef)), // D - ]); - } - else - { - - } + g.VerifyCustomAttributes( + [ + new CustomAttributeRow(Handle(1, TableIndex.Property), Handle(5, TableIndex.MethodDef)), // X + new CustomAttributeRow(Handle(2, TableIndex.Field), Handle(2, TableIndex.MethodDef)), // E.A + new CustomAttributeRow(Handle(3, TableIndex.Field), Handle(4, TableIndex.MethodDef)), // _x + new CustomAttributeRow(Handle(14, TableIndex.TypeDef), Handle(1, TableIndex.MethodDef)), // E + new CustomAttributeRow(Handle(15, TableIndex.TypeDef), Handle(3, TableIndex.MethodDef)), // C + new CustomAttributeRow(Handle(16, TableIndex.TypeDef), Handle(6, TableIndex.MethodDef)), // D + ]); g.VerifyEncLogDefinitions( [ @@ -3340,31 +3271,15 @@ class C g.VerifyTypeDefNames("E", "C", "D"); g.VerifyMethodDefNames(); - // https://github.com/dotnet/roslyn/issues/73513 - if (RuntimeUtilities.IsCoreClr9OrHigherRuntime) - { - g.VerifyCustomAttributes( - [ - new CustomAttributeRow(Handle(1, TableIndex.Property), Handle(11, TableIndex.MethodDef)),// X - new CustomAttributeRow(Handle(2, TableIndex.Field), Handle(8, TableIndex.MethodDef)), // E.A - new CustomAttributeRow(Handle(3, TableIndex.Field), Handle(10, TableIndex.MethodDef)), // _x - new CustomAttributeRow(Handle(14, TableIndex.TypeDef), Handle(7, TableIndex.MethodDef)), // E - new CustomAttributeRow(Handle(15, TableIndex.TypeDef), Handle(9, TableIndex.MethodDef)), // C - new CustomAttributeRow(Handle(16, TableIndex.TypeDef), Handle(12, TableIndex.MethodDef)),// D - ]); - } - else - { - g.VerifyCustomAttributes( - [ - new CustomAttributeRow(Handle(14, TableIndex.TypeDef), Handle(7, TableIndex.MethodDef)), // E - new CustomAttributeRow(Handle(15, TableIndex.TypeDef), Handle(9, TableIndex.MethodDef)), // C - new CustomAttributeRow(Handle(16, TableIndex.TypeDef), Handle(12, TableIndex.MethodDef)),// D - new CustomAttributeRow(Handle(2, TableIndex.Field), Handle(8, TableIndex.MethodDef)), // E.A - new CustomAttributeRow(Handle(3, TableIndex.Field), Handle(10, TableIndex.MethodDef)), // _x - new CustomAttributeRow(Handle(1, TableIndex.Property), Handle(11, TableIndex.MethodDef)),// X - ]); - } + g.VerifyCustomAttributes( + [ + new CustomAttributeRow(Handle(1, TableIndex.Property), Handle(11, TableIndex.MethodDef)),// X + new CustomAttributeRow(Handle(2, TableIndex.Field), Handle(8, TableIndex.MethodDef)), // E.A + new CustomAttributeRow(Handle(3, TableIndex.Field), Handle(10, TableIndex.MethodDef)), // _x + new CustomAttributeRow(Handle(14, TableIndex.TypeDef), Handle(7, TableIndex.MethodDef)), // E + new CustomAttributeRow(Handle(15, TableIndex.TypeDef), Handle(9, TableIndex.MethodDef)), // C + new CustomAttributeRow(Handle(16, TableIndex.TypeDef), Handle(12, TableIndex.MethodDef)),// D + ]); g.VerifyEncLogDefinitions(new[] { @@ -6193,7 +6108,7 @@ void ValidateReplacedType(CompilationDifference diff, MetadataReader[] readers) Assert.Equal(generation, parentGeneration); Assert.Equal(newTypeDefHandle, parentHandle); - // attribute contructor should match + // attribute constructor should match var ctorHandle = aggregator.GetGenerationHandle(attribute.Constructor, out var ctorGeneration); Assert.Equal(0, ctorGeneration); Assert.Equal(attributeCtorDefHandle, ctorHandle); @@ -7459,33 +7374,16 @@ [B] static void M2<[A]T>() { } Handle(6, TableIndex.MethodSemantics), Handle(2, TableIndex.GenericParam)); - // https://github.com/dotnet/roslyn/issues/73513 - if (RuntimeUtilities.IsCoreClr9OrHigherRuntime) - { - CheckAttributes(reader1, - new CustomAttributeRow(Handle(1, TableIndex.GenericParam), Handle(1, TableIndex.MethodDef)), - new CustomAttributeRow(Handle(2, TableIndex.Property), Handle(2, TableIndex.MethodDef)), - new CustomAttributeRow(Handle(2, TableIndex.Event), Handle(1, TableIndex.MethodDef)), - new CustomAttributeRow(Handle(3, TableIndex.Field), Handle(1, TableIndex.MethodDef)), - new CustomAttributeRow(Handle(4, TableIndex.Field), Handle(11, TableIndex.MemberRef)), - new CustomAttributeRow(Handle(4, TableIndex.Field), Handle(12, TableIndex.MemberRef)), - new CustomAttributeRow(Handle(12, TableIndex.MethodDef), Handle(2, TableIndex.MethodDef)), - new CustomAttributeRow(Handle(14, TableIndex.MethodDef), Handle(11, TableIndex.MemberRef)), - new CustomAttributeRow(Handle(15, TableIndex.MethodDef), Handle(11, TableIndex.MemberRef))); - } - else - { - CheckAttributes(reader1, - new CustomAttributeRow(Handle(1, TableIndex.GenericParam), Handle(1, TableIndex.MethodDef)), - new CustomAttributeRow(Handle(3, TableIndex.Field), Handle(1, TableIndex.MethodDef)), - new CustomAttributeRow(Handle(4, TableIndex.Field), Handle(11, TableIndex.MemberRef)), - new CustomAttributeRow(Handle(4, TableIndex.Field), Handle(12, TableIndex.MemberRef)), - new CustomAttributeRow(Handle(12, TableIndex.MethodDef), Handle(2, TableIndex.MethodDef)), - new CustomAttributeRow(Handle(14, TableIndex.MethodDef), Handle(11, TableIndex.MemberRef)), - new CustomAttributeRow(Handle(15, TableIndex.MethodDef), Handle(11, TableIndex.MemberRef)), - new CustomAttributeRow(Handle(2, TableIndex.Event), Handle(1, TableIndex.MethodDef)), - new CustomAttributeRow(Handle(2, TableIndex.Property), Handle(2, TableIndex.MethodDef))); - } + CheckAttributes(reader1, + new CustomAttributeRow(Handle(1, TableIndex.GenericParam), Handle(1, TableIndex.MethodDef)), + new CustomAttributeRow(Handle(2, TableIndex.Property), Handle(2, TableIndex.MethodDef)), + new CustomAttributeRow(Handle(2, TableIndex.Event), Handle(1, TableIndex.MethodDef)), + new CustomAttributeRow(Handle(3, TableIndex.Field), Handle(1, TableIndex.MethodDef)), + new CustomAttributeRow(Handle(4, TableIndex.Field), Handle(11, TableIndex.MemberRef)), + new CustomAttributeRow(Handle(4, TableIndex.Field), Handle(12, TableIndex.MemberRef)), + new CustomAttributeRow(Handle(12, TableIndex.MethodDef), Handle(2, TableIndex.MethodDef)), + new CustomAttributeRow(Handle(14, TableIndex.MethodDef), Handle(11, TableIndex.MemberRef)), + new CustomAttributeRow(Handle(15, TableIndex.MethodDef), Handle(11, TableIndex.MemberRef))); } /// diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/LocalStateTracing/LocalStateTracingTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/LocalStateTracing/LocalStateTracingTests.cs index 899fc155bff31..861f246abcc58 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/LocalStateTracing/LocalStateTracingTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/LocalStateTracing/LocalStateTracingTests.cs @@ -3207,7 +3207,7 @@ .locals init (Microsoft.CodeAnalysis.Runtime.LocalStoreTracker V_0, } [Fact] - public void Initializers_NoContructorBody() + public void Initializers_NoConstructorBody() { var source = WithHelpers(@" var _ = new C(); diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/RuntimeProbing/ModuleCancellationTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/RuntimeProbing/ModuleCancellationTests.cs index 26c01cb91bcdd..6771a4eb4c05c 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/RuntimeProbing/ModuleCancellationTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/RuntimeProbing/ModuleCancellationTests.cs @@ -2783,4 +2783,28 @@ void G(T a, S b) {} var verifier = CompileAndVerify(source); AssertNotInstrumentedWithTokenLoad(verifier, "C.G(T, S, System.Threading.CancellationToken)"); } + + [Fact] + public void FlowPass() + { + var source = """ + using System.Threading; + using System.Collections.Generic; + + class C + { + IEnumerable F() + { + var x = G() as string; + yield return (x != null) ? 1 : 0; + } + + object G(CancellationToken token = default) + => ""; + } + """; + + // definite assignment flow pass doesn't fail + CompileAndVerify(source).VerifyDiagnostics(); + } } diff --git a/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests.cs index 620867a4028d8..80b439bf2dfdd 100644 --- a/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests.cs @@ -4879,12 +4879,14 @@ class C { } public void AttributeArgumentAsEnumFromMetadata() { var metadataStream1 = CSharpCompilation.Create("bar.dll", + options: TestOptions.DebugDll, references: new[] { MscorlibRef }, syntaxTrees: new[] { Parse("public enum Bar { Baz }") }).EmitToStream(options: new EmitOptions(metadataOnly: true)); var ref1 = MetadataReference.CreateFromStream(metadataStream1); var metadataStream2 = CSharpCompilation.Create("goo.dll", references: new[] { MscorlibRef, ref1 }, + options: TestOptions.DebugDll, syntaxTrees: new[] { SyntaxFactory.ParseSyntaxTree( "public class Ca : System.Attribute { public Ca(object o) { } } " + diff --git a/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_WellKnownAttributes.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_WellKnownAttributes.cs index d731b5cf5b410..cb4ef10c97def 100644 --- a/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_WellKnownAttributes.cs +++ b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_WellKnownAttributes.cs @@ -11311,6 +11311,45 @@ void local1() Assert.True(verifier.HasLocalsInit("C.g__local1|4_0")); } + [Theory] + [InlineData("[SkipLocalsInit]", "")] + [InlineData("", "[SkipLocalsInit]")] + public void SkipLocalsInit_PartialEventAccessor_ContainsLocalFunction(string defAttrs, string implAttrs) + { + // SkipLocalsInit applied to either part affects the event and nested functions + var source = $$""" + using System; + using System.Runtime.CompilerServices; + + public partial class C + { + {{defAttrs}} + partial event Action EventWithAttribute; + + {{implAttrs}} + partial event Action EventWithAttribute + { + add + { + int w = 1; + w = w + w + w + w; + + void local1() + { + int x = 1; + x = x + x + x + x; + } + } + remove { } + } + } + """; + + var verifier = CompileAndVerifyWithSkipLocalsInit(source); + Assert.False(verifier.HasLocalsInit("C.EventWithAttribute.add")); + Assert.False(verifier.HasLocalsInit("C.g__local1|0_0")); + } + [Fact] public void SkipLocalsInit_Class_ContainsLocalFunction() { diff --git a/src/Compilers/CSharp/Test/Emit3/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs b/src/Compilers/CSharp/Test/Emit3/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs index 971a72c210829..77f2542f3d244 100644 --- a/src/Compilers/CSharp/Test/Emit3/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs +++ b/src/Compilers/CSharp/Test/Emit3/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs @@ -36,6 +36,8 @@ public void DiagnosticAnalyzerAllInOne() missingSyntaxKinds.Add(SyntaxKind.CollectionExpression); missingSyntaxKinds.Add(SyntaxKind.ExpressionElement); missingSyntaxKinds.Add(SyntaxKind.SpreadElement); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Add to all-in-one + missingSyntaxKinds.Add(SyntaxKind.ExtensionDeclaration); var analyzer = new CSharpTrackingDiagnosticAnalyzer(); var options = new AnalyzerOptions(new[] { new TestAdditionalText() }.ToImmutableArray()); diff --git a/src/Compilers/CSharp/Test/Emit3/Diagnostics/GetDiagnosticsTests.cs b/src/Compilers/CSharp/Test/Emit3/Diagnostics/GetDiagnosticsTests.cs index da6e2ff2751c5..3a7a679a1ab01 100644 --- a/src/Compilers/CSharp/Test/Emit3/Diagnostics/GetDiagnosticsTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Diagnostics/GetDiagnosticsTests.cs @@ -175,7 +175,7 @@ private void NonPartialMethod2() { } Assert.True(eventQueue.Count > 0); bool compilationStartedFired; HashSet declaredSymbolNames, completedCompilationUnits; - Assert.True(DequeueCompilationEvents(eventQueue, out compilationStartedFired, out declaredSymbolNames, out completedCompilationUnits)); + Assert.True(DequeueCompilationEvents(eventQueue, out compilationStartedFired, out declaredSymbolNames, out _, out completedCompilationUnits)); // Verify symbol declared events fired for all symbols declared in the first source file. Assert.True(compilationStartedFired); @@ -224,7 +224,7 @@ partial void PartialMethod() { } Assert.True(eventQueue.Count > 0); bool compilationStartedFired; HashSet declaredSymbolNames, completedCompilationUnits; - Assert.True(DequeueCompilationEvents(eventQueue, out compilationStartedFired, out declaredSymbolNames, out completedCompilationUnits)); + Assert.True(DequeueCompilationEvents(eventQueue, out compilationStartedFired, out declaredSymbolNames, out _, out completedCompilationUnits)); // Verify symbol declared events fired for all symbols declared in the first source file. Assert.True(compilationStartedFired); @@ -276,7 +276,7 @@ partial class Class Assert.True(eventQueue.Count > 0); bool compilationStartedFired; HashSet declaredSymbolNames, completedCompilationUnits; - Assert.True(DequeueCompilationEvents(eventQueue, out compilationStartedFired, out declaredSymbolNames, out completedCompilationUnits)); + Assert.True(DequeueCompilationEvents(eventQueue, out compilationStartedFired, out declaredSymbolNames, out _, out completedCompilationUnits)); // Verify symbol declared events fired for all symbols declared in the first source file. Assert.True(compilationStartedFired); @@ -303,6 +303,130 @@ partial class Class AssertEx.Equal(["file1"], completedCompilationUnits.OrderBy(name => name)); } + [Fact] + public void TestCompilationEventsForPartialEvent() + { + var source1 = @" +namespace N1 +{ + partial class Class + { + event System.Action NonPartialEvent1 { add { } remove { } } + partial event System.Action DefOnlyPartialEvent; + partial event System.Action ImplOnlyPartialEvent { add { } remove { } } + partial event System.Action PartialEvent1; + partial event System.Action PartialEvent2 { add { } remove { } } + } +} +"; + var source2 = @" +namespace N1 +{ + partial class Class + { + event System.Action NonPartialEvent2 { add { } remove { } } + partial event System.Action PartialEvent1 { add { } remove { } } + partial event System.Action PartialEvent2; + } +} +"; + + var tree1 = CSharpSyntaxTree.ParseText(source1, path: "file1", options: TestOptions.RegularPreview); + var tree2 = CSharpSyntaxTree.ParseText(source2, path: "file2", options: TestOptions.RegularPreview); + var eventQueue = new AsyncQueue(); + var compilation = CreateCompilationWithMscorlib461(new[] { tree1, tree2 }).WithEventQueue(eventQueue); + + // Invoke SemanticModel.GetDiagnostics to force populate the event queue for symbols in the first source file. + var model = compilation.GetSemanticModel(tree1); + model.GetDiagnostics(tree1.GetRoot().FullSpan); + + Assert.True(eventQueue.Count > 0); + bool compilationStartedFired; + HashSet declaredSymbolNames, completedCompilationUnits; + Assert.True(DequeueCompilationEvents(eventQueue, out compilationStartedFired, out declaredSymbolNames, out _, out completedCompilationUnits)); + + // Verify symbol declared events fired for all symbols declared in the first source file. + Assert.True(compilationStartedFired); + + // NB: NonPartialEvent2 is missing here because we only asked for diagnostics in tree1. + // PartialEvent2 is missing because it is the implementation part and that is removed (only the definition part is kept). + AssertEx.Equal([ + "", + "add_ImplOnlyPartialEvent", + "add_NonPartialEvent1", + "add_PartialEvent1", + "Class", + "DefOnlyPartialEvent", + "ImplOnlyPartialEvent", + "N1", + "NonPartialEvent1", + "PartialEvent1", + "remove_ImplOnlyPartialEvent", + "remove_NonPartialEvent1", + "remove_PartialEvent1", + ], declaredSymbolNames.OrderBy(name => name)); + + AssertEx.Equal(["file1"], completedCompilationUnits.OrderBy(name => name)); + } + + [Fact] + public void TestCompilationEventsForPartialConstructor() + { + var source1 = @" +namespace N1 +{ + partial class Class + { + partial C(int a) { } // not partial 1 + partial C(int a, int b); // def only + partial C(int a, int b, int c) { } // impl only + partial C(int a, int b, int c, int d); // full partial with def first + partial C(int a, int b, int c, int d, int e) { } // full partial with impl first + } +} +"; + var source2 = @" +namespace N1 +{ + partial class Class + { + partial C(string a) { } // not partial 2 + partial C(int a, int b, int c, int d) { } // full partial with def first + partial C(int a, int b, int c, int d, int e); // full partial with impl first + } +} +"; + + var tree1 = CSharpSyntaxTree.ParseText(source1, path: "file1", options: TestOptions.RegularPreview); + var tree2 = CSharpSyntaxTree.ParseText(source2, path: "file2", options: TestOptions.RegularPreview); + var eventQueue = new AsyncQueue(); + var compilation = CreateCompilationWithMscorlib461(new[] { tree1, tree2 }).WithEventQueue(eventQueue); + + // Invoke SemanticModel.GetDiagnostics to force populate the event queue for symbols in the first source file. + var model = compilation.GetSemanticModel(tree1); + model.GetDiagnostics(tree1.GetRoot().FullSpan); + + Assert.True(eventQueue.Count > 0); + bool compilationStartedFired; + HashSet declaredSymbols, completedCompilationUnits; + Assert.True(DequeueCompilationEvents(eventQueue, out compilationStartedFired, out _, out declaredSymbols, out completedCompilationUnits)); + + // Verify symbol declared events fired for all symbols declared in the first source file. + Assert.True(compilationStartedFired); + + // NB: non partial 2 is missing here because we only asked for diagnostics in tree1 + AssertEx.Equal([ + "", + "N1", + "N1.Class", + "N1.Class..ctor(System.Int32 a)", + "N1.Class..ctor(System.Int32 a, System.Int32 b, System.Int32 c)", + "N1.Class..ctor(System.Int32 a, System.Int32 b, System.Int32 c, System.Int32 d)", + ], declaredSymbols.OrderBy(name => name, StringComparer.Ordinal)); + + AssertEx.Equal(["file1"], completedCompilationUnits.OrderBy(name => name)); + } + [Fact, WorkItem(8178, "https://github.com/dotnet/roslyn/issues/8178")] public void TestEarlyCancellation() { @@ -324,10 +448,11 @@ private void NonPartialMethod1() { } model.GetDiagnostics(tree.GetRoot().FullSpan); } - private static bool DequeueCompilationEvents(AsyncQueue eventQueue, out bool compilationStartedFired, out HashSet declaredSymbolNames, out HashSet completedCompilationUnits) + private static bool DequeueCompilationEvents(AsyncQueue eventQueue, out bool compilationStartedFired, out HashSet declaredSymbolNames, out HashSet declaredSymbols, out HashSet completedCompilationUnits) { compilationStartedFired = false; declaredSymbolNames = new HashSet(); + declaredSymbols = new HashSet(); completedCompilationUnits = new HashSet(); if (eventQueue.Count == 0) { @@ -348,7 +473,7 @@ private static bool DequeueCompilationEvents(AsyncQueue eventQ if (symbolDeclaredEvent != null) { var symbol = symbolDeclaredEvent.Symbol; - var added = declaredSymbolNames.Add(symbol.Name); + var added = declaredSymbolNames.Add(symbol.Name) & declaredSymbols.Add(symbol.ToTestDisplayString()); if (!added) { Assert.True(symbol.GetSymbol().IsPartialMember(), "Unexpected multiple symbol declared events for symbol " + symbol); diff --git a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs index d95d92200b540..4cf1db623c279 100644 --- a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs @@ -7,6 +7,7 @@ using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using System.Collections.Immutable; @@ -5604,16 +5605,13 @@ class C else { comp.VerifyEmitDiagnostics( - // (4,13): warning CS9264: Non-nullable property 'P1' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // (4,13): warning CS9264: Non-nullable property 'P1' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. // object P1 => field; Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "P1").WithArguments("property", "P1").WithLocation(4, 13), - // (5,13): warning CS9264: Non-nullable property 'P2' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // (5,13): warning CS9264: Non-nullable property 'P2' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. // object P2 { get => field; } Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "P2").WithArguments("property", "P2").WithLocation(5, 13), - // (6,13): warning CS9264: Non-nullable property 'P3' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. - // object P3 { set { field = value; } } - Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "P3").WithArguments("property", "P3").WithLocation(6, 13), - // (7,13): warning CS9264: Non-nullable property 'P4' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // (7,13): warning CS9264: Non-nullable property 'P4' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. // object P4 { get => field; set { field = value; } } Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "P4").WithArguments("property", "P4").WithLocation(7, 13)); } @@ -5635,7 +5633,7 @@ class C // (4,19): warning CS8602: Dereference of a possibly null reference. // string? P1 => field.ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "field").WithLocation(4, 19), - // (5,12): warning CS9264: Non-nullable property 'P2' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // (5,12): warning CS9264: Non-nullable property 'P2' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. // string P2 => field.ToString(); Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "P2").WithArguments("property", "P2").WithLocation(5, 12)); } @@ -5770,9 +5768,6 @@ class C // (8,51): warning CS8601: Possible null reference assignment. // object P5 { get; set { field = value; } } = MaybeNull(); Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "MaybeNull()").WithLocation(8, 51), - // (9,46): warning CS8601: Possible null reference assignment. - // object P6 { set { field = value; } } = MaybeNull(); - Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "MaybeNull()").WithLocation(9, 46), // (14,9): warning CS8602: Dereference of a possibly null reference. // P1.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "P1").WithLocation(14, 9), @@ -5848,7 +5843,7 @@ public C() { } var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (6,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // (6,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. // public C() { } Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "C").WithArguments("property", "Prop").WithLocation(6, 12)); } @@ -5868,7 +5863,7 @@ public C() { } var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (6,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // (6,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. // public C() { } Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "C").WithArguments("property", "Prop").WithLocation(6, 12)); } @@ -5930,7 +5925,7 @@ static C() { } var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (6,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // (6,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. // static C() { } Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "C").WithArguments("property", "Prop").WithLocation(6, 12)); } @@ -5950,7 +5945,7 @@ static C() { } var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (6,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // (6,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. // static C() { } Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "C").WithArguments("property", "Prop").WithLocation(6, 12)); } @@ -6196,22 +6191,16 @@ class C public string Prop { get => field; - set => field = null; // 1 + set => field = null; } - public C() // 2 + public C() { } } """; var comp = CreateCompilation([source, MaybeNullAttributeDefinition, AllowNullAttributeDefinition]); - comp.VerifyEmitDiagnostics( - // (10,24): warning CS8625: Cannot convert null literal to non-nullable reference type. - // set => field = null; // 1 - Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(10, 24), - // (12,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. - // public C() // 2 - Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "C").WithArguments("property", "Prop").WithLocation(12, 12)); + comp.VerifyEmitDiagnostics(); } [Fact] @@ -6242,7 +6231,7 @@ public C() // 2 // (10,24): warning CS8625: Cannot convert null literal to non-nullable reference type. // set => field = null; // 1 Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(10, 24), - // (12,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // (12,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. // public C() // 2 Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "C").WithArguments("property", "Prop").WithLocation(12, 12)); } @@ -6304,7 +6293,7 @@ public C() // 2 // (10,24): warning CS8601: Possible null reference assignment. // set => field = value; // 1 Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "value").WithLocation(10, 24), - // (12,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // (12,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. // public C() // 2 Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "C").WithArguments("property", "Prop").WithLocation(12, 12)); } @@ -6333,7 +6322,7 @@ public C() // 1 var comp = CreateCompilation([source, AllowNullAttributeDefinition]); comp.VerifyEmitDiagnostics( - // (11,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // (11,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. // public C() Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "C").WithArguments("property", "Prop").WithLocation(11, 12)); } @@ -6361,7 +6350,7 @@ public C() // 1 var comp = CreateCompilation([source, AllowNullAttributeDefinition]); comp.VerifyEmitDiagnostics( - // (11,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // (11,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. // public C() // 1 Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "C").WithArguments("property", "Prop").WithLocation(11, 12)); } @@ -6460,7 +6449,7 @@ public C() // 2 // (10,24): warning CS8601: Possible null reference assignment. // set => field = value; // 1 Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "value").WithLocation(10, 24), - // (12,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // (12,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. // public C() // 2 Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "C").WithArguments("property", "Prop").WithLocation(12, 12)); } @@ -6624,7 +6613,7 @@ class C var comp = CreateCompilation([source, NotNullAttributeDefinition]); comp.VerifyEmitDiagnostics( - // (7,20): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // (7,20): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. // public string? Prop { get; set => field = value; } Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "Prop").WithArguments("property", "Prop").WithLocation(7, 20)); } @@ -6646,7 +6635,7 @@ class C var comp = CreateCompilation([source, NotNullAttributeDefinition]); comp.VerifyEmitDiagnostics( - // (7,20): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // (7,20): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. // public string? Prop { get; set => field = value; } Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "Prop").WithArguments("property", "Prop").WithLocation(7, 20)); } @@ -6958,7 +6947,7 @@ public C() var comp = CreateCompilation([source, RequiredMemberAttribute, CompilerFeatureRequiredAttribute, SetsRequiredMembersAttribute]); comp.VerifyEmitDiagnostics( - // (9,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // (9,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. // public C() Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "C").WithArguments("property", "Prop").WithLocation(9, 12)); } @@ -7194,10 +7183,7 @@ class C """; var comp = CreateCompilation([source, MaybeNullAttributeDefinition, AllowNullAttributeDefinition]); - comp.VerifyEmitDiagnostics( - // (6,19): warning CS9264: Non-nullable property 'Prop1' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. - // public string Prop1 => field ??= "a"; // 1 - Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "Prop1").WithArguments("property", "Prop1").WithLocation(6, 19)); + comp.VerifyEmitDiagnostics(); } // Based on NullableReferenceTypesTests.NotNull_Property_WithAssignment @@ -7347,83 +7333,83 @@ class C T P1 { get => field; - } = default; // 1 + } = default; [AllowNull] T P2 { get => field; - } = default; // 2 + } = default; // 1 [MaybeNull, AllowNull] T P3 { get => field; - } = default; // 3 + } = default; [MaybeNull] T P4 { get => field; set => field = value; - } = default; // 4 + } = default; [AllowNull] T P5 { get => field; - set => field = value; // 5 - } = default; // 6 + set => field = value; // 2 + } = default; // 3 [MaybeNull, AllowNull] T P6 { get => field; - set => field = value; // 7 - } = default; // 8 + set => field = value; + } = default; C([AllowNull]T t) { - P1 = t; // 9 - P2 = t; + P1 = t; + P2 = t; // 4 P3 = t; - P4 = t; // 10 + P4 = t; // 5 P5 = t; P6 = t; } }"; var comp = CreateCompilation(new[] { source, AllowNullAttributeDefinition, MaybeNullAttributeDefinition }); comp.VerifyDiagnostics( - // 0.cs(9,9): warning CS8601: Possible null reference assignment. - // } = default; // 1 - Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "default").WithLocation(9, 9), // 0.cs(15,9): warning CS8601: Possible null reference assignment. - // } = default; // 2 + // } = default; // 1 Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "default").WithLocation(15, 9), - // 0.cs(21,9): warning CS8601: Possible null reference assignment. - // } = default; // 3 - Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "default").WithLocation(21, 9), - // 0.cs(28,9): warning CS8601: Possible null reference assignment. - // } = default; // 4 - Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "default").WithLocation(28, 9), // 0.cs(34,24): warning CS8601: Possible null reference assignment. - // set => field = value; // 5 + // set => field = value; // 2 Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "value").WithLocation(34, 24), // 0.cs(35,9): warning CS8601: Possible null reference assignment. - // } = default; // 6 + // } = default; // 3 Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "default").WithLocation(35, 9), - // 0.cs(41,24): warning CS8601: Possible null reference assignment. - // set => field = value; // 7 - Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "value").WithLocation(41, 24), - // 0.cs(42,9): warning CS8601: Possible null reference assignment. - // } = default; // 8 - Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "default").WithLocation(42, 9), - // 0.cs(46,14): warning CS8601: Possible null reference assignment. - // P1 = t; // 9 - Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "t").WithLocation(46, 14), + // 0.cs(47,14): warning CS8601: Possible null reference assignment. + // P2 = t; // 4 + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "t").WithLocation(47, 14), // 0.cs(49,14): warning CS8601: Possible null reference assignment. - // P4 = t; // 10 - Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "t").WithLocation(49, 14)); + // P4 = t; // 5 + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "t").WithLocation(49, 14) + ); + + var classC = comp.GetMember("C"); + verify(classC.GetMember("k__BackingField"), NullableAnnotation.Annotated); + verify(classC.GetMember("k__BackingField"), NullableAnnotation.NotAnnotated); + verify(classC.GetMember("k__BackingField"), NullableAnnotation.Annotated); + verify(classC.GetMember("k__BackingField"), NullableAnnotation.Annotated); + verify(classC.GetMember("k__BackingField"), NullableAnnotation.NotAnnotated); + verify(classC.GetMember("k__BackingField"), NullableAnnotation.Annotated); + + void verify(SynthesizedBackingFieldSymbol field, NullableAnnotation expectedInferredAnnotation) + { + Assert.Equal(NullableAnnotation.NotAnnotated, field.TypeWithAnnotations.NullableAnnotation); + Assert.Equal(expectedInferredAnnotation, field.GetInferredNullableAnnotation()); + } } // Based on RequiredMembersTests.RequiredMemberSuppressesNullabilityWarnings_ChainedConstructor_01. @@ -7476,7 +7462,7 @@ class C else { comp.VerifyEmitDiagnostics( - // (8,5): warning CS9264: Non-nullable property 'P2' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // (8,5): warning CS9264: Non-nullable property 'P2' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. // C(bool unused) { } Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "C").WithArguments("property", "P2").WithLocation(8, 5), // (8,5): warning CS8618: Non-nullable property 'P1' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. @@ -7531,10 +7517,10 @@ class C else { comp.VerifyEmitDiagnostics( - // (9,5): warning CS9264: Non-nullable property 'P5' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // (9,5): warning CS9264: Non-nullable property 'P5' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. // C(bool unused) { } Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "C").WithArguments("property", "P5").WithLocation(9, 5), - // (9,5): warning CS9264: Non-nullable property 'P6' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // (9,5): warning CS9264: Non-nullable property 'P6' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. // C(bool unused) { } Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "C").WithArguments("property", "P6").WithLocation(9, 5), // (9,5): warning CS8618: Non-nullable property 'P4' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. @@ -10737,5 +10723,1413 @@ struct S var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics(); } + + [Fact] + public void Nullable_NotResilient_NotInitialized_01() + { + var source = """ + #nullable enable + class C + { + public string Prop { get => field; set => field = value; } // 1 + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (4,19): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. + // public string Prop { get => field; set => field = value; } // 1 + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "Prop").WithArguments("property", "Prop").WithLocation(4, 19)); + + var prop = comp.GetMember("C.Prop"); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Nullable_NotResilient_NotInitialized_02() + { + var source = """ + #nullable enable + class C + { + public string Prop => field.ToString() ?? "a"; + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (4,19): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. + // public string Prop => field.ToString() ?? "a"; + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "Prop").WithArguments("property", "Prop").WithLocation(4, 19)); + + var prop = comp.GetMember("C.Prop"); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Nullable_Resilient_NotInitialized_03() + { + var source = """ + #nullable enable + class C + { + public string Prop + { + get + { + string unrelated = null; + return field ??= "a"; + } + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (8,20): warning CS0219: The variable 'unrelated' is assigned but its value is never used + // string unrelated = null; + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "unrelated").WithArguments("unrelated").WithLocation(8, 20), + // (8,32): warning CS8600: Converting null literal or possible null value to non-nullable type. + // string unrelated = null; + Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "null").WithLocation(8, 32)); + + var prop = comp.GetMember("C.Prop"); + Assert.Equal(NullableAnnotation.Annotated, prop.BackingField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Nullable_Getter_DifferentWarningsOccurWithEitherNullability() + { + var source = """ + #nullable enable + using System.Collections.Generic; + + class C + { + public string Prop + { + get + { + var list = M(field); + List li1 = list; + List li2 = list; + return field; + } + } + + static List M(T elem) => [elem]; + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (6,19): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. + // public string Prop + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "Prop").WithArguments("property", "Prop").WithLocation(6, 19), + // (12,33): warning CS8619: Nullability of reference types in value of type 'List' doesn't match target type 'List'. + // List li2 = list; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "list").WithArguments("System.Collections.Generic.List", "System.Collections.Generic.List").WithLocation(12, 33)); + } + + [Fact] + public void NullResilience_GetterDoesNotUseField() + { + var source = """ + #nullable enable + + class C + { + public string Prop { get => "a"; set => field = value; } + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (5,26): warning CS9266: The 'get' accessor of property 'C.Prop' should use 'field' because the other accessor is using it. + // public string Prop { get => "a"; set => field = value; } + Diagnostic(ErrorCode.WRN_AccessorDoesNotUseBackingField, "get").WithArguments("get", "C.Prop").WithLocation(5, 26)); + + var field = comp.GetMember("C.k__BackingField"); + + // We could further scope this by saying: do not infer if the getter specifically doesn't use 'field', + // regardless of whether the setter uses it, and perhaps skip some additional work. + // However, this is considered a pathological case. + Assert.True(field.InfersNullableAnnotation); + Assert.Equal(NullableAnnotation.Annotated, field.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, field.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Nullable_NotResilient_Initialized_01() + { + var source = """ + #nullable enable + class C + { + public string Prop { get => field; set => field = value; } = "a"; + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + + var prop = comp.GetMember("C.Prop"); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Nullable_NotResilient_Initialized_02() + { + var source = """ + #nullable enable + class C + { + public C() { Prop = "a"; } + public string Prop { get => field; set => field = value; } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + + var prop = comp.GetMember("C.Prop"); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.TypeWithAnnotations.NullableAnnotation); + } + + [Theory] + [InlineData("??=")] + [InlineData("??")] + public void Nullable_Resilient_NotInitialized_01(string op) + { + var source = $$""" + #nullable enable + class C + { + public string Prop => field {{op}} "a"; + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + + var prop = comp.GetMember("C.Prop"); + Assert.Equal(NullableAnnotation.Annotated, prop.BackingField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Nullable_Resilient_Initialized_01() + { + var source = """ + #nullable enable + class C + { + public string Prop { get => field ??= "a"; } = "b"; + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + + var prop = comp.GetMember("C.Prop"); + Assert.Equal(NullableAnnotation.Annotated, prop.BackingField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Nullable_Resilient_Initialized_02() + { + var source = """ + #nullable enable + class C + { + public C() { Prop = "b"; } + public string Prop { get => field ?? "a"; } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + + var prop = comp.GetMember("C.Prop"); + Assert.Equal(NullableAnnotation.Annotated, prop.BackingField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Nullable_Resilient_Initialized_03() + { + var source = """ + #nullable enable + class C + { + public C() + { + Prop = null; + } + + public string Prop { get => field ??= "a"; } = null; + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + + var prop = comp.GetMember("C.Prop"); + Assert.Equal(NullableAnnotation.Annotated, prop.BackingField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Nullable_Resilient_Initialized_04() + { + // This case is a bit funky. The inference does not affect signature of the setter. + // In general, we don't want an inference to affect shape of a public API. + // But, it's conceivable to want to assign a possible null value here, which gets further coalesced into a non-null in the getter. + var source = """ + #nullable enable + class C + { + public C() + { + Prop = null; // 1 + } + + public string Prop { get => field ??= "a"; set; } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (6,16): warning CS8625: Cannot convert null literal to non-nullable reference type. + // Prop = null; // 1 + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(6, 16)); + + var prop = comp.GetMember("C.Prop"); + Assert.Equal(NullableAnnotation.Annotated, prop.BackingField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Nullable_Resilient_Initialized_05() + { + // Suggested fix for the nullable warning in Nullable_Resilient_Initialized_04 + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + public C() + { + Prop = null; + } + + [AllowNull] + public string Prop { get => field ??= "a"; set; } + } + """; + + var comp = CreateCompilation([source, AllowNullAttributeDefinition]); + comp.VerifyEmitDiagnostics(); + + var prop = comp.GetMember("C.Prop"); + Assert.Equal(NullableAnnotation.Annotated, prop.BackingField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Nullable_Resilient_UseInSetter_01() + { + var source = """ + #nullable enable + + class C + { + public string Prop + { + get => field ??= "a"; + set => field = field.ToString(); + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (8,24): warning CS8602: Dereference of a possibly null reference. + // set => field = field.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "field").WithLocation(8, 24)); + + var prop = comp.GetMember("C.Prop"); + Assert.Equal(NullableAnnotation.Annotated, prop.BackingField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Nullable_Resilient_UseInSetter_02() + { + var source = """ + #nullable enable + + class C + { + public string Prop + { + get => field ??= "a"; + set => field = null; + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + + var prop = comp.GetMember("C.Prop"); + Assert.Equal(NullableAnnotation.Annotated, prop.BackingField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Nullable_Resilient_NotNullProperty_01() + { + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [NotNull] + public string? Prop + { + get => field ??= "a"; + set => field = null; + } + } + """; + + var comp = CreateCompilation([source, NotNullAttributeDefinition]); + comp.VerifyEmitDiagnostics(); + + var prop = comp.GetMember("C.Prop"); + Assert.False(prop.BackingField.InfersNullableAnnotation); + Assert.Equal(NullableAnnotation.Annotated, prop.BackingField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Nullable_Resilient_NotNullProperty_02() + { + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [NotNull] + public T Prop + { + get => field ??= default!; + set => field = default; + } + } + """; + + var comp = CreateCompilation([source, NotNullAttributeDefinition]); + comp.VerifyEmitDiagnostics(); + + var prop = comp.GetMember("C.Prop"); + Assert.Equal(NullableAnnotation.Annotated, prop.BackingField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Nullable_Resilient_NotNullProperty_03() + { + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C(T fallback) + { + [NotNull] + public T Prop + { + get => field ??= fallback; + set => field = default; + } + } + """; + + var comp = CreateCompilation([source, NotNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (9,16): warning CS8607: A possible null value may not be used for a type marked with [NotNull] or [DisallowNull] + // get => field ??= fallback; + Diagnostic(ErrorCode.WRN_DisallowNullAttributeForbidsMaybeNullAssignment, "field ??= fallback").WithLocation(9, 16)); + + var prop = comp.GetMember("C.Prop"); + Assert.Equal(NullableAnnotation.Annotated, prop.BackingField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Nullable_Resilient_Generic_01() + { + var source = """ + #nullable enable + + class C(T fallback) + { + public T Prop + { + get => field ??= fallback; + set => field = default; + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + + var prop = comp.GetMember("C.Prop"); + Assert.Equal(NullableAnnotation.Annotated, prop.BackingField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Nullable_NotResilient_Generic_01() + { + var source = """ + #nullable enable + + class C + { + public T Prop + { + get => field; + set => field = value; + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (5,14): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. + // public T Prop + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "Prop").WithArguments("property", "Prop").WithLocation(5, 14)); + + var prop = comp.GetMember("C.Prop"); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Nullable_NotResilient_UseInSetter_01() + { + // Setter analysis is not yet implemented. + // https://github.com/dotnet/roslyn/issues/77215 + var source = """ + #nullable enable + + class C + { + public string Prop + { + get => field; + set => field = field.ToString(); + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (5,19): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. + // public string Prop + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "Prop").WithArguments("property", "Prop").WithLocation(5, 19)); + + var prop = comp.GetMember("C.Prop"); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Nullable_NotResilient_UseInSetter_02() + { + var source = """ + #nullable enable + + class C + { + public string Prop + { + get => field; + set => field = null; + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (5,19): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. + // public string Prop + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "Prop").WithArguments("property", "Prop").WithLocation(5, 19), + // (8,24): warning CS8625: Cannot convert null literal to non-nullable reference type. + // set => field = null; + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(8, 24)); + + var prop = comp.GetMember("C.Prop"); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.TypeWithAnnotations.NullableAnnotation); + } + + [Theory] + [InlineData("#nullable disable")] + [InlineData("#nullable disable warnings")] + [InlineData("#pragma warning disable 8603 // Possible null reference return.")] + public void Nullable_NotResilient_AccessorWarningsAreDisabled_01(string directive) + { + var source = $$""" + #nullable enable + + class C + { + public string Prop + { + {{directive}} + get => field; + set => field = null; + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + + var prop = comp.GetMember("C.Prop"); + Assert.Equal(NullableAnnotation.Annotated, prop.BackingField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.TypeWithAnnotations.NullableAnnotation); + } + + [Theory] + [InlineData("#nullable disable")] + [InlineData("#nullable disable warnings")] + [InlineData("#pragma warning disable")] + [InlineData("#pragma warning disable 8603 // Possible null reference return.")] + public void Nullable_Resilient_ChainedConstructor_01(string directive) + { + // Since the backing field is nullable, a chained constructor isn't expected to put it into non-null state. + // The property has maybe-null state in "caller" constructor since it shares a slot with the field. + var source = $$""" + #nullable enable + + class C + { + public C(bool ignored) { Prop = "a"; } + public C() : this(false) + { + Prop.ToString(); // 1 + } + + public string Prop + { + {{directive}} + get => field; + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (8,9): warning CS8602: Dereference of a possibly null reference. + // Prop.ToString(); // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Prop").WithLocation(8, 9)); + + var prop = comp.GetMember("C.Prop"); + Assert.Equal(NullableAnnotation.Annotated, prop.BackingField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Nullable_Resilient_ChainedConstructor_02() + { + var source = $$""" + #nullable enable + + class C + { + public C(bool ignored) { Prop = "a"; } + public C() : this(false) + { + Prop.ToString(); // 1 + } + + public string Prop + { + get => field!; + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (8,9): warning CS8602: Dereference of a possibly null reference. + // Prop.ToString(); // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Prop").WithLocation(8, 9)); + + var prop = comp.GetMember("C.Prop"); + Assert.Equal(NullableAnnotation.Annotated, prop.BackingField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Nullable_Explicit_ChainedConstructor_01() + { + // Behavior is consistent with inferred nullable backing field compared with explicitly attributed backing field. + var source = $$""" + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + public C(bool ignored) { Prop = "a"; } + public C() : this(false) + { + Prop.ToString(); // 1 + } + + [field: MaybeNull] + public string Prop + { + get => field!; + } + } + """; + + var comp = CreateCompilation([source, MaybeNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (9,9): warning CS8602: Dereference of a possibly null reference. + // Prop.ToString(); // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Prop").WithLocation(9, 9)); + + var prop = comp.GetMember("C.Prop"); + Assert.False(prop.BackingField.InfersNullableAnnotation); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Nullable_NotResilient_ChainedConstructor_01() + { + // Backing field is non-nullable, so chaining a constructor puts it into non-null state. + var source = $$""" + #nullable enable + + class C + { + public C(bool ignored) { Prop = "a"; } + public C() : this(false) + { + Prop.ToString(); + } + + public string Prop + { + get => field; + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + + var prop = comp.GetMember("C.Prop"); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Nullable_Resilient_NullForgivingOperator() + { + var source = """ + #nullable enable + + class C + { + public string Prop + { + get => field!; + set => field = null; + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + + var prop = comp.GetMember("C.Prop"); + Assert.Equal(NullableAnnotation.Annotated, prop.BackingField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.TypeWithAnnotations.NullableAnnotation); + } + + [Theory] + [CombinatorialData] + public void Nullable_NotResilient_DiagnosticSuppressor(bool useSuppressor) + { + // DiagnosticSuppressors don't affect the inferred nullability of the backing field. + var source = """ + #nullable enable + + class C + { + public string Prop + { + get => field; + set => field = null; + } + } + """; + + var comp = CreateCompilation(source); + if (useSuppressor) + { + // The 8603 is a "hypothetical" diagnostic which occurs only internally in the compiler. + // We don't run DiagnosticSuppressors in that context. + // So, it's not clear that this suppressor would ever do anything. + // Still, it seems useful to express our intent with this test, that DiagnosticSuppressors don't have an effect. + comp = comp.VerifySuppressedDiagnostics( + [new CommonDiagnosticAnalyzers.DiagnosticSuppressorForId("CS8603"), new CommonDiagnosticAnalyzers.DiagnosticSuppressorForId("CS8625")], + expected: [Diagnostic("CS8625", "null", isSuppressed: true).WithLocation(8, 24)]); + } + + comp.VerifyEmitDiagnostics( + // (5,19): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. + // public string Prop + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "Prop").WithArguments("property", "Prop").WithLocation(5, 19), + // (8,24): warning CS8625: Cannot convert null literal to non-nullable reference type. + // set => field = null; + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(8, 24)); + var prop = comp.GetMember("C.Prop"); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, prop.BackingField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Nullable_Resilient_AnnotationInMetadata() + { + // Inferred nullability is not used in metadata. + var source = """ + #nullable enable + + class C + { + public string Prop + { + get => field ??= "a"; + } + } + """; + + var comp0 = CreateCompilation(source); + comp0.VerifyEmitDiagnostics(); + var sourceField = comp0.GetMember("C.k__BackingField"); + Assert.True(sourceField.InfersNullableAnnotation); + Assert.Equal(NullableAnnotation.NotAnnotated, sourceField.TypeWithAnnotations.NullableAnnotation); + Assert.Equal(NullableAnnotation.Annotated, sourceField.GetInferredNullableAnnotation()); + + var comp1 = CreateCompilation("", references: [comp0.EmitToImageReference()], options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + var metadataField = comp1.GetMember("C.k__BackingField"); + Assert.Equal(NullableAnnotation.NotAnnotated, metadataField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Nullable_DisallowNullField_NullableValueType() + { + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + public C() + { + Prop = null; // 1 + Prop = 0; + } + + [field: DisallowNull] + public int? Prop + { + get => field; + } + } + """; + + var comp0 = CreateCompilation([source, DisallowNullAttributeDefinition]); + comp0.VerifyEmitDiagnostics( + // (8,16): warning CS8607: A possible null value may not be used for a type marked with [NotNull] or [DisallowNull] + // Prop = null; // 1 + Diagnostic(ErrorCode.WRN_DisallowNullAttributeForbidsMaybeNullAssignment, "null").WithLocation(8, 16)); + + var sourceField = comp0.GetMember("C.k__BackingField"); + Assert.False(sourceField.InfersNullableAnnotation); + Assert.Equal(NullableAnnotation.Annotated, sourceField.TypeWithAnnotations.NullableAnnotation); + Assert.Equal("System.Int32?", sourceField.TypeWithAnnotations.ToTestDisplayString()); + } + + [Fact] + public void NullableWarningOnFieldInBothCases() + { + var source = """ + #nullable enable + + class C + { + public C() + { + Prop = null; + } + + public string Prop + { + get + { + field = null; + field.ToString(); // 1 + return "a"; + } + } + } + """; + + var comp0 = CreateCompilation(source); + comp0.VerifyEmitDiagnostics( + // (15,13): warning CS8602: Dereference of a possibly null reference. + // field.ToString(); // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "field").WithLocation(15, 13)); + + var sourceField = comp0.GetMember("C.k__BackingField"); + Assert.True(sourceField.InfersNullableAnnotation); + Assert.Equal(NullableAnnotation.Annotated, sourceField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, sourceField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void StaticPropAndConstructor_Resilient_01() + { + var source = """ + #nullable enable + + class C + { + public static string Prop => field ?? "a"; + } + """; + + var comp0 = CreateCompilation(source); + comp0.VerifyEmitDiagnostics(); + + var sourceField = comp0.GetMember("C.k__BackingField"); + Assert.True(sourceField.InfersNullableAnnotation); + Assert.Equal(NullableAnnotation.Annotated, sourceField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, sourceField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void StaticPropAndConstructor_NotResilient_01() + { + var source = """ + #nullable enable + + class C + { + public static string Prop => field; + } + """; + + var comp0 = CreateCompilation(source); + comp0.VerifyEmitDiagnostics( + // (5,26): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. + // public static string Prop => field; + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "Prop").WithArguments("property", "Prop").WithLocation(5, 26)); + + var sourceField = comp0.GetMember("C.k__BackingField"); + Assert.True(sourceField.InfersNullableAnnotation); + Assert.Equal(NullableAnnotation.NotAnnotated, sourceField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, sourceField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void StaticPropAndConstructor_NotResilient_02() + { + var source = """ + #nullable enable + + class C + { + static C() + { + Prop = "a"; + } + public static string Prop => field; + } + """; + + var comp0 = CreateCompilation(source); + comp0.VerifyEmitDiagnostics(); + + var sourceField = comp0.GetMember("C.k__BackingField"); + Assert.True(sourceField.InfersNullableAnnotation); + Assert.Equal(NullableAnnotation.NotAnnotated, sourceField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, sourceField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void StaticPropAndConstructor_NotResilient_03() + { + var source = """ + #nullable enable + + class C + { + public static string Prop { get => field; } = "a"; + } + """; + + var comp0 = CreateCompilation(source); + comp0.VerifyEmitDiagnostics(); + + var sourceField = comp0.GetMember("C.k__BackingField"); + Assert.True(sourceField.InfersNullableAnnotation); + Assert.Equal(NullableAnnotation.NotAnnotated, sourceField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, sourceField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Ref_NotResilient_01() + { + var source = """ + #nullable enable + + class C + { + public static void M(ref string s) { } + public string Prop // 1 + { + get + { + M(ref field); + return field; + } + } + } + """; + + var comp0 = CreateCompilation(source); + comp0.VerifyEmitDiagnostics( + // (6,19): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. + // public string Prop // 1 + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "Prop").WithArguments("property", "Prop").WithLocation(6, 19)); + + var sourceField = comp0.GetMember("C.k__BackingField"); + Assert.True(sourceField.InfersNullableAnnotation); + Assert.Equal(NullableAnnotation.NotAnnotated, sourceField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, sourceField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Ref_Resilient_01() + { + // "Resilient" in the sense that same warnings occur whether field is nullable or not. + var source = """ + #nullable enable + + class C + { + public static void M(ref string? s) { } + public string Prop + { + get + { + M(ref field); + return field; // 1 + } + } + } + """; + + var comp0 = CreateCompilation(source); + comp0.VerifyEmitDiagnostics( + // (11,20): warning CS8603: Possible null reference return. + // return field; // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "field").WithLocation(11, 20)); + + var sourceField = comp0.GetMember("C.k__BackingField"); + Assert.True(sourceField.InfersNullableAnnotation); + Assert.Equal(NullableAnnotation.Annotated, sourceField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, sourceField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Ref_Resilient_02() + { + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + public static void M([NotNull] ref string? s) { s = "a"; } + public string Prop + { + get + { + M(ref field); + return field; + } + } + } + """; + + var comp0 = CreateCompilation([source, NotNullAttributeDefinition]); + comp0.VerifyEmitDiagnostics(); + + var sourceField = comp0.GetMember("C.k__BackingField"); + Assert.True(sourceField.InfersNullableAnnotation); + Assert.Equal(NullableAnnotation.Annotated, sourceField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, sourceField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Ref_Resilient_03() + { + // This is an interesting case. + // Diagnostic (1) is reported the same way in both cases, but they actually refer to different things. + // For the 'string? field' case, it refers to the assignment of 'field' to 'ref string s' on the way in. + // For the 'string field' case, it refers to the '[MaybeNull]' assignment to 'field' on the way out. + + // This is something that might be simplified by saying null-resilience decides initial flow state rather than annotation. + // Then, maybe-null going into the field would not produce a warning in both cases. + // We would then conclude that the property is not-null-resilient, due to the 'M(ref field)' call resulting in a warning only when initial state is maybe-null. + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + public static void M([MaybeNull] ref string s) { } + public string Prop + { + get + { + M(ref field); // 1 + return field; // 2 + } + } + } + """; + var comp0 = CreateCompilation([source, MaybeNullAttributeDefinition]); + comp0.VerifyEmitDiagnostics( + // (11,19): warning CS8601: Possible null reference assignment. + // M(ref field); // 1 + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "field").WithLocation(11, 19), + // (12,20): warning CS8603: Possible null reference return. + // return field; // 2 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "field").WithLocation(12, 20)); + + var sourceField = comp0.GetMember("C.k__BackingField"); + Assert.True(sourceField.InfersNullableAnnotation); + Assert.Equal(NullableAnnotation.Annotated, sourceField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, sourceField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void LocalFunction_NullResilience_01() + { + // Is null-resilient + var source = """ + #nullable enable + + class C + { + public string Prop + { + get + { + return local(); + string local() => field ?? "a"; + } + } + } + """; + + var comp0 = CreateCompilation(source); + comp0.VerifyEmitDiagnostics(); + + var sourceField = comp0.GetMember("C.k__BackingField"); + Assert.True(sourceField.InfersNullableAnnotation); + Assert.Equal(NullableAnnotation.Annotated, sourceField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, sourceField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void LocalFunction_NullResilient_02() + { + // Not null-resilient + var source = """ + #nullable enable + + class C + { + public string Prop // 1 + { + get + { + return local(); + string local() => field; + } + } + } + """; + + var comp0 = CreateCompilation(source); + comp0.VerifyEmitDiagnostics( + // (5,19): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. + // public string Prop // 1 + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "Prop").WithArguments("property", "Prop").WithLocation(5, 19)); + + var sourceField = comp0.GetMember("C.k__BackingField"); + Assert.True(sourceField.InfersNullableAnnotation); + Assert.Equal(NullableAnnotation.NotAnnotated, sourceField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, sourceField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void LocalFunction_NullResilient_03() + { + // Local function is not called, but, the warning in the local function only occurs when field is nullable. + var source = """ + #nullable enable + + class C + { + public string Prop // 1 + { + get + { + return field ?? "a"; + void local() => field.ToString(); // 2 + } + } + } + """; + + var comp0 = CreateCompilation(source); + comp0.VerifyEmitDiagnostics( + // (5,19): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. + // public string Prop // 1 + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "Prop").WithArguments("property", "Prop").WithLocation(5, 19), + // (10,18): warning CS8321: The local function 'local' is declared but never used + // void local() => field.ToString(); // 2 + Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "local").WithArguments("local").WithLocation(10, 18)); + + var sourceField = comp0.GetMember("C.k__BackingField"); + Assert.True(sourceField.InfersNullableAnnotation); + Assert.Equal(NullableAnnotation.NotAnnotated, sourceField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, sourceField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void LocalFunction_NullResilience_04() + { + // Is null-resilient + var source = """ + #nullable enable + + class C + { + public string Prop + { + get + { + field ??= "a"; + local(); + return field; + void local() => field.ToString(); + } + } + } + """; + + var comp0 = CreateCompilation(source); + comp0.VerifyEmitDiagnostics(); + + var sourceField = comp0.GetMember("C.k__BackingField"); + Assert.True(sourceField.InfersNullableAnnotation); + Assert.Equal(NullableAnnotation.Annotated, sourceField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, sourceField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void LocalFunction_NullResilience_05() + { + // Not null-resilient + var source = """ + #nullable enable + + class C + { + public string Prop // 1 + { + get + { + local(); + field ??= "a"; + return field; + void local() => field.ToString(); + } + } + } + """; + + var comp0 = CreateCompilation(source); + comp0.VerifyEmitDiagnostics( + // (5,19): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. + // public string Prop // 1 + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "Prop").WithArguments("property", "Prop").WithLocation(5, 19)); + + var sourceField = comp0.GetMember("C.k__BackingField"); + Assert.True(sourceField.InfersNullableAnnotation); + Assert.Equal(NullableAnnotation.NotAnnotated, sourceField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, sourceField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Lambda_NullResilience_01() + { + // Null-resilient + var source = """ + #nullable enable + using System; + + class C + { + public string Prop // 1 + { + get + { + Func a = () => field ?? "a"; + return a(); + } + } + } + """; + + var comp0 = CreateCompilation(source); + comp0.VerifyEmitDiagnostics(); + + var sourceField = comp0.GetMember("C.k__BackingField"); + Assert.True(sourceField.InfersNullableAnnotation); + Assert.Equal(NullableAnnotation.Annotated, sourceField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, sourceField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Lambda_NullResilience_02() + { + // Not null-resilient + var source = """ + #nullable enable + using System; + + class C + { + public string Prop // 1 + { + get + { + Func a = () => field; + return a(); + } + } + } + """; + + var comp0 = CreateCompilation(source); + comp0.VerifyEmitDiagnostics( + // (6,19): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. + // public string Prop // 1 + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "Prop").WithArguments("property", "Prop").WithLocation(6, 19)); + + var sourceField = comp0.GetMember("C.k__BackingField"); + Assert.True(sourceField.InfersNullableAnnotation); + Assert.Equal(NullableAnnotation.NotAnnotated, sourceField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, sourceField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void AsTargetTypedOperand_01() + { + // Not null-resilient + var source = """ + #nullable enable + + class C + { + public string Prop // 1 + { + get + { + var arr = M([field]); + return arr[0]; + } + } + + public static T[] M(T[] arr) => arr; + } + """; + + var comp0 = CreateCompilation(source); + comp0.VerifyEmitDiagnostics( + // (5,19): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or safely handling the case where 'field' is null in the 'get' accessor. + // public string Prop // 1 + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "Prop").WithArguments("property", "Prop").WithLocation(5, 19)); + + var sourceField = comp0.GetMember("C.k__BackingField"); + Assert.True(sourceField.InfersNullableAnnotation); + Assert.Equal(NullableAnnotation.NotAnnotated, sourceField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, sourceField.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void AsTargetTypedOperand_02() + { + // Null-resilient + var source = """ + #nullable enable + + class C + { + public string Prop + { + get + { + var arr = M([field ?? "a"]); + return arr[0]; + } + } + + public static T[] M(T[] arr) => arr; + } + """; + + var comp0 = CreateCompilation(source); + comp0.VerifyEmitDiagnostics(); + + var sourceField = comp0.GetMember("C.k__BackingField"); + Assert.True(sourceField.InfersNullableAnnotation); + Assert.Equal(NullableAnnotation.Annotated, sourceField.GetInferredNullableAnnotation()); + Assert.Equal(NullableAnnotation.NotAnnotated, sourceField.TypeWithAnnotations.NullableAnnotation); + } } } diff --git a/src/Compilers/CSharp/Test/Emit3/FirstClassSpanTests.cs b/src/Compilers/CSharp/Test/Emit3/FirstClassSpanTests.cs index f4004a3170e99..65462a8c3034a 100644 --- a/src/Compilers/CSharp/Test/Emit3/FirstClassSpanTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/FirstClassSpanTests.cs @@ -4937,9 +4937,9 @@ static class C """; CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular13).VerifyDiagnostics( - // (4,5): error CS1503: Argument 1: cannot convert from 'method group' to 'System.Func' + // (4,7): error CS1061: 'int[]' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'int[]' could be found (are you missing a using directive or an assembly reference?) // C.R(a.M); - Diagnostic(ErrorCode.ERR_BadArgType, "a.M").WithArguments("1", "method group", "System.Func").WithLocation(4, 5), + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("int[]", "M").WithLocation(4, 7), // (5,10): error CS1929: 'int[]' does not contain a definition for 'M' and the best extension method overload 'C.M(Span, int)' requires a receiver of type 'System.Span' // C.R(x => a.M(x)); Diagnostic(ErrorCode.ERR_BadInstanceArgType, "a").WithArguments("int[]", "M", "C.M(System.Span, int)", "System.Span").WithLocation(5, 10)); @@ -4955,6 +4955,37 @@ static class C CreateCompilationWithSpanAndMemoryExtensions(source).VerifyDiagnostics(expectedDiagnostics); } + [Fact] + public void Nameof_MethodGroup() + { + var source = """ + using System; + + var a = new[] { 1, 2, 3 }; + _ = nameof(a.M); + + static class C + { + public static int M(this Span x, int y) => x[y]; + } + """; + + CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular13).VerifyDiagnostics( + // (4,14): error CS1061: 'int[]' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'int[]' could be found (are you missing a using directive or an assembly reference?) + // _ = nameof(a.M); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("int[]", "M").WithLocation(4, 14)); + + var expectedDiagnostics = new[] + { + // (4,12): error CS8093: Extension method groups are not allowed as an argument to 'nameof'. + // _ = nameof(a.M); + Diagnostic(ErrorCode.ERR_NameofExtensionMethod, "a.M").WithLocation(4, 12) + }; + + CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilationWithSpanAndMemoryExtensions(source).VerifyDiagnostics(expectedDiagnostics); + } + [Fact] public void Conversion_Array_Span_Implicit_MethodGroup_ExtensionMethodReceiver_Inferred() { @@ -4973,9 +5004,9 @@ static class C """; CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular13).VerifyDiagnostics( - // (4,10): error CS8917: The delegate type could not be inferred. + // (4,12): error CS1061: 'int[]' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'int[]' could be found (are you missing a using directive or an assembly reference?) // var d1 = a.M; - Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "a.M").WithLocation(4, 10), + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("int[]", "M").WithLocation(4, 12), // (5,10): error CS8917: The delegate type could not be inferred. // var d2 = x => a.M(x); Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "x => a.M(x)").WithLocation(5, 10), @@ -5027,12 +5058,12 @@ static class C """; CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular13).VerifyDiagnostics( - // (4,5): error CS1061: 'int[]' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'int[]' could be found (are you missing a using directive or an assembly reference?) + // (4,7): error CS1061: 'int[]' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'int[]' could be found (are you missing a using directive or an assembly reference?) // C.R(a.M); - Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "a.M").WithArguments("int[]", "M").WithLocation(4, 5), - // (5,5): error CS1503: Argument 1: cannot convert from 'method group' to 'System.Func' + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("int[]", "M").WithLocation(4, 7), + // (5,7): error CS1061: 'int[]' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'int[]' could be found (are you missing a using directive or an assembly reference?) // C.R(a.M); - Diagnostic(ErrorCode.ERR_BadArgType, "a.M").WithArguments("1", "method group", "System.Func").WithLocation(5, 5), + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("int[]", "M").WithLocation(5, 7), // (6,12): error CS1061: 'int[]' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'int[]' could be found (are you missing a using directive or an assembly reference?) // C.R(x => a.M(x)); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("int[]", "M").WithLocation(6, 12), @@ -5077,27 +5108,27 @@ static class C """; CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular13).VerifyDiagnostics( - // (4,10): error CS8917: The delegate type could not be inferred. + // (4,12): error CS1061: 'int[]' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'int[]' could be found (are you missing a using directive or an assembly reference?) // var d1 = a.M; - Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "a.M").WithLocation(4, 10), + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("int[]", "M").WithLocation(4, 12), // (5,10): error CS8917: The delegate type could not be inferred. // var d2 = x => a.M(x); Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "x => a.M(x)").WithLocation(5, 10), // (6,23): error CS1061: 'int[]' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'int[]' could be found (are you missing a using directive or an assembly reference?) // var d3 = (int x) => a.M(x); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("int[]", "M").WithLocation(6, 23), - // (7,10): error CS8917: The delegate type could not be inferred. + // (7,12): error CS1061: 'int[]' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'int[]' could be found (are you missing a using directive or an assembly reference?) // var d4 = a.M; - Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "a.M").WithLocation(7, 10), + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("int[]", "M").WithLocation(7, 12), // (8,10): error CS8917: The delegate type could not be inferred. // var d5 = x => a.M(x); Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "x => a.M(x)").WithLocation(8, 10), // (9,21): error CS1929: 'int[]' does not contain a definition for 'M' and the best extension method overload 'C.M(Span, int)' requires a receiver of type 'System.Span' // var d6 = (int x) => a.M(x); Diagnostic(ErrorCode.ERR_BadInstanceArgType, "a").WithArguments("int[]", "M", "C.M(System.Span, int)", "System.Span").WithLocation(9, 21), - // (10,21): error CS1061: 'int[]' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'int[]' could be found (are you missing a using directive or an assembly reference?) + // (10,23): error CS1061: 'int[]' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'int[]' could be found (are you missing a using directive or an assembly reference?) // Func d7 = a.M; - Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "a.M").WithArguments("int[]", "M").WithLocation(10, 21), + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("int[]", "M").WithLocation(10, 23), // (11,28): error CS1061: 'int[]' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'int[]' could be found (are you missing a using directive or an assembly reference?) // Func d8 = x => a.M(x); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("int[]", "M").WithLocation(11, 28)); diff --git a/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/FlowTestBase.cs b/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/FlowTestBase.cs index 928ebdceec7b5..064bbfa34fd2b 100644 --- a/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/FlowTestBase.cs +++ b/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/FlowTestBase.cs @@ -44,6 +44,26 @@ internal ImmutableArray FlowDiagnostics(CSharpCompilation compilatio return flowDiagnostics.ToReadOnlyAndFree().Diagnostics; } + protected static void VerifyDataFlowAnalysis(string expected, DataFlowAnalysis result) + { + var actual = $$""" +VariablesDeclared: {{GetSymbolNamesJoined(result.VariablesDeclared)}} +AlwaysAssigned: {{GetSymbolNamesJoined(result.AlwaysAssigned)}} +Captured: {{GetSymbolNamesJoined(result.Captured)}} +CapturedInside: {{GetSymbolNamesJoined(result.CapturedInside)}} +CapturedOutside: {{GetSymbolNamesJoined(result.CapturedOutside)}} +DataFlowsIn: {{GetSymbolNamesJoined(result.DataFlowsIn)}} +DataFlowsOut: {{GetSymbolNamesJoined(result.DataFlowsOut)}} +DefinitelyAssignedOnEntry: {{GetSymbolNamesJoined(result.DefinitelyAssignedOnEntry)}} +DefinitelyAssignedOnExit: {{GetSymbolNamesJoined(result.DefinitelyAssignedOnExit)}} +ReadInside: {{GetSymbolNamesJoined(result.ReadInside)}} +ReadOutside: {{GetSymbolNamesJoined(result.ReadOutside)}} +WrittenInside: {{GetSymbolNamesJoined(result.WrittenInside)}} +WrittenOutside: {{GetSymbolNamesJoined(result.WrittenOutside)}} +"""; + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, actual); + } + private IEnumerable AllMethods(Symbol symbol) { switch (symbol.Kind) diff --git a/src/Compilers/CSharp/Test/Emit3/PartialEventsAndConstructorsTests.cs b/src/Compilers/CSharp/Test/Emit3/PartialEventsAndConstructorsTests.cs new file mode 100644 index 0000000000000..cbe87ebb75e9e --- /dev/null +++ b/src/Compilers/CSharp/Test/Emit3/PartialEventsAndConstructorsTests.cs @@ -0,0 +1,3434 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Roslyn.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests; + +public sealed class PartialEventsAndConstructorsTests : CSharpTestBase +{ + [Fact] + public void ReturningPartialType_LocalFunction_InMethod() + { + var source = """ + class @partial + { + static void Main() + { + System.Console.Write(F().GetType().Name); + partial F() => new(); + } + } + """; + CompileAndVerify(source, parseOptions: TestOptions.Regular13, expectedOutput: "partial").VerifyDiagnostics(); + + var expectedDiagnostics = new[] + { + // (5,30): error CS0103: The name 'F' does not exist in the current context + // System.Console.Write(F().GetType().Name); + Diagnostic(ErrorCode.ERR_NameNotInContext, "F").WithArguments("F").WithLocation(5, 30), + // (5,50): error CS1513: } expected + // System.Console.Write(F().GetType().Name); + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(5, 50), + // (6,17): error CS1520: Method must have a return type + // partial F() => new(); + Diagnostic(ErrorCode.ERR_MemberNeedsType, "F").WithLocation(6, 17), + // (6,17): error CS0751: A partial member must be declared within a partial type + // partial F() => new(); + Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "F").WithLocation(6, 17), + // (6,17): error CS9276: Partial member 'partial.partial()' must have a definition part. + // partial F() => new(); + Diagnostic(ErrorCode.ERR_PartialMemberMissingDefinition, "F").WithArguments("partial.partial()").WithLocation(6, 17), + // (6,24): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement + // partial F() => new(); + Diagnostic(ErrorCode.ERR_IllegalStatement, "new()").WithLocation(6, 24), + // (8,1): error CS1022: Type or namespace definition, or end-of-file expected + // } + Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(8, 1) + }; + + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void ReturningPartialType_LocalFunction_TopLevel() + { + var source = """ + System.Console.Write(F().GetType().Name); + partial F() => new(); + class @partial; + """; + CompileAndVerify(source, parseOptions: TestOptions.Regular13, expectedOutput: "partial").VerifyDiagnostics(); + + var expectedDiagnostics = new[] + { + // (1,22): error CS0103: The name 'F' does not exist in the current context + // System.Console.Write(F().GetType().Name); + Diagnostic(ErrorCode.ERR_NameNotInContext, "F").WithArguments("F").WithLocation(1, 22), + // (2,9): error CS0116: A namespace cannot directly contain members such as fields, methods or statements + // partial F() => new(); + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "F").WithLocation(2, 9), + // (2,10): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement + // partial F() => new(); + Diagnostic(ErrorCode.ERR_IllegalStatement, "() => new()").WithLocation(2, 10) + }; + + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void ReturningPartialType_Method() + { + var source = """ + class C + { + partial F() => new(); + static void Main() + { + System.Console.Write(new C().F().GetType().Name); + } + } + class @partial; + """; + CompileAndVerify(source, parseOptions: TestOptions.Regular13, expectedOutput: "partial").VerifyDiagnostics(); + + var expectedDiagnostics = new[] + { + // (3,13): error CS1520: Method must have a return type + // partial F() => new(); + Diagnostic(ErrorCode.ERR_MemberNeedsType, "F").WithLocation(3, 13), + // (3,13): error CS0751: A partial member must be declared within a partial type + // partial F() => new(); + Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "F").WithLocation(3, 13), + // (3,13): error CS9276: Partial member 'C.C()' must have a definition part. + // partial F() => new(); + Diagnostic(ErrorCode.ERR_PartialMemberMissingDefinition, "F").WithArguments("C.C()").WithLocation(3, 13), + // (3,20): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement + // partial F() => new(); + Diagnostic(ErrorCode.ERR_IllegalStatement, "new()").WithLocation(3, 20), + // (6,38): error CS1061: 'C' does not contain a definition for 'F' and no accessible extension method 'F' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?) + // System.Console.Write(new C().F().GetType().Name); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "F").WithArguments("C", "F").WithLocation(6, 38) + }; + + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void ReturningPartialType_Method_CouldBePartialConstructor() + { + var source = """ + class C + { + partial F() { } + partial C() { } + } + """; + CreateCompilation(source, parseOptions: TestOptions.Regular13).VerifyDiagnostics( + // (3,5): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) + // partial F() { } + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(3, 5), + // (3,5): error CS8652: The feature 'partial events and constructors' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // partial F() { } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "partial").WithArguments("partial events and constructors").WithLocation(3, 5), + // (3,13): error CS0161: 'C.F()': not all code paths return a value + // partial F() { } + Diagnostic(ErrorCode.ERR_ReturnExpected, "F").WithArguments("C.F()").WithLocation(3, 13), + // (4,5): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) + // partial C() { } + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(4, 5), + // (4,5): error CS8652: The feature 'partial events and constructors' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // partial C() { } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "partial").WithArguments("partial events and constructors").WithLocation(4, 5), + // (4,13): error CS0542: 'C': member names cannot be the same as their enclosing type + // partial C() { } + Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "C").WithArguments("C").WithLocation(4, 13), + // (4,13): error CS0161: 'C.C()': not all code paths return a value + // partial C() { } + Diagnostic(ErrorCode.ERR_ReturnExpected, "C").WithArguments("C.C()").WithLocation(4, 13)); + } + + [Fact] + public void ReturningPartialType_Method_Escaped() + { + var source = """ + class C + { + @partial F() { } + @partial C() { } + } + """; + + var expectedDiagnostics = new[] + { + // (3,5): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) + // @partial F() { } + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "@partial").WithArguments("partial").WithLocation(3, 5), + // (3,14): error CS0161: 'C.F()': not all code paths return a value + // @partial F() { } + Diagnostic(ErrorCode.ERR_ReturnExpected, "F").WithArguments("C.F()").WithLocation(3, 14), + // (4,5): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) + // @partial C() { } + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "@partial").WithArguments("partial").WithLocation(4, 5), + // (4,14): error CS0542: 'C': member names cannot be the same as their enclosing type + // @partial C() { } + Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "C").WithArguments("C").WithLocation(4, 14), + // (4,14): error CS0161: 'C.C()': not all code paths return a value + // @partial C() { } + Diagnostic(ErrorCode.ERR_ReturnExpected, "C").WithArguments("C.C()").WithLocation(4, 14) + }; + + CreateCompilation(source, parseOptions: TestOptions.Regular13).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void LangVersion() + { + var source = """ + partial class C + { + partial event System.Action E; + partial event System.Action E { add { } remove { } } + partial C(); + partial C() { } + } + """; + + CreateCompilation(source, parseOptions: TestOptions.Regular13).VerifyDiagnostics( + // (3,33): error CS8703: The modifier 'partial' is not valid for this item in C# 13.0. Please use language version 'preview' or greater. + // partial event System.Action E; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "E").WithArguments("partial", "13.0", "preview").WithLocation(3, 33), + // (5,5): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) + // partial C(); + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(5, 5), + // (5,5): error CS8652: The feature 'partial events and constructors' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // partial C(); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "partial").WithArguments("partial events and constructors").WithLocation(5, 5), + // (5,13): error CS0501: 'C.C()' must declare a body because it is not marked abstract, extern, or partial + // partial C(); + Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "C").WithArguments("C.C()").WithLocation(5, 13), + // (5,13): error CS0542: 'C': member names cannot be the same as their enclosing type + // partial C(); + Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "C").WithArguments("C").WithLocation(5, 13), + // (6,5): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) + // partial C() { } + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(6, 5), + // (6,5): error CS8652: The feature 'partial events and constructors' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // partial C() { } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "partial").WithArguments("partial events and constructors").WithLocation(6, 5), + // (6,13): error CS0542: 'C': member names cannot be the same as their enclosing type + // partial C() { } + Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "C").WithArguments("C").WithLocation(6, 13), + // (6,13): error CS0111: Type 'C' already defines a member called 'C' with the same parameter types + // partial C() { } + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "C").WithArguments("C", "C").WithLocation(6, 13), + // (6,13): error CS0161: 'C.C()': not all code paths return a value + // partial C() { } + Diagnostic(ErrorCode.ERR_ReturnExpected, "C").WithArguments("C.C()").WithLocation(6, 13)); + + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CreateCompilation(source).VerifyDiagnostics(); + } + + [Theory, CombinatorialData] + public void PartialLast([CombinatorialValues("", "public")] string modifier) + { + var source = $$""" + partial class C + { + {{modifier}} + partial event System.Action E; + {{modifier}} + partial event System.Action E { add { } remove { } } + {{modifier}} + partial C(); + {{modifier}} + partial C() { } + } + """; + CreateCompilation(source).VerifyDiagnostics(); + } + + [Fact] + public void PartialNotLast() + { + var source = """ + partial class C + { + partial public event System.Action E; + partial public event System.Action E { add { } remove { } } + partial public C(); + partial public C() { } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. + // partial public event System.Action E; + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 5), + // (4,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. + // partial public event System.Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(4, 5), + // (5,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. + // partial public C(); + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(5, 5), + // (6,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. + // partial public C() { } + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(6, 5)); + } + + [Fact] + public void PartialAsType() + { + var source = """ + partial class C + { + partial C() => new partial(); + } + + class @partial; + """; + CreateCompilation(source).VerifyDiagnostics( + // (3,13): error CS9276: Partial member 'C.C()' must have a definition part. + // partial C() => new partial(); + Diagnostic(ErrorCode.ERR_PartialMemberMissingDefinition, "C").WithArguments("C.C()").WithLocation(3, 13)); + } + + [Fact] + public void MissingImplementation() + { + var source = """ + partial class C + { + partial event System.Action E; + partial C(); + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (3,33): error CS9275: Partial member 'C.E' must have an implementation part. + // partial event System.Action E; + Diagnostic(ErrorCode.ERR_PartialMemberMissingImplementation, "E").WithArguments("C.E").WithLocation(3, 33), + // (4,13): error CS9275: Partial member 'C.C()' must have an implementation part. + // partial C(); + Diagnostic(ErrorCode.ERR_PartialMemberMissingImplementation, "C").WithArguments("C.C()").WithLocation(4, 13)); + } + + [Fact] + public void MissingDefinition() + { + var source = """ + partial class C + { + partial event System.Action E { add { } remove { } } + partial C() { } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (3,33): error CS9276: Partial member 'C.E' must have a definition part. + // partial event System.Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_PartialMemberMissingDefinition, "E").WithArguments("C.E").WithLocation(3, 33), + // (4,13): error CS9276: Partial member 'C.C()' must have a definition part. + // partial C() { } + Diagnostic(ErrorCode.ERR_PartialMemberMissingDefinition, "C").WithArguments("C.C()").WithLocation(4, 13)); + } + + [Fact] + public void DuplicateDefinition() + { + var source = """ + partial class C + { + partial event System.Action E, F; + partial event System.Action E; + partial event System.Action F; + partial C(); + partial C(); + + partial event System.Action E { add { } remove { } } + partial event System.Action F { add { } remove { } } + partial C() { } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (4,33): error CS9277: Partial member 'C.E' may not have multiple defining declarations. + // partial event System.Action E; + Diagnostic(ErrorCode.ERR_PartialMemberDuplicateDefinition, "E").WithArguments("C.E").WithLocation(4, 33), + // (4,33): error CS0102: The type 'C' already contains a definition for 'E' + // partial event System.Action E; + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "E").WithArguments("C", "E").WithLocation(4, 33), + // (5,33): error CS9277: Partial member 'C.F' may not have multiple defining declarations. + // partial event System.Action F; + Diagnostic(ErrorCode.ERR_PartialMemberDuplicateDefinition, "F").WithArguments("C.F").WithLocation(5, 33), + // (5,33): error CS0102: The type 'C' already contains a definition for 'F' + // partial event System.Action F; + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "F").WithArguments("C", "F").WithLocation(5, 33), + // (7,13): error CS9277: Partial member 'C.C()' may not have multiple defining declarations. + // partial C(); + Diagnostic(ErrorCode.ERR_PartialMemberDuplicateDefinition, "C").WithArguments("C.C()").WithLocation(7, 13), + // (7,13): error CS0111: Type 'C' already defines a member called 'C' with the same parameter types + // partial C(); + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "C").WithArguments("C", "C").WithLocation(7, 13)); + } + + [Fact] + public void DuplicateImplementation() + { + var source = """ + partial class C + { + partial event System.Action E { add { } remove { } } + partial event System.Action E { add { } remove { } } + partial C() { } + partial C() { } + + partial event System.Action E; + partial C(); + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (4,33): error CS9278: Partial member 'C.E' may not have multiple implementing declarations. + // partial event System.Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_PartialMemberDuplicateImplementation, "E").WithArguments("C.E").WithLocation(4, 33), + // (6,13): error CS9278: Partial member 'C.C()' may not have multiple implementing declarations. + // partial C() { } + Diagnostic(ErrorCode.ERR_PartialMemberDuplicateImplementation, "C").WithArguments("C.C()").WithLocation(6, 13), + // (8,33): error CS0102: The type 'C' already contains a definition for 'E' + // partial event System.Action E; + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "E").WithArguments("C", "E").WithLocation(8, 33), + // (9,13): error CS0111: Type 'C' already defines a member called 'C' with the same parameter types + // partial C(); + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "C").WithArguments("C", "C").WithLocation(9, 13)); + } + + [Fact] + public void DuplicateDeclarations_01() + { + var source = """ + partial class C + { + partial event System.Action E { add { } remove { } } + partial event System.Action E { add { } remove { } } + partial C() { } + partial C() { } + + partial event System.Action E; + partial event System.Action E; + partial C(); + partial C(); + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (4,33): error CS9278: Partial member 'C.E' may not have multiple implementing declarations. + // partial event System.Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_PartialMemberDuplicateImplementation, "E").WithArguments("C.E").WithLocation(4, 33), + // (6,13): error CS9278: Partial member 'C.C()' may not have multiple implementing declarations. + // partial C() { } + Diagnostic(ErrorCode.ERR_PartialMemberDuplicateImplementation, "C").WithArguments("C.C()").WithLocation(6, 13), + // (8,33): error CS0102: The type 'C' already contains a definition for 'E' + // partial event System.Action E; + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "E").WithArguments("C", "E").WithLocation(8, 33), + // (9,33): error CS9277: Partial member 'C.E' may not have multiple defining declarations. + // partial event System.Action E; + Diagnostic(ErrorCode.ERR_PartialMemberDuplicateDefinition, "E").WithArguments("C.E").WithLocation(9, 33), + // (9,33): error CS0102: The type 'C' already contains a definition for 'E' + // partial event System.Action E; + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "E").WithArguments("C", "E").WithLocation(9, 33), + // (10,13): error CS0111: Type 'C' already defines a member called 'C' with the same parameter types + // partial C(); + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "C").WithArguments("C", "C").WithLocation(10, 13), + // (11,13): error CS9277: Partial member 'C.C()' may not have multiple defining declarations. + // partial C(); + Diagnostic(ErrorCode.ERR_PartialMemberDuplicateDefinition, "C").WithArguments("C.C()").WithLocation(11, 13), + // (11,13): error CS0111: Type 'C' already defines a member called 'C' with the same parameter types + // partial C(); + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "C").WithArguments("C", "C").WithLocation(11, 13)); + } + + [Fact] + public void DuplicateDeclarations_02() + { + var source = """ + partial class C + { + partial event System.Action E; + partial void add_E(System.Action value); + partial void remove_E(System.Action value); + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (3,33): error CS9275: Partial member 'C.E' must have an implementation part. + // partial event System.Action E; + Diagnostic(ErrorCode.ERR_PartialMemberMissingImplementation, "E").WithArguments("C.E").WithLocation(3, 33), + // (3,33): error CS0082: Type 'C' already reserves a member called 'add_E' with the same parameter types + // partial event System.Action E; + Diagnostic(ErrorCode.ERR_MemberReserved, "E").WithArguments("add_E", "C").WithLocation(3, 33), + // (3,33): error CS0082: Type 'C' already reserves a member called 'remove_E' with the same parameter types + // partial event System.Action E; + Diagnostic(ErrorCode.ERR_MemberReserved, "E").WithArguments("remove_E", "C").WithLocation(3, 33)); + } + + [Fact] + public void DuplicateDeclarations_03() + { + var source = """ + partial class C + { + partial event System.Action E; + partial event System.Action E; + partial C(); + partial C(); + + partial event System.Action E { add { } remove { } } + partial event System.Action E { add { } remove { } } + partial C() { } + partial C() { } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (4,33): error CS9277: Partial member 'C.E' may not have multiple defining declarations. + // partial event System.Action E; + Diagnostic(ErrorCode.ERR_PartialMemberDuplicateDefinition, "E").WithArguments("C.E").WithLocation(4, 33), + // (4,33): error CS0102: The type 'C' already contains a definition for 'E' + // partial event System.Action E; + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "E").WithArguments("C", "E").WithLocation(4, 33), + // (6,13): error CS9277: Partial member 'C.C()' may not have multiple defining declarations. + // partial C(); + Diagnostic(ErrorCode.ERR_PartialMemberDuplicateDefinition, "C").WithArguments("C.C()").WithLocation(6, 13), + // (6,13): error CS0111: Type 'C' already defines a member called 'C' with the same parameter types + // partial C(); + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "C").WithArguments("C", "C").WithLocation(6, 13), + // (9,33): error CS9278: Partial member 'C.E' may not have multiple implementing declarations. + // partial event System.Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_PartialMemberDuplicateImplementation, "E").WithArguments("C.E").WithLocation(9, 33), + // (9,33): error CS0102: The type 'C' already contains a definition for 'E' + // partial event System.Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "E").WithArguments("C", "E").WithLocation(9, 33), + // (11,13): error CS9278: Partial member 'C.C()' may not have multiple implementing declarations. + // partial C() { } + Diagnostic(ErrorCode.ERR_PartialMemberDuplicateImplementation, "C").WithArguments("C.C()").WithLocation(11, 13), + // (11,13): error CS0111: Type 'C' already defines a member called 'C' with the same parameter types + // partial C() { } + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "C").WithArguments("C", "C").WithLocation(11, 13)); + } + + [Fact] + public void DuplicateDeclarations_04() + { + var source = """ + using System; + partial class C + { + partial event Action E; + partial event Action E { add { } } + partial event Action E { remove { } } + } + """; + var comp = CreateCompilation(source).VerifyDiagnostics( + // (5,26): error CS0065: 'C.E': event property must have both add and remove accessors + // partial event Action E { add { } } + Diagnostic(ErrorCode.ERR_EventNeedsBothAccessors, "E").WithArguments("C.E").WithLocation(5, 26), + // (6,26): error CS0065: 'C.E': event property must have both add and remove accessors + // partial event Action E { remove { } } + Diagnostic(ErrorCode.ERR_EventNeedsBothAccessors, "E").WithArguments("C.E").WithLocation(6, 26), + // (6,26): error CS9278: Partial member 'C.E' may not have multiple implementing declarations. + // partial event Action E { remove { } } + Diagnostic(ErrorCode.ERR_PartialMemberDuplicateImplementation, "E").WithArguments("C.E").WithLocation(6, 26), + // (6,26): error CS0102: The type 'C' already contains a definition for 'E' + // partial event Action E { remove { } } + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "E").WithArguments("C", "E").WithLocation(6, 26)); + + var events = comp.GetMembers("C.E"); + Assert.Equal(2, events.Length); + + var e1 = (SourceEventSymbol)events[0]; + Assert.True(e1.IsPartialDefinition); + AssertEx.Equal("event System.Action C.E", e1.ToTestDisplayString()); + AssertEx.Equal("event System.Action C.E", e1.PartialImplementationPart.ToTestDisplayString()); + + var e2 = (SourceEventSymbol)events[1]; + Assert.True(e2.IsPartialImplementation); + AssertEx.Equal("event System.Action C.E", e2.ToTestDisplayString()); + Assert.Null(e2.PartialDefinitionPart); + } + + [Fact] + public void EventInitializer_Single() + { + var source = """ + partial class C + { + partial event System.Action E = null; + partial event System.Action E { add { } remove { } } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (3,33): error CS9279: 'C.E': partial event cannot have initializer + // partial event System.Action E = null; + Diagnostic(ErrorCode.ERR_PartialEventInitializer, "E").WithArguments("C.E").WithLocation(3, 33), + // (3,33): warning CS0414: The field 'C.E' is assigned but its value is never used + // partial event System.Action E = null; + Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "E").WithArguments("C.E").WithLocation(3, 33)); + } + + [Fact] + public void EventInitializer_Multiple_01() + { + var source = """ + partial class C + { + partial event System.Action E, F = null; + partial event System.Action E { add { } remove { } } + partial event System.Action F { add { } remove { } } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (3,36): error CS9279: 'C.F': partial event cannot have initializer + // partial event System.Action E, F = null; + Diagnostic(ErrorCode.ERR_PartialEventInitializer, "F").WithArguments("C.F").WithLocation(3, 36), + // (3,36): warning CS0414: The field 'C.F' is assigned but its value is never used + // partial event System.Action E, F = null; + Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "F").WithArguments("C.F").WithLocation(3, 36)); + } + + [Fact] + public void EventInitializer_Multiple_02() + { + var source = """ + partial class C + { + partial event System.Action E = null, F = null; + partial event System.Action E { add { } remove { } } + partial event System.Action F { add { } remove { } } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (3,33): error CS9279: 'C.E': partial event cannot have initializer + // partial event System.Action E = null, F = null; + Diagnostic(ErrorCode.ERR_PartialEventInitializer, "E").WithArguments("C.E").WithLocation(3, 33), + // (3,33): warning CS0414: The field 'C.E' is assigned but its value is never used + // partial event System.Action E = null, F = null; + Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "E").WithArguments("C.E").WithLocation(3, 33), + // (3,43): error CS9279: 'C.F': partial event cannot have initializer + // partial event System.Action E = null, F = null; + Diagnostic(ErrorCode.ERR_PartialEventInitializer, "F").WithArguments("C.F").WithLocation(3, 43), + // (3,43): warning CS0414: The field 'C.F' is assigned but its value is never used + // partial event System.Action E = null, F = null; + Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "F").WithArguments("C.F").WithLocation(3, 43)); + } + + [Fact] + public void EventAccessorMissing() + { + var source = """ + partial class C + { + partial event System.Action E, F; + partial event System.Action E { add { } } + partial event System.Action F { remove { } } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (4,33): error CS0065: 'C.E': event property must have both add and remove accessors + // partial event System.Action E { add { } } + Diagnostic(ErrorCode.ERR_EventNeedsBothAccessors, "E").WithArguments("C.E").WithLocation(4, 33), + // (5,33): error CS0065: 'C.F': event property must have both add and remove accessors + // partial event System.Action F { remove { } } + Diagnostic(ErrorCode.ERR_EventNeedsBothAccessors, "F").WithArguments("C.F").WithLocation(5, 33)); + } + + [Fact] + public void StaticPartialConstructor_01() + { + var source = """ + partial class C + { + static partial C(); + static partial C() { } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (3,12): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. + // static partial C(); + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 12), + // (4,12): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. + // static partial C() { } + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(4, 12), + // (4,20): error CS0111: Type 'C' already defines a member called 'C' with the same parameter types + // static partial C() { } + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "C").WithArguments("C", "C").WithLocation(4, 20)); + } + + [Fact] + public void StaticPartialConstructor_02() + { + var source = """ + partial class C + { + partial static C(); + partial static C() { } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. + // partial static C(); + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 5), + // (3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. + // partial static C(); + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 5), + // (4,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. + // partial static C() { } + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(4, 5), + // (4,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. + // partial static C() { } + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(4, 5), + // (4,20): error CS0111: Type 'C' already defines a member called 'C' with the same parameter types + // partial static C() { } + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "C").WithArguments("C", "C").WithLocation(4, 20)); + } + + [Fact] + public void Finalizer() + { + var source = """ + partial class C + { + partial ~C(); + partial ~C() { } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (3,13): error CS1519: Invalid token '~' in class, record, struct, or interface member declaration + // partial ~C(); + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "~").WithArguments("~").WithLocation(3, 13), + // (4,13): error CS1519: Invalid token '~' in class, record, struct, or interface member declaration + // partial ~C() { } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "~").WithArguments("~").WithLocation(4, 13), + // (3,14): error CS0501: 'C.~C()' must declare a body because it is not marked abstract, extern, or partial + // partial ~C(); + Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "C").WithArguments("C.~C()").WithLocation(3, 14), + // (4,14): error CS0111: Type 'C' already defines a member called '~C' with the same parameter types + // partial ~C() { } + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "C").WithArguments("~C", "C").WithLocation(4, 14)); + } + + [Fact] + public void PrimaryConstructor_Duplicate_WithoutInitializer() + { + var source = """ + partial class C() + { + partial C(); + partial C() { } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (3,13): error CS0111: Type 'C' already defines a member called 'C' with the same parameter types + // partial C(); + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "C").WithArguments("C", "C").WithLocation(3, 13), + // (4,13): error CS8862: A constructor declared in a type with parameter list must have 'this' constructor initializer. + // partial C() { } + Diagnostic(ErrorCode.ERR_UnexpectedOrMissingConstructorInitializerInRecord, "C").WithLocation(4, 13)); + } + + [Fact] + public void PrimaryConstructor_Duplicate_WithInitializer() + { + var source = """ + partial class C() + { + partial C(); + partial C() : this() { } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (3,13): error CS0111: Type 'C' already defines a member called 'C' with the same parameter types + // partial C(); + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "C").WithArguments("C", "C").WithLocation(3, 13), + // (4,19): error CS0121: The call is ambiguous between the following methods or properties: 'C.C()' and 'C.C()' + // partial C() : this() { } + Diagnostic(ErrorCode.ERR_AmbigCall, "this").WithArguments("C.C()", "C.C()").WithLocation(4, 19)); + } + + [Fact] + public void PrimaryConstructor_DefinitionOnly() + { + var source = """ + partial class C() + { + partial C(); + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (3,13): error CS9275: Partial member 'C.C()' must have an implementation part. + // partial C(); + Diagnostic(ErrorCode.ERR_PartialMemberMissingImplementation, "C").WithArguments("C.C()").WithLocation(3, 13), + // (3,13): error CS0111: Type 'C' already defines a member called 'C' with the same parameter types + // partial C(); + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "C").WithArguments("C", "C").WithLocation(3, 13)); + } + + [Fact] + public void PrimaryConstructor_ImplementationOnly_WithoutInitializer() + { + var source = """ + partial class C() + { + partial C() { } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (3,13): error CS9276: Partial member 'C.C()' must have a definition part. + // partial C() { } + Diagnostic(ErrorCode.ERR_PartialMemberMissingDefinition, "C").WithArguments("C.C()").WithLocation(3, 13), + // (3,13): error CS0111: Type 'C' already defines a member called 'C' with the same parameter types + // partial C() { } + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "C").WithArguments("C", "C").WithLocation(3, 13), + // (3,13): error CS8862: A constructor declared in a type with parameter list must have 'this' constructor initializer. + // partial C() { } + Diagnostic(ErrorCode.ERR_UnexpectedOrMissingConstructorInitializerInRecord, "C").WithLocation(3, 13)); + } + + [Fact] + public void PrimaryConstructor_ImplementationOnly_WithInitializer() + { + var source = """ + partial class C() + { + partial C() : this() { } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (3,13): error CS9276: Partial member 'C.C()' must have a definition part. + // partial C() : this() { } + Diagnostic(ErrorCode.ERR_PartialMemberMissingDefinition, "C").WithArguments("C.C()").WithLocation(3, 13), + // (3,13): error CS0111: Type 'C' already defines a member called 'C' with the same parameter types + // partial C() : this() { } + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "C").WithArguments("C", "C").WithLocation(3, 13), + // (3,19): error CS0121: The call is ambiguous between the following methods or properties: 'C.C()' and 'C.C()' + // partial C() : this() { } + Diagnostic(ErrorCode.ERR_AmbigCall, "this").WithArguments("C.C()", "C.C()").WithLocation(3, 19)); + } + + [Fact] + public void PrimaryConstructor_Different_WithoutInitializer() + { + var source = """ + partial class C() + { + partial C(int x); + partial C(int x) { } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (4,13): error CS8862: A constructor declared in a type with parameter list must have 'this' constructor initializer. + // partial C(int x) { } + Diagnostic(ErrorCode.ERR_UnexpectedOrMissingConstructorInitializerInRecord, "C").WithLocation(4, 13)); + } + + [Fact] + public void PrimaryConstructor_Different_WithInitializer() + { + var source = """ + partial class C() + { + partial C(int x); + partial C(int x) : this() { } + } + """; + CreateCompilation(source).VerifyDiagnostics(); + } + + [Fact] + public void PrimaryConstructor_Twice() + { + var source = """ + partial class C(); + partial class C() { } + """; + CreateCompilation(source).VerifyDiagnostics( + // (2,16): error CS8863: Only a single partial type declaration may have a parameter list + // partial class C() { } + Diagnostic(ErrorCode.ERR_MultipleRecordParameterLists, "()").WithLocation(2, 16)); + } + + [Fact] + public void NotInPartialType() + { + var source = """ + class C + { + partial event System.Action E; + partial event System.Action E { add { } remove { } } + partial event System.Action F { add { } remove { } } + partial C(); + partial C() { } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (3,33): error CS0751: A partial member must be declared within a partial type + // partial event System.Action E; + Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "E").WithLocation(3, 33), + // (5,33): error CS9276: Partial event 'C.F' must have a definition part. + // partial event System.Action F { add { } remove { } } + Diagnostic(ErrorCode.ERR_PartialMemberMissingDefinition, "F").WithArguments("C.F").WithLocation(5, 33), + // (5,33): error CS0751: A partial member must be declared within a partial type + // partial event System.Action F { add { } remove { } } + Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "F").WithLocation(5, 33), + // (6,13): error CS0751: A partial member must be declared within a partial type + // partial C(); + Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "C").WithLocation(6, 13), + // (7,13): error CS0751: A partial member must be declared within a partial type + // partial C() { } + Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "C").WithLocation(7, 13)); + } + + [Fact] + public void InInterface() + { + var source = """ + partial interface I + { + partial event System.Action E; + partial event System.Action E { add { } remove { } } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (4,37): error CS8701: Target runtime doesn't support default interface implementation. + // partial event System.Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportDefaultInterfaceImplementation, "add").WithLocation(4, 37), + // (4,45): error CS8701: Target runtime doesn't support default interface implementation. + // partial event System.Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportDefaultInterfaceImplementation, "remove").WithLocation(4, 45)); + + CreateCompilation(source, targetFramework: TargetFramework.Net60).VerifyDiagnostics(); + + CreateCompilation(source, targetFramework: TargetFramework.Net60, parseOptions: TestOptions.Regular7).VerifyDiagnostics( + // (3,33): error CS8703: The modifier 'partial' is not valid for this item in C# 7.0. Please use language version 'preview' or greater. + // partial event System.Action E; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "E").WithArguments("partial", "7.0", "preview").WithLocation(3, 33), + // (4,37): error CS8107: Feature 'default interface implementation' is not available in C# 7.0. Please use language version 8.0 or greater. + // partial event System.Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "add").WithArguments("default interface implementation", "8.0").WithLocation(4, 37), + // (4,45): error CS8107: Feature 'default interface implementation' is not available in C# 7.0. Please use language version 8.0 or greater. + // partial event System.Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "remove").WithArguments("default interface implementation", "8.0").WithLocation(4, 45)); + } + + [Fact] + public void InInterface_DefinitionOnly() + { + var source = """ + partial interface I + { + partial event System.Action E; + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (3,33): error CS9275: Partial member 'I.E' must have an implementation part. + // partial event System.Action E; + Diagnostic(ErrorCode.ERR_PartialMemberMissingImplementation, "E").WithArguments("I.E").WithLocation(3, 33)); + } + + [Fact] + public void Abstract() + { + var source = """ + abstract partial class C + { + protected abstract partial event System.Action E; + protected abstract partial event System.Action E { add { } remove { } } + protected abstract partial C(); + protected abstract partial C() { } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (3,52): error CS0750: A partial member cannot have the 'abstract' modifier + // protected abstract partial event System.Action E; + Diagnostic(ErrorCode.ERR_PartialMemberCannotBeAbstract, "E").WithLocation(3, 52), + // (4,54): error CS8712: 'C.E': abstract event cannot use event accessor syntax + // protected abstract partial event System.Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_AbstractEventHasAccessors, "{").WithArguments("C.E").WithLocation(4, 54), + // (5,32): error CS0106: The modifier 'abstract' is not valid for this item + // protected abstract partial C(); + Diagnostic(ErrorCode.ERR_BadMemberFlag, "C").WithArguments("abstract").WithLocation(5, 32), + // (6,32): error CS0106: The modifier 'abstract' is not valid for this item + // protected abstract partial C() { } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "C").WithArguments("abstract").WithLocation(6, 32)); + } + + [Fact] + public void Required() + { + var source = """ + partial class C + { + public required partial event System.Action E; + public required partial event System.Action E { add { } remove { } } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (3,49): error CS0106: The modifier 'required' is not valid for this item + // public required partial event System.Action E; + Diagnostic(ErrorCode.ERR_BadMemberFlag, "E").WithArguments("required").WithLocation(3, 49), + // (4,49): error CS0106: The modifier 'required' is not valid for this item + // public required partial event System.Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "E").WithArguments("required").WithLocation(4, 49)); + } + + [Fact] + public void ExplicitInterfaceImplementation() + { + var source = """ + interface I + { + event System.Action E; + } + partial class C : I + { + partial event System.Action I.E; + partial event System.Action I.E { add { } remove { } } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (5,15): error CS8646: 'I.E' is explicitly implemented more than once. + // partial class C : I + Diagnostic(ErrorCode.ERR_DuplicateExplicitImpl, "C").WithArguments("I.E").WithLocation(5, 15), + // (7,35): error CS0071: An explicit interface implementation of an event must use event accessor syntax + // partial event System.Action I.E; + Diagnostic(ErrorCode.ERR_ExplicitEventFieldImpl, "E").WithLocation(7, 35), + // (7,35): error CS9276: Partial member 'C.I.E' must have a definition part. + // partial event System.Action I.E; + Diagnostic(ErrorCode.ERR_PartialMemberMissingDefinition, "E").WithArguments("C.I.E").WithLocation(7, 35), + // (7,35): error CS0754: A partial member may not explicitly implement an interface member + // partial event System.Action I.E; + Diagnostic(ErrorCode.ERR_PartialMemberNotExplicit, "E").WithLocation(7, 35), + // (8,35): error CS9278: Partial member 'C.I.E' may not have multiple implementing declarations. + // partial event System.Action I.E { add { } remove { } } + Diagnostic(ErrorCode.ERR_PartialMemberDuplicateImplementation, "E").WithArguments("C.I.E").WithLocation(8, 35), + // (8,35): error CS0102: The type 'C' already contains a definition for 'I.E' + // partial event System.Action I.E { add { } remove { } } + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "E").WithArguments("C", "I.E").WithLocation(8, 35), + // (8,35): error CS0754: A partial member may not explicitly implement an interface member + // partial event System.Action I.E { add { } remove { } } + Diagnostic(ErrorCode.ERR_PartialMemberNotExplicit, "E").WithLocation(8, 35)); + } + + [Fact] + public void ConstructorInitializers_This_Duplicate() + { + var source = """ + partial class C + { + partial C() : this(1) { } + partial C() : this(2); + + C(int x) { } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (4,17): error CS9280: 'C.C()': only the implementing declaration of a partial constructor can have an initializer + // partial C() : this(2); + Diagnostic(ErrorCode.ERR_PartialConstructorInitializer, ": this(2)").WithArguments("C.C()").WithLocation(4, 17)); + } + + [Fact] + public void ConstructorInitializers_This_OnDefinition() + { + var source = """ + partial class C + { + partial C() { } + partial C() : this(1); + + C(int x) { } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (4,17): error CS9280: 'C.C()': only the implementing declaration of a partial constructor can have an initializer + // partial C() : this(1); + Diagnostic(ErrorCode.ERR_PartialConstructorInitializer, ": this(1)").WithArguments("C.C()").WithLocation(4, 17)); + } + + [Fact] + public void ConstructorInitializers_This_OnImplementation() + { + var source = """ + var c = new C(); + + partial class C + { + public partial C() : this(1) { } + public partial C(); + + C(int x) { System.Console.Write(x); } + } + """; + CompileAndVerify(source, expectedOutput: "1").VerifyDiagnostics(); + } + + [Fact] + public void ConstructorInitializers_Base_Duplicate() + { + var source = """ + abstract class B + { + protected B(int x) { } + } + + partial class C : B + { + partial C() : base(1) { } + partial C() : base(2); + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (9,17): error CS9280: 'C.C()': only the implementing declaration of a partial constructor can have an initializer + // partial C() : base(2); + Diagnostic(ErrorCode.ERR_PartialConstructorInitializer, ": base(2)").WithArguments("C.C()").WithLocation(9, 17)); + } + + [Fact] + public void ConstructorInitializers_Base_OnDefinition_01() + { + var source = """ + abstract class B + { + protected B(int x) { } + } + + partial class C : B + { + partial C() { } + partial C() : base(1); + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (8,13): error CS7036: There is no argument given that corresponds to the required parameter 'x' of 'B.B(int)' + // partial C() { } + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "C").WithArguments("x", "B.B(int)").WithLocation(8, 13), + // (9,17): error CS9280: 'C.C()': only the implementing declaration of a partial constructor can have an initializer + // partial C() : base(1); + Diagnostic(ErrorCode.ERR_PartialConstructorInitializer, ": base(1)").WithArguments("C.C()").WithLocation(9, 17)); + } + + [Fact] + public void ConstructorInitializers_Base_OnDefinition_02() + { + var source = """ + abstract class B + { + protected B(int x) { } + protected B() { } + } + + partial class C : B + { + partial C() { } + partial C() : base(1); + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (10,17): error CS9280: 'C.C()': only the implementing declaration of a partial constructor can have an initializer + // partial C() : base(1); + Diagnostic(ErrorCode.ERR_PartialConstructorInitializer, ": base(1)").WithArguments("C.C()").WithLocation(10, 17)); + } + + [Fact] + public void ConstructorInitializers_Base_OnImplementation() + { + var source = """ + var c = new C(); + + abstract class B + { + protected B(int x) { System.Console.Write(x); } + } + + partial class C : B + { + public partial C() : base(1) { } + public partial C(); + } + """; + CompileAndVerify(source, expectedOutput: "1").VerifyDiagnostics(); + } + + [Fact] + public void VariableInitializer() + { + var source = """ + var c = new C(); + + partial class C + { + int x = 5; + + public partial C() { System.Console.Write(x); } + public partial C(); + } + """; + CompileAndVerify(source, expectedOutput: "5").VerifyDiagnostics(); + } + + [Fact] + public void Extern_01() + { + var source = """ + partial class C + { + partial event System.Action E; + extern partial event System.Action E; + + partial C(); + extern partial C(); + } + """; + CompileAndVerifyWithMscorlib46(source, + options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All), + sourceSymbolValidator: verifySource, + symbolValidator: verifyMetadata, + // PEVerify fails when extern methods lack an implementation + verify: Verification.FailsPEVerify with + { + PEVerifyMessage = """ + Error: Method marked Abstract, Runtime, InternalCall or Imported must have zero RVA, and vice versa. + Error: Method marked Abstract, Runtime, InternalCall or Imported must have zero RVA, and vice versa. + Error: Method marked Abstract, Runtime, InternalCall or Imported must have zero RVA, and vice versa. + Type load failed. + """, + }) + .VerifyDiagnostics() + .VerifyTypeIL("C", """ + .class private auto ansi beforefieldinit C + extends [mscorlib]System.Object + { + // Methods + .method private hidebysig specialname + instance void add_E ( + class [mscorlib]System.Action 'value' + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + } // end of method C::add_E + .method private hidebysig specialname + instance void remove_E ( + class [mscorlib]System.Action 'value' + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + } // end of method C::remove_E + .method private hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + } // end of method C::.ctor + // Events + .event [mscorlib]System.Action E + { + .addon instance void C::add_E(class [mscorlib]System.Action) + .removeon instance void C::remove_E(class [mscorlib]System.Action) + } + } // end of class C + """); + + static void verifySource(ModuleSymbol module) + { + var ev = module.GlobalNamespace.GetMember("C.E"); + Assert.True(ev.IsPartialDefinition); + Assert.True(ev.GetPublicSymbol().IsExtern); + Assert.True(ev.AddMethod!.GetPublicSymbol().IsExtern); + Assert.True(ev.RemoveMethod!.GetPublicSymbol().IsExtern); + Assert.True(ev.PartialImplementationPart!.GetPublicSymbol().IsExtern); + Assert.True(ev.PartialImplementationPart!.AddMethod!.GetPublicSymbol().IsExtern); + Assert.True(ev.PartialImplementationPart!.RemoveMethod!.GetPublicSymbol().IsExtern); + + var c = module.GlobalNamespace.GetMember("C..ctor"); + Assert.True(c.IsPartialDefinition); + Assert.True(c.GetPublicSymbol().IsExtern); + Assert.True(c.PartialImplementationPart!.GetPublicSymbol().IsExtern); + + var members = module.GlobalNamespace.GetTypeMember("C").GetMembers().Select(s => s.ToTestDisplayString()).Join("\n"); + AssertEx.AssertEqualToleratingWhitespaceDifferences(""" + void C.E.add + void C.E.remove + event System.Action C.E + C..ctor() + """, members); + } + + static void verifyMetadata(ModuleSymbol module) + { + // IsExtern doesn't round trip from metadata when DllImportAttribute is missing. + // This is consistent with the behavior of partial methods and properties. + + var ev = module.GlobalNamespace.GetMember("C.E"); + Assert.False(ev.GetPublicSymbol().IsExtern); + Assert.False(ev.AddMethod!.GetPublicSymbol().IsExtern); + Assert.False(ev.RemoveMethod!.GetPublicSymbol().IsExtern); + + var c = module.GlobalNamespace.GetMember("C..ctor"); + Assert.False(c.GetPublicSymbol().IsExtern); + + var members = module.GlobalNamespace.GetTypeMember("C").GetMembers().Select(s => s.ToTestDisplayString()).Join("\n"); + AssertEx.AssertEqualToleratingWhitespaceDifferences(""" + void C.E.add + void C.E.remove + C..ctor() + event System.Action C.E + """, members); + } + } + + [Fact] + public void Extern_02() + { + var source = """ + partial class C + { + partial event System.Action E; + extern event System.Action E; + + partial C(); + extern C(); + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (3,33): error CS9275: Partial member 'C.E' must have an implementation part. + // partial event System.Action E; + Diagnostic(ErrorCode.ERR_PartialMemberMissingImplementation, "E").WithArguments("C.E").WithLocation(3, 33), + // (4,32): error CS0102: The type 'C' already contains a definition for 'E' + // extern event System.Action E; + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "E").WithArguments("C", "E").WithLocation(4, 32), + // (4,32): warning CS0626: Method, operator, or accessor 'C.E.remove' is marked external and has no attributes on it. Consider adding a DllImport attribute to specify the external implementation. + // extern event System.Action E; + Diagnostic(ErrorCode.WRN_ExternMethodNoImplementation, "E").WithArguments("C.E.remove").WithLocation(4, 32), + // (6,13): error CS9275: Partial member 'C.C()' must have an implementation part. + // partial C(); + Diagnostic(ErrorCode.ERR_PartialMemberMissingImplementation, "C").WithArguments("C.C()").WithLocation(6, 13), + // (7,12): error CS0111: Type 'C' already defines a member called 'C' with the same parameter types + // extern C(); + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "C").WithArguments("C", "C").WithLocation(7, 12), + // (7,12): warning CS0824: Constructor 'C.C()' is marked external + // extern C(); + Diagnostic(ErrorCode.WRN_ExternCtorNoImplementation, "C").WithArguments("C.C()").WithLocation(7, 12)); + } + + [Fact] + public void Extern_03() + { + var source = """ + partial class C + { + extern partial event System.Action E; + partial event System.Action E { add { } remove { } } + + extern partial C(); + partial C() { } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (3,40): error CS9276: Partial member 'C.E' must have a definition part. + // extern partial event System.Action E; + Diagnostic(ErrorCode.ERR_PartialMemberMissingDefinition, "E").WithArguments("C.E").WithLocation(3, 40), + // (4,33): error CS9278: Partial member 'C.E' may not have multiple implementing declarations. + // partial event System.Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_PartialMemberDuplicateImplementation, "E").WithArguments("C.E").WithLocation(4, 33), + // (4,33): error CS0102: The type 'C' already contains a definition for 'E' + // partial event System.Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "E").WithArguments("C", "E").WithLocation(4, 33), + // (6,20): error CS9276: Partial member 'C.C()' must have a definition part. + // extern partial C(); + Diagnostic(ErrorCode.ERR_PartialMemberMissingDefinition, "C").WithArguments("C.C()").WithLocation(6, 20), + // (7,13): error CS9278: Partial member 'C.C()' may not have multiple implementing declarations. + // partial C() { } + Diagnostic(ErrorCode.ERR_PartialMemberDuplicateImplementation, "C").WithArguments("C.C()").WithLocation(7, 13), + // (7,13): error CS0111: Type 'C' already defines a member called 'C' with the same parameter types + // partial C() { } + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "C").WithArguments("C", "C").WithLocation(7, 13)); + } + + [Fact] + public void Extern_DllImport() + { + var source = """ + using System; + using System.Runtime.InteropServices; + public partial class C + { + public static partial event Action E; + [method: DllImport("something.dll")] + public static extern partial event Action E; + } + """; + CompileAndVerify(source, + sourceSymbolValidator: verify, + symbolValidator: verify) + .VerifyDiagnostics(); + + static void verify(ModuleSymbol module) + { + var e = module.GlobalNamespace.GetMember("C.E"); + Assert.True(e.GetPublicSymbol().IsExtern); + // unexpected mismatch between metadata and entrypoint name: https://github.com/dotnet/roslyn/issues/76882 + verifyAccessor(e.AddMethod!, "add_E", "remove_E"); + verifyAccessor(e.RemoveMethod!, "remove_E", "remove_E"); + + if (module is SourceModuleSymbol) + { + var eImpl = ((SourceEventSymbol)e).PartialImplementationPart!; + Assert.True(eImpl.GetPublicSymbol().IsExtern); + // unexpected mismatch between metadata and entrypoint name: https://github.com/dotnet/roslyn/issues/76882 + verifyAccessor(eImpl.AddMethod!, "add_E", "remove_E"); + verifyAccessor(eImpl.RemoveMethod!, "remove_E", "remove_E"); + } + } + + static void verifyAccessor(MethodSymbol accessor, string expectedMetadataName, string expectedEntryPointName) + { + Assert.True(accessor.GetPublicSymbol().IsExtern); + Assert.Equal(expectedMetadataName, accessor.MetadataName); + Assert.False(accessor.ImplementationAttributes.HasFlag(MethodImplAttributes.Synchronized)); + + var importData = accessor.GetDllImportData()!; + Assert.Equal("something.dll", importData.ModuleName); + Assert.Equal(expectedEntryPointName, importData.EntryPointName); + Assert.Equal(CharSet.None, importData.CharacterSet); + Assert.False(importData.SetLastError); + Assert.False(importData.ExactSpelling); + Assert.Equal(MethodImplAttributes.PreserveSig, accessor.ImplementationAttributes); + Assert.Equal(CallingConvention.Winapi, importData.CallingConvention); + Assert.Null(importData.BestFitMapping); + Assert.Null(importData.ThrowOnUnmappableCharacter); + } + } + + [Fact] + public void Extern_InternalCall() + { + var source = """ + using System; + using System.Runtime.CompilerServices; + public partial class C + { + public partial C(); + [MethodImpl(MethodImplOptions.InternalCall)] + public extern partial C(); + + public partial event Action E; + [method: MethodImpl(MethodImplOptions.InternalCall)] + public extern partial event Action E; + } + """; + CompileAndVerify(source, + sourceSymbolValidator: verifySource, + symbolValidator: verifyMetadata) + .VerifyDiagnostics(); + + static void verifySource(ModuleSymbol module) + { + var ev = module.GlobalNamespace.GetMember("C.E"); + Assert.True(ev.GetPublicSymbol().IsExtern); + Assert.True(ev.AddMethod!.GetPublicSymbol().IsExtern); + Assert.Null(ev.AddMethod!.GetDllImportData()); + Assert.Equal(MethodImplAttributes.InternalCall, ev.AddMethod.ImplementationAttributes); + Assert.False(ev.AddMethod.ImplementationAttributes.HasFlag(MethodImplAttributes.Synchronized)); + Assert.True(ev.RemoveMethod!.GetPublicSymbol().IsExtern); + Assert.Null(ev.RemoveMethod!.GetDllImportData()); + Assert.Equal(MethodImplAttributes.InternalCall, ev.RemoveMethod.ImplementationAttributes); + Assert.False(ev.RemoveMethod.ImplementationAttributes.HasFlag(MethodImplAttributes.Synchronized)); + + var c = module.GlobalNamespace.GetMember("C..ctor"); + Assert.True(c.GetPublicSymbol().IsExtern); + Assert.Null(c.GetDllImportData()); + Assert.Equal(MethodImplAttributes.InternalCall, c.ImplementationAttributes); + } + + static void verifyMetadata(ModuleSymbol module) + { + var ev = module.GlobalNamespace.GetMember("C.E"); + Assert.False(ev.GetPublicSymbol().IsExtern); + Assert.False(ev.AddMethod!.GetPublicSymbol().IsExtern); + Assert.Null(ev.AddMethod!.GetDllImportData()); + Assert.Equal(MethodImplAttributes.InternalCall, ev.AddMethod.ImplementationAttributes); + Assert.False(ev.AddMethod.ImplementationAttributes.HasFlag(MethodImplAttributes.Synchronized)); + Assert.False(ev.RemoveMethod!.GetPublicSymbol().IsExtern); + Assert.Null(ev.RemoveMethod!.GetDllImportData()); + Assert.Equal(MethodImplAttributes.InternalCall, ev.RemoveMethod.ImplementationAttributes); + Assert.False(ev.RemoveMethod.ImplementationAttributes.HasFlag(MethodImplAttributes.Synchronized)); + + var c = module.GlobalNamespace.GetMember("C..ctor"); + Assert.False(c.GetPublicSymbol().IsExtern); + Assert.Null(c.GetDllImportData()); + Assert.Equal(MethodImplAttributes.InternalCall, c.ImplementationAttributes); + } + } + + [Fact] + public void WinRtEvent() + { + var source = """ + partial class C + { + public partial event System.Action E; + public partial event System.Action E { add { return default; } remove { } } + } + """; + CompileAndVerifyWithWinRt(source, + sourceSymbolValidator: validate, + symbolValidator: validate, + options: TestOptions.ReleaseWinMD) + .VerifyDiagnostics() + .VerifyTypeIL("C", """ + .class private auto ansi beforefieldinit C + extends [mscorlib]System.Object + { + // Methods + .method public hidebysig specialname + instance valuetype [mscorlib]System.Runtime.InteropServices.WindowsRuntime.EventRegistrationToken add_E ( + class [mscorlib]System.Action 'value' + ) cil managed + { + // Method begins at RVA 0x2068 + // Code size 10 (0xa) + .maxstack 1 + .locals init ( + [0] valuetype [mscorlib]System.Runtime.InteropServices.WindowsRuntime.EventRegistrationToken + ) + IL_0000: ldloca.s 0 + IL_0002: initobj [mscorlib]System.Runtime.InteropServices.WindowsRuntime.EventRegistrationToken + IL_0008: ldloc.0 + IL_0009: ret + } // end of method C::add_E + .method public hidebysig specialname + instance void remove_E ( + valuetype [mscorlib]System.Runtime.InteropServices.WindowsRuntime.EventRegistrationToken 'value' + ) cil managed + { + // Method begins at RVA 0x207e + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method C::remove_E + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x2080 + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method C::.ctor + // Events + .event [mscorlib]System.Action E + { + .addon instance valuetype [mscorlib]System.Runtime.InteropServices.WindowsRuntime.EventRegistrationToken C::add_E(class [mscorlib]System.Action) + .removeon instance void C::remove_E(valuetype [mscorlib]System.Runtime.InteropServices.WindowsRuntime.EventRegistrationToken) + } + } // end of class C + """); + + static void validate(ModuleSymbol module) + { + var e = module.GlobalNamespace.GetMember("C.E"); + Assert.True(e.IsWindowsRuntimeEvent); + + if (module is SourceModuleSymbol) + { + Assert.True(((SourceEventSymbol)e).PartialImplementationPart!.IsWindowsRuntimeEvent); + } + } + } + + [Fact] + public void Extern_MissingCompareExchange() + { + var source = """ + using System; + partial class C + { + partial event Action E; + extern partial event Action E; + } + """; + var comp = CreateCompilation(source, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All)); + comp.MakeMemberMissing(WellKnownMember.System_Threading_Interlocked__CompareExchange_T); + CompileAndVerify(comp, + sourceSymbolValidator: validate, + symbolValidator: validate, + // PEVerify fails when extern methods lack an implementation + verify: Verification.FailsPEVerify with + { + PEVerifyMessage = """ + Error: Method marked Abstract, Runtime, InternalCall or Imported must have zero RVA, and vice versa. + Error: Method marked Abstract, Runtime, InternalCall or Imported must have zero RVA, and vice versa. + Type load failed. + """, + }) + .VerifyDiagnostics(); + + static void validate(ModuleSymbol module) + { + var e = module.GlobalNamespace.GetMember("C.E"); + Assert.True(e.AddMethod!.ImplementationAttributes.HasFlag(MethodImplAttributes.Synchronized)); + Assert.True(e.RemoveMethod!.ImplementationAttributes.HasFlag(MethodImplAttributes.Synchronized)); + } + } + + [Fact] + public void Metadata() + { + var source = """ + public partial class C + { + public partial event System.Action E; + public partial event System.Action E { add { } remove { } } + public partial C(); + public partial C() { } + } + """; + CompileAndVerify(source, + sourceSymbolValidator: verifySource, + symbolValidator: verifyMetadata) + .VerifyDiagnostics(); + + static void verifySource(ModuleSymbol module) + { + var e = module.GlobalNamespace.GetMember("C.E"); + Assert.True(e.IsPartialDefinition); + Assert.False(e.IsPartialImplementation); + Assert.False(e.HasAssociatedField); + Assert.False(e.IsWindowsRuntimeEvent); + Assert.Null(e.PartialDefinitionPart); + Assert.True(e.SourcePartialImplementationPart!.IsPartialImplementation); + Assert.False(e.SourcePartialImplementationPart.IsPartialDefinition); + Assert.False(e.SourcePartialImplementationPart.HasAssociatedField); + Assert.False(e.SourcePartialImplementationPart.IsWindowsRuntimeEvent); + + var addMethod = e.AddMethod!; + Assert.Equal("add_E", addMethod.Name); + Assert.NotSame(addMethod, e.SourcePartialImplementationPart.AddMethod); + Assert.Same(e, addMethod.AssociatedSymbol); + Assert.Same(e.PartialImplementationPart, addMethod.PartialImplementationPart.AssociatedSymbol); + var removeMethod = e.RemoveMethod!; + Assert.Equal("remove_E", removeMethod.Name); + Assert.NotSame(removeMethod, e.SourcePartialImplementationPart.RemoveMethod); + Assert.Same(e, removeMethod.AssociatedSymbol); + Assert.Same(e.PartialImplementationPart, removeMethod.PartialImplementationPart.AssociatedSymbol); + + var c = module.GlobalNamespace.GetMember("C..ctor"); + Assert.True(c.IsPartialDefinition); + Assert.False(c.IsPartialImplementation); + Assert.Null(c.PartialDefinitionPart); + var cImpl = (SourceConstructorSymbol)c.PartialImplementationPart!; + Assert.True(cImpl.IsPartialImplementation); + Assert.False(cImpl.IsPartialDefinition); + } + + static void verifyMetadata(ModuleSymbol module) + { + var e = module.GlobalNamespace.GetMember("C.E"); + Assert.False(e.HasAssociatedField); + + var addMethod = e.AddMethod!; + Assert.Equal("add_E", addMethod.Name); + var removeMethod = e.RemoveMethod!; + Assert.Equal("remove_E", removeMethod.Name); + } + } + + [Fact] + public void GetDeclaredSymbol() + { + var source = (""" + partial class C + { + public partial event System.Action E, F; + public partial event System.Action E { add { } remove { } } + public partial event System.Action F { add { } remove { } } + + public partial C(); + public partial C() { } + } + """, "Program.cs"); + + var comp = CreateCompilation(source).VerifyDiagnostics(); + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var eventDefs = tree.GetRoot().DescendantNodes().OfType().ToImmutableArray(); + Assert.Equal(2, eventDefs.Length); + + var eventImpls = tree.GetRoot().DescendantNodes().OfType().ToImmutableArray(); + Assert.Equal(2, eventImpls.Length); + + { + var defSymbol = (IEventSymbol)model.GetDeclaredSymbol(eventDefs[0])!; + Assert.Equal("event System.Action C.E", defSymbol.ToTestDisplayString()); + + IEventSymbol implSymbol = model.GetDeclaredSymbol(eventImpls[0])!; + Assert.Equal("event System.Action C.E", implSymbol.ToTestDisplayString()); + + Assert.NotEqual(defSymbol, implSymbol); + Assert.Same(implSymbol, defSymbol.PartialImplementationPart); + Assert.Same(defSymbol, implSymbol.PartialDefinitionPart); + Assert.Null(implSymbol.PartialImplementationPart); + Assert.Null(defSymbol.PartialDefinitionPart); + Assert.True(defSymbol.IsPartialDefinition); + Assert.False(implSymbol.IsPartialDefinition); + + Assert.NotEqual(defSymbol.Locations.Single(), implSymbol.Locations.Single()); + } + + { + var defSymbol = (IEventSymbol)model.GetDeclaredSymbol(eventDefs[1])!; + Assert.Equal("event System.Action C.F", defSymbol.ToTestDisplayString()); + + IEventSymbol implSymbol = model.GetDeclaredSymbol(eventImpls[1])!; + Assert.Equal("event System.Action C.F", implSymbol.ToTestDisplayString()); + + Assert.NotEqual(defSymbol, implSymbol); + Assert.Same(implSymbol, defSymbol.PartialImplementationPart); + Assert.Same(defSymbol, implSymbol.PartialDefinitionPart); + Assert.Null(implSymbol.PartialImplementationPart); + Assert.Null(defSymbol.PartialDefinitionPart); + Assert.True(defSymbol.IsPartialDefinition); + Assert.False(implSymbol.IsPartialDefinition); + + Assert.NotEqual(defSymbol.Locations.Single(), implSymbol.Locations.Single()); + } + + { + var ctors = tree.GetRoot().DescendantNodes().OfType().ToImmutableArray(); + Assert.Equal(2, ctors.Length); + + IMethodSymbol defSymbol = model.GetDeclaredSymbol(ctors[0])!; + Assert.Equal("C..ctor()", defSymbol.ToTestDisplayString()); + + IMethodSymbol implSymbol = model.GetDeclaredSymbol(ctors[1])!; + Assert.Equal("C..ctor()", implSymbol.ToTestDisplayString()); + + Assert.NotEqual(defSymbol, implSymbol); + Assert.Same(implSymbol, defSymbol.PartialImplementationPart); + Assert.Same(defSymbol, implSymbol.PartialDefinitionPart); + Assert.Null(implSymbol.PartialImplementationPart); + Assert.Null(defSymbol.PartialDefinitionPart); + Assert.True(defSymbol.IsPartialDefinition); + Assert.False(implSymbol.IsPartialDefinition); + + Assert.NotEqual(defSymbol.Locations.Single(), implSymbol.Locations.Single()); + } + } + + [Fact] + public void GetDeclaredSymbol_GenericContainer() + { + var source = (""" + partial class C + { + public partial event System.Action E; + public partial event System.Action E { add { } remove { } } + + public partial C(); + public partial C() { } + } + """, "Program.cs"); + + var comp = CreateCompilation(source).VerifyDiagnostics(); + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + { + var defSymbol = (IEventSymbol)model.GetDeclaredSymbol(tree.GetRoot().DescendantNodes().OfType().Single())!; + Assert.Equal("event System.Action C.E", defSymbol.ToTestDisplayString()); + + IEventSymbol implSymbol = model.GetDeclaredSymbol(tree.GetRoot().DescendantNodes().OfType().Single())!; + Assert.Equal("event System.Action C.E", implSymbol.ToTestDisplayString()); + + Assert.NotEqual(defSymbol, implSymbol); + Assert.Same(implSymbol, defSymbol.PartialImplementationPart); + Assert.Same(defSymbol, implSymbol.PartialDefinitionPart); + Assert.Null(implSymbol.PartialImplementationPart); + Assert.Null(defSymbol.PartialDefinitionPart); + Assert.True(defSymbol.IsPartialDefinition); + Assert.False(implSymbol.IsPartialDefinition); + + Assert.NotEqual(defSymbol.Locations.Single(), implSymbol.Locations.Single()); + + var intSymbol = comp.GetSpecialType(SpecialType.System_Int32); + var cOfTSymbol = defSymbol.ContainingType!; + var cOfIntSymbol = cOfTSymbol.Construct([intSymbol]); + + var defOfIntSymbol = (IEventSymbol)cOfIntSymbol.GetMember("E"); + Assert.Equal("event System.Action C.E", defOfIntSymbol.ToTestDisplayString()); + Assert.Null(defOfIntSymbol.PartialImplementationPart); + Assert.Null(defOfIntSymbol.PartialDefinitionPart); + Assert.False(defOfIntSymbol.IsPartialDefinition); + } + + { + var ctors = tree.GetRoot().DescendantNodes().OfType().ToImmutableArray(); + Assert.Equal(2, ctors.Length); + + IMethodSymbol defSymbol = model.GetDeclaredSymbol(ctors[0])!; + Assert.Equal("C..ctor()", defSymbol.ToTestDisplayString()); + + IMethodSymbol implSymbol = model.GetDeclaredSymbol(ctors[1])!; + Assert.Equal("C..ctor()", implSymbol.ToTestDisplayString()); + + Assert.NotEqual(defSymbol, implSymbol); + Assert.Same(implSymbol, defSymbol.PartialImplementationPart); + Assert.Same(defSymbol, implSymbol.PartialDefinitionPart); + Assert.Null(implSymbol.PartialImplementationPart); + Assert.Null(defSymbol.PartialDefinitionPart); + Assert.True(defSymbol.IsPartialDefinition); + Assert.False(implSymbol.IsPartialDefinition); + + Assert.NotEqual(defSymbol.Locations.Single(), implSymbol.Locations.Single()); + + var intSymbol = comp.GetSpecialType(SpecialType.System_Int32); + var cOfTSymbol = defSymbol.ContainingType!; + var cOfIntSymbol = cOfTSymbol.Construct([intSymbol]); + + var defOfIntSymbol = (IMethodSymbol)cOfIntSymbol.GetMember(".ctor"); + Assert.Equal("C..ctor()", defOfIntSymbol.ToTestDisplayString()); + Assert.Null(defOfIntSymbol.PartialImplementationPart); + Assert.Null(defOfIntSymbol.PartialDefinitionPart); + Assert.False(defOfIntSymbol.IsPartialDefinition); + } + } + + [Fact] + public void GetDeclaredSymbol_ConstructorParameter() + { + var source = (""" + partial class C + { + public partial C(int i); + public partial C(int i) { } + } + """, "Program.cs"); + + var comp = CreateCompilation(source).VerifyDiagnostics(); + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var parameters = tree.GetRoot().DescendantNodes().OfType().ToArray(); + Assert.Equal(2, parameters.Length); + + IParameterSymbol defSymbol = model.GetDeclaredSymbol(parameters[0])!; + Assert.Equal("System.Int32 i", defSymbol.ToTestDisplayString()); + + IParameterSymbol implSymbol = model.GetDeclaredSymbol(parameters[1])!; + Assert.Equal("System.Int32 i", implSymbol.ToTestDisplayString()); + + Assert.NotEqual(defSymbol, implSymbol); + Assert.Same(implSymbol, ((IMethodSymbol)defSymbol.ContainingSymbol).PartialImplementationPart!.Parameters.Single()); + Assert.Same(defSymbol, ((IMethodSymbol)implSymbol.ContainingSymbol).PartialDefinitionPart!.Parameters.Single()); + + Assert.NotEqual(defSymbol.Locations.Single(), implSymbol.Locations.Single()); + } + + [Fact] + public void SequencePoints() + { + var source = """ + partial class C + { + partial C(int i); + partial C(int i) + { + System.Console.Write(i); + } + partial event System.Action E; + partial event System.Action E + { + add + { + System.Console.Write(value); + } + remove + { + value(); + } + } + } + """; + CompileAndVerify(source) + .VerifyDiagnostics() + .VerifyMethodBody("C..ctor", """ + { + // Code size 13 (0xd) + .maxstack 1 + // sequence point: partial C(int i) + IL_0000: ldarg.0 + IL_0001: call "object..ctor()" + // sequence point: System.Console.Write(i); + IL_0006: ldarg.1 + IL_0007: call "void System.Console.Write(int)" + // sequence point: } + IL_000c: ret + } + """) + .VerifyMethodBody("C.E.add", """ + { + // Code size 7 (0x7) + .maxstack 1 + // sequence point: System.Console.Write(value); + IL_0000: ldarg.1 + IL_0001: call "void System.Console.Write(object)" + // sequence point: } + IL_0006: ret + } + """) + .VerifyMethodBody("C.E.remove", """ + { + // Code size 7 (0x7) + .maxstack 1 + // sequence point: value(); + IL_0000: ldarg.1 + IL_0001: callvirt "void System.Action.Invoke()" + // sequence point: } + IL_0006: ret + } + """); + } + + [Fact] + public void EmitOrder_01() + { + verify(""" + partial class C + { + partial event System.Action E; + partial event System.Action E { add { } remove { } } + partial C(); + partial C() { } + } + """); + + verify(""" + partial class C + { + partial event System.Action E { add { } remove { } } + partial event System.Action E; + partial C() { } + partial C(); + } + """); + + verify(""" + partial class C + { + partial event System.Action E { add { } remove { } } + partial C() { } + } + """, """ + partial class C + { + partial event System.Action E; + partial C(); + } + """); + + verify(""" + partial class C + { + partial event System.Action E; + partial C(); + } + """, """ + partial class C + { + partial event System.Action E { add { } remove { } } + partial C() { } + } + """); + + void verify(params CSharpTestSource sources) + { + CompileAndVerify(sources, + options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All), + symbolValidator: validate) + .VerifyDiagnostics(); + } + + static void validate(ModuleSymbol module) + { + var members = module.GlobalNamespace.GetTypeMember("C").GetMembers().Select(s => s.ToTestDisplayString()).Join("\n"); + AssertEx.AssertEqualToleratingWhitespaceDifferences(""" + void C.E.add + void C.E.remove + C..ctor() + event System.Action C.E + """, members); + } + } + + [Fact] + public void EmitOrder_02() + { + verify(""" + partial class C + { + partial C(); + partial C() { } + partial event System.Action E; + partial event System.Action E { add { } remove { } } + } + """); + + verify(""" + partial class C + { + partial C() { } + partial C(); + partial event System.Action E { add { } remove { } } + partial event System.Action E; + } + """); + + verify(""" + partial class C + { + partial C(); + partial event System.Action E; + } + """, """ + partial class C + { + partial C() { } + partial event System.Action E { add { } remove { } } + } + """); + + verify(""" + partial class C + { + partial C() { } + partial event System.Action E { add { } remove { } } + } + """, """ + partial class C + { + partial C(); + partial event System.Action E; + } + """); + + void verify(params CSharpTestSource sources) + { + CompileAndVerify(sources, + options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All), + symbolValidator: validate) + .VerifyDiagnostics(); + } + + static void validate(ModuleSymbol module) + { + var members = module.GlobalNamespace.GetTypeMember("C").GetMembers().Select(s => s.ToTestDisplayString()).Join("\n"); + AssertEx.AssertEqualToleratingWhitespaceDifferences(""" + C..ctor() + void C.E.add + void C.E.remove + event System.Action C.E + """, members); + } + } + + [Fact] + public void Use_Valid() + { + var source = """ + using System; + + var c = new C(); + c.E += () => Console.Write(1); + c.E -= () => Console.Write(2); + + partial class C + { + public partial event Action E; + public partial event Action E + { + add { Console.Write(3); value(); } + remove { Console.Write(4); value(); } + } + public partial C(); + public partial C() { Console.Write(5); } + } + """; + CompileAndVerify(source, expectedOutput: "53142").VerifyDiagnostics(); + } + + [Fact] + public void Use_EventAsValue() + { + var source = """ + using System; + + var c = new C(); + Action a = c.E; + c.E(); + + partial class C + { + public partial event Action E; + public partial event Action E { add { } remove { } } + + void M() + { + Action a = this.E; + this.E(); + } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (4,14): error CS0079: The event 'C.E' can only appear on the left hand side of += or -= + // Action a = c.E; + Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "E").WithArguments("C.E").WithLocation(4, 14), + // (5,3): error CS0079: The event 'C.E' can only appear on the left hand side of += or -= + // c.E(); + Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "E").WithArguments("C.E").WithLocation(5, 3), + // (14,25): error CS0079: The event 'C.E' can only appear on the left hand side of += or -= + // Action a = this.E; + Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "E").WithArguments("C.E").WithLocation(14, 25), + // (15,14): error CS0079: The event 'C.E' can only appear on the left hand side of += or -= + // this.E(); + Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "E").WithArguments("C.E").WithLocation(15, 14)); + } + + [Fact] + public void Use_EventAccessorsInaccessible() + { + var source = """ + using System; + + var c = new C(); + c.E += () => { }; + c.E -= () => { }; + + partial class C + { + partial event Action E; + partial event Action E { add { } remove { } } + + void M() + { + this.E += () => { }; + this.E -= () => { }; + } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (4,3): error CS0122: 'C.E' is inaccessible due to its protection level + // c.E += () => { }; + Diagnostic(ErrorCode.ERR_BadAccess, "E").WithArguments("C.E").WithLocation(4, 3), + // (5,3): error CS0122: 'C.E' is inaccessible due to its protection level + // c.E -= () => { }; + Diagnostic(ErrorCode.ERR_BadAccess, "E").WithArguments("C.E").WithLocation(5, 3)); + } + + [Fact] + public void Use_Static() + { + var source = """ + var c = new C(); + c.E += () => { }; + C.E += () => { }; // 1 + c.F += () => { }; // 2 + C.F += () => { }; + + partial class C + { + public partial event System.Action E; + public static partial event System.Action F; + } + partial class C + { + public partial event System.Action E + { + add + { + this.E += null; + E += null; + C.E += null; // 3 + } + remove + { + this.F += null; // 4 + F += null; + C.F += null; + } + } + public static partial event System.Action F + { + add + { + this.E += null; // 5 + E += null; // 6 + C.E += null; // 7 + } + remove + { + this.F += null; // 8 + F += null; + C.F += null; + } + } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (3,1): error CS0120: An object reference is required for the non-static field, method, or property 'C.E' + // C.E += () => { }; // 1 + Diagnostic(ErrorCode.ERR_ObjectRequired, "C.E").WithArguments("C.E").WithLocation(3, 1), + // (4,1): error CS0176: Member 'C.F' cannot be accessed with an instance reference; qualify it with a type name instead + // c.F += () => { }; // 2 + Diagnostic(ErrorCode.ERR_ObjectProhibited, "c.F").WithArguments("C.F").WithLocation(4, 1), + // (20,13): error CS0120: An object reference is required for the non-static field, method, or property 'C.E' + // C.E += null; // 3 + Diagnostic(ErrorCode.ERR_ObjectRequired, "C.E").WithArguments("C.E").WithLocation(20, 13), + // (24,13): error CS0176: Member 'C.F' cannot be accessed with an instance reference; qualify it with a type name instead + // this.F += null; // 4 + Diagnostic(ErrorCode.ERR_ObjectProhibited, "this.F").WithArguments("C.F").WithLocation(24, 13), + // (33,13): error CS0026: Keyword 'this' is not valid in a static property, static method, or static field initializer + // this.E += null; // 5 + Diagnostic(ErrorCode.ERR_ThisInStaticMeth, "this").WithLocation(33, 13), + // (34,13): error CS0120: An object reference is required for the non-static field, method, or property 'C.E' + // E += null; // 6 + Diagnostic(ErrorCode.ERR_ObjectRequired, "E").WithArguments("C.E").WithLocation(34, 13), + // (35,13): error CS0120: An object reference is required for the non-static field, method, or property 'C.E' + // C.E += null; // 7 + Diagnostic(ErrorCode.ERR_ObjectRequired, "C.E").WithArguments("C.E").WithLocation(35, 13), + // (39,13): error CS0026: Keyword 'this' is not valid in a static property, static method, or static field initializer + // this.F += null; // 8 + Diagnostic(ErrorCode.ERR_ThisInStaticMeth, "this").WithLocation(39, 13), + // (39,13): error CS0176: Member 'C.F' cannot be accessed with an instance reference; qualify it with a type name instead + // this.F += null; // 8 + Diagnostic(ErrorCode.ERR_ObjectProhibited, "this.F").WithArguments("C.F").WithLocation(39, 13)); + } + + [Fact] + public void Use_Inheritance() + { + var source = """ + using System; + + var c = new C1(); + c.E += () => { }; + c = new C2(); + c.E += () => { }; + + partial class C1 + { + public virtual partial event Action E; + public virtual partial event Action E { add { Console.Write(1); } remove { } } + } + partial class C2 : C1 + { + public override partial event Action E; + public override partial event Action E { add { Console.Write(2); } remove { } } + } + """; + CompileAndVerify(source, expectedOutput: "12").VerifyDiagnostics(); + } + + [Fact] + public void Difference_Accessibility() + { + var source = """ + partial class C + { + partial C(); + internal partial C(int x); + partial event System.Action E, F; + public partial event System.Action G; + } + partial class C + { + public partial C() { } + private partial C(int x) { } + private partial event System.Action E { add { } remove { } } + partial event System.Action F { add { } remove { } } + internal partial event System.Action G { add { } remove { } } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (10,20): error CS8799: Both partial member declarations must have identical accessibility modifiers. + // public partial C() { } + Diagnostic(ErrorCode.ERR_PartialMemberAccessibilityDifference, "C").WithLocation(10, 20), + // (11,21): error CS8799: Both partial member declarations must have identical accessibility modifiers. + // private partial C(int x) { } + Diagnostic(ErrorCode.ERR_PartialMemberAccessibilityDifference, "C").WithLocation(11, 21), + // (12,41): error CS8799: Both partial member declarations must have identical accessibility modifiers. + // private partial event System.Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_PartialMemberAccessibilityDifference, "E").WithLocation(12, 41), + // (14,42): error CS8799: Both partial member declarations must have identical accessibility modifiers. + // internal partial event System.Action G { add { } remove { } } + Diagnostic(ErrorCode.ERR_PartialMemberAccessibilityDifference, "G").WithLocation(14, 42)); + } + + [Fact] + public void Difference_Type() + { + var source = """ + using A = System.Action; + partial class C + { + partial event System.Action E, F; + partial event System.Action<(int X, int Y)> G; + partial event System.Action<(string X, string Y)> H; + partial event System.Action I; + partial event A J; + } + partial class C + { + partial event System.Func E { add { } remove { } } + partial event System.Action F { add { } remove { } } + partial event System.Action<(int A, int B)> G { add { } remove { } } + partial event System.Action<(int A, int B)> H { add { } remove { } } + partial event System.Action I { add { } remove { } } + partial event System.Action J { add { } remove { } } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (12,36): error CS9255: Both partial member declarations must have the same type. + // partial event System.Func E { add { } remove { } } + Diagnostic(ErrorCode.ERR_PartialMemberTypeDifference, "E").WithLocation(12, 36), + // (14,49): error CS8142: Both partial member declarations, 'C.G' and 'C.G', must use the same tuple element names. + // partial event System.Action<(int A, int B)> G { add { } remove { } } + Diagnostic(ErrorCode.ERR_PartialMemberInconsistentTupleNames, "G").WithArguments("C.G", "C.G").WithLocation(14, 49), + // (15,49): error CS9255: Both partial member declarations must have the same type. + // partial event System.Action<(int A, int B)> H { add { } remove { } } + Diagnostic(ErrorCode.ERR_PartialMemberTypeDifference, "H").WithLocation(15, 49), + // (16,41): warning CS9256: Partial member declarations 'event Action C.I' and 'event Action C.I' have signature differences. + // partial event System.Action I { add { } remove { } } + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "I").WithArguments("event Action C.I", "event Action C.I").WithLocation(16, 41)); + } + + [Fact] + public void Difference_ParameterType() + { + var source = """ + partial class C1 + { + partial C1(string x); + partial C1(int x) { } + } + partial class C2 + { + partial C2(dynamic x); + partial C2(object x) { } + } + partial class C3 + { + partial C3((int X, int Y) x); + partial C3((int A, int B) x) { } + } + partial class C4 + { + partial C4((int X, int Y) x); + partial C4((string A, string B) x) { } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (3,13): error CS9275: Partial member 'C1.C1(string)' must have an implementation part. + // partial C1(string x); + Diagnostic(ErrorCode.ERR_PartialMemberMissingImplementation, "C1").WithArguments("C1.C1(string)").WithLocation(3, 13), + // (4,13): error CS9276: Partial member 'C1.C1(int)' must have a definition part. + // partial C1(int x) { } + Diagnostic(ErrorCode.ERR_PartialMemberMissingDefinition, "C1").WithArguments("C1.C1(int)").WithLocation(4, 13), + // (9,13): warning CS9256: Partial member declarations 'C2.C2(dynamic x)' and 'C2.C2(object x)' have signature differences. + // partial C2(object x) { } + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "C2").WithArguments("C2.C2(dynamic x)", "C2.C2(object x)").WithLocation(9, 13), + // (14,13): error CS8142: Both partial member declarations, 'C3.C3((int X, int Y))' and 'C3.C3((int A, int B))', must use the same tuple element names. + // partial C3((int A, int B) x) { } + Diagnostic(ErrorCode.ERR_PartialMemberInconsistentTupleNames, "C3").WithArguments("C3.C3((int X, int Y))", "C3.C3((int A, int B))").WithLocation(14, 13), + // (18,13): error CS9275: Partial member 'C4.C4((int X, int Y))' must have an implementation part. + // partial C4((int X, int Y) x); + Diagnostic(ErrorCode.ERR_PartialMemberMissingImplementation, "C4").WithArguments("C4.C4((int X, int Y))").WithLocation(18, 13), + // (19,13): error CS9276: Partial member 'C4.C4((string A, string B))' must have a definition part. + // partial C4((string A, string B) x) { } + Diagnostic(ErrorCode.ERR_PartialMemberMissingDefinition, "C4").WithArguments("C4.C4((string A, string B))").WithLocation(19, 13)); + } + + [Fact] + public void Difference_Nullability() + { + var source = """ + partial class C + { + partial event System.Action? E; + partial event System.Action F; + partial event System.Action G; + } + partial class C + { + partial event System.Action E { add { } remove { } } + partial event System.Action F { add { } remove { } } + partial event System.Action? G { add { } remove { } } + } + """; + + var expectedDiagnostics = new[] + { + // (9,33): warning CS9256: Partial member declarations 'event Action? C.E' and 'event Action C.E' have signature differences. + // partial event System.Action E { add { } remove { } } + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "E").WithArguments("event Action? C.E", "event Action C.E").WithLocation(9, 33), + // (10,41): warning CS9256: Partial member declarations 'event Action C.F' and 'event Action C.F' have signature differences. + // partial event System.Action F { add { } remove { } } + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "F").WithArguments("event Action C.F", "event Action C.F").WithLocation(10, 41), + // (11,34): warning CS9256: Partial member declarations 'event Action C.G' and 'event Action? C.G' have signature differences. + // partial event System.Action? G { add { } remove { } } + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "G").WithArguments("event Action C.G", "event Action? C.G").WithLocation(11, 34) + }; + + CreateCompilation(source, options: TestOptions.DebugDll.WithNullableContextOptions(NullableContextOptions.Enable)).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source, options: TestOptions.DebugDll.WithNullableContextOptions(NullableContextOptions.Annotations)).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Difference_ParameterNullability() + { + var source = """ + partial class C1 + { + partial C1(string x); + partial C1(string? x) { } + } + partial class C2 + { + partial C2(string? x); + partial C2(string x) { } + } + """; + + var expectedDiagnostics = new[] + { + // (4,13): warning CS9256: Partial member declarations 'C1.C1(string x)' and 'C1.C1(string? x)' have signature differences. + // partial C1(string? x) { } + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "C1").WithArguments("C1.C1(string x)", "C1.C1(string? x)").WithLocation(4, 13), + // (9,13): warning CS9256: Partial member declarations 'C2.C2(string? x)' and 'C2.C2(string x)' have signature differences. + // partial C2(string x) { } + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "C2").WithArguments("C2.C2(string? x)", "C2.C2(string x)").WithLocation(9, 13) + }; + + CreateCompilation(source, options: TestOptions.DebugDll.WithNullableContextOptions(NullableContextOptions.Enable)).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source, options: TestOptions.DebugDll.WithNullableContextOptions(NullableContextOptions.Annotations)).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Difference_NullabilityContext() + { + var source = """ + #nullable enable + partial class C + { + partial event System.Action E; + partial event System.Action? F; + #nullable disable + partial event System.Action G; + } + + #nullable disable + partial class C + { + partial event System.Action E { add { } remove { } } + partial event System.Action F { add { } remove { } } + #nullable enable + partial event System.Action G { add { } remove { } } + } + """; + + var comp = CreateCompilation(source).VerifyDiagnostics(); + + var e = comp.GetMember("C.E"); + Assert.True(e.IsPartialDefinition); + Assert.Equal(NullableAnnotation.NotAnnotated, e.TypeWithAnnotations.NullableAnnotation); + + var f = comp.GetMember("C.F"); + Assert.True(f.IsPartialDefinition); + Assert.Equal(NullableAnnotation.Annotated, f.TypeWithAnnotations.NullableAnnotation); + + var g = comp.GetMember("C.G"); + Assert.True(g.IsPartialDefinition); + Assert.Equal(NullableAnnotation.Oblivious, g.TypeWithAnnotations.NullableAnnotation); + } + + [Fact] + public void Difference_NullabilityAnalysis() + { + // The implementation part signature is used to analyze the implementation part bodies. + // The definition part signature is used to analyze use sites. + // Note that event assignments are not checked for nullability: https://github.com/dotnet/roslyn/issues/31018 + var source = """ + #nullable enable + + var c = new C(0, null); + c = new C(null, 0); + c.E += null; + c.E -= null; + c.F += null; + c.F -= null; + + partial class C + { + public partial C(int x, string? y); + public partial C(string x, int y); + public partial event System.Action E; + public partial event System.Action? F; + } + + partial class C + { + public partial C(int x, string y) + { + y.ToString(); + } + public partial C(string? x, int y) + { + x.ToString(); + } + public partial event System.Action? E { add { value(); } remove { value(); } } + public partial event System.Action F { add { value(); } remove { value(); } } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (4,11): warning CS8625: Cannot convert null literal to non-nullable reference type. + // c = new C(null, 0); + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(4, 11), + // (20,20): warning CS9256: Partial member declarations 'C.C(int x, string? y)' and 'C.C(int x, string y)' have signature differences. + // public partial C(int x, string y) + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "C").WithArguments("C.C(int x, string? y)", "C.C(int x, string y)").WithLocation(20, 20), + // (24,20): warning CS9256: Partial member declarations 'C.C(string x, int y)' and 'C.C(string? x, int y)' have signature differences. + // public partial C(string? x, int y) + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "C").WithArguments("C.C(string x, int y)", "C.C(string? x, int y)").WithLocation(24, 20), + // (26,9): warning CS8602: Dereference of a possibly null reference. + // x.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(26, 9), + // (28,41): warning CS9256: Partial member declarations 'event Action C.E' and 'event Action? C.E' have signature differences. + // public partial event System.Action? E { add { value(); } remove { value(); } } + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "E").WithArguments("event Action C.E", "event Action? C.E").WithLocation(28, 41), + // (28,51): warning CS8602: Dereference of a possibly null reference. + // public partial event System.Action? E { add { value(); } remove { value(); } } + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "value").WithLocation(28, 51), + // (28,71): warning CS8602: Dereference of a possibly null reference. + // public partial event System.Action? E { add { value(); } remove { value(); } } + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "value").WithLocation(28, 71), + // (29,40): warning CS9256: Partial member declarations 'event Action? C.F' and 'event Action C.F' have signature differences. + // public partial event System.Action F { add { value(); } remove { value(); } } + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "F").WithArguments("event Action? C.F", "event Action C.F").WithLocation(29, 40)); + } + + [Fact] + public void Difference_Static() + { + var source = """ + partial class C + { + partial event System.Action E, F; + } + partial class C + { + static partial event System.Action E { add { } remove { } } + partial event System.Action F { add { } remove { } } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (7,40): error CS0763: Both partial member declarations must be static or neither may be static + // static partial event System.Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_PartialMemberStaticDifference, "E").WithLocation(7, 40)); + } + + [Fact] + public void Difference_Unsafe_01() + { + var source = """ + partial class C + { + unsafe partial C(); + unsafe partial event System.Action E, F; + } + partial class C + { + partial C() { } + unsafe partial event System.Action E { add { } remove { } } + partial event System.Action F { add { } remove { } } + } + """; + CreateCompilation(source, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (8,13): error CS0764: Both partial member declarations must be unsafe or neither may be unsafe + // partial C() { } + Diagnostic(ErrorCode.ERR_PartialMemberUnsafeDifference, "C").WithLocation(8, 13), + // (10,33): error CS0764: Both partial member declarations must be unsafe or neither may be unsafe + // partial event System.Action F { add { } remove { } } + Diagnostic(ErrorCode.ERR_PartialMemberUnsafeDifference, "F").WithLocation(10, 33)); + } + + [Fact] + public void Difference_Unsafe_02() + { + var source = """ + unsafe partial class C + { + partial C(int* p); + partial event System.Action E, F; + } + partial class C + { + partial C(int* p) { } + partial event System.Action E { add { int* p = null; } remove { } } + partial event System.Action F { add { int* p = null; } remove { } } + } + """; + CreateCompilation(source, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (8,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // partial C(int* p) { } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(8, 15), + // (9,43): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // partial event System.Action E { add { int* p = null; } remove { } } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(9, 43), + // (10,43): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // partial event System.Action F { add { int* p = null; } remove { } } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(10, 43)); + } + + [Fact] + public void Difference_ExtendedModifiers() + { + var source = """ + partial class C1 + { + protected virtual partial event System.Action E, F; + protected partial event System.Action E { add { } remove { } } + protected virtual partial event System.Action F { add { } remove { } } + } + partial class C2 : C1 + { + protected override partial event System.Action E; + protected sealed partial event System.Action E { add { } remove { } } + protected new partial event System.Action F; + protected partial event System.Action F { add { } remove { } } + } + partial class C3 : C1 + { + protected sealed partial event System.Action E; + protected partial event System.Action E { add { } remove { } } + protected override partial event System.Action F; + protected override sealed partial event System.Action F { add { } remove { } } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (4,43): error CS8800: Both partial member declarations must have identical combinations of 'virtual', 'override', 'sealed', and 'new' modifiers. + // protected partial event System.Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_PartialMemberExtendedModDifference, "E").WithLocation(4, 43), + // (10,50): error CS8800: Both partial member declarations must have identical combinations of 'virtual', 'override', 'sealed', and 'new' modifiers. + // protected sealed partial event System.Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_PartialMemberExtendedModDifference, "E").WithLocation(10, 50), + // (12,43): error CS8800: Both partial member declarations must have identical combinations of 'virtual', 'override', 'sealed', and 'new' modifiers. + // protected partial event System.Action F { add { } remove { } } + Diagnostic(ErrorCode.ERR_PartialMemberExtendedModDifference, "F").WithLocation(12, 43), + // (16,50): warning CS0114: 'C3.E' hides inherited member 'C1.E'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword. + // protected sealed partial event System.Action E; + Diagnostic(ErrorCode.WRN_NewOrOverrideExpected, "E").WithArguments("C3.E", "C1.E").WithLocation(16, 50), + // (16,50): error CS0238: 'C3.E' cannot be sealed because it is not an override + // protected sealed partial event System.Action E; + Diagnostic(ErrorCode.ERR_SealedNonOverride, "E").WithArguments("C3.E").WithLocation(16, 50), + // (17,43): error CS8800: Both partial member declarations must have identical combinations of 'virtual', 'override', 'sealed', and 'new' modifiers. + // protected partial event System.Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_PartialMemberExtendedModDifference, "E").WithLocation(17, 43), + // (19,59): error CS8800: Both partial member declarations must have identical combinations of 'virtual', 'override', 'sealed', and 'new' modifiers. + // protected override sealed partial event System.Action F { add { } remove { } } + Diagnostic(ErrorCode.ERR_PartialMemberExtendedModDifference, "F").WithLocation(19, 59)); + } + + [Fact] + public void Difference_RefKind() + { + var source = """ + partial class C1 + { + partial C1(int x); + partial C1(ref int x) { } + } + partial class C2 + { + partial C2(in int x); + partial C2(ref readonly int x) { } + } + partial class C3 + { + partial C3(ref int x); + partial C3(out int x) => throw null; + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (3,13): error CS9275: Partial member 'C1.C1(int)' must have an implementation part. + // partial C1(int x); + Diagnostic(ErrorCode.ERR_PartialMemberMissingImplementation, "C1").WithArguments("C1.C1(int)").WithLocation(3, 13), + // (4,13): error CS9276: Partial member 'C1.C1(ref int)' must have a definition part. + // partial C1(ref int x) { } + Diagnostic(ErrorCode.ERR_PartialMemberMissingDefinition, "C1").WithArguments("C1.C1(ref int)").WithLocation(4, 13), + // (8,13): error CS9275: Partial member 'C2.C2(in int)' must have an implementation part. + // partial C2(in int x); + Diagnostic(ErrorCode.ERR_PartialMemberMissingImplementation, "C2").WithArguments("C2.C2(in int)").WithLocation(8, 13), + // (9,13): error CS9276: Partial member 'C2.C2(ref readonly int)' must have a definition part. + // partial C2(ref readonly int x) { } + Diagnostic(ErrorCode.ERR_PartialMemberMissingDefinition, "C2").WithArguments("C2.C2(ref readonly int)").WithLocation(9, 13), + // (9,13): error CS0663: 'C2' cannot define an overloaded constructor that differs only on parameter modifiers 'ref readonly' and 'in' + // partial C2(ref readonly int x) { } + Diagnostic(ErrorCode.ERR_OverloadRefKind, "C2").WithArguments("C2", "constructor", "ref readonly", "in").WithLocation(9, 13), + // (13,13): error CS9275: Partial member 'C3.C3(ref int)' must have an implementation part. + // partial C3(ref int x); + Diagnostic(ErrorCode.ERR_PartialMemberMissingImplementation, "C3").WithArguments("C3.C3(ref int)").WithLocation(13, 13), + // (14,13): error CS9276: Partial member 'C3.C3(out int)' must have a definition part. + // partial C3(out int x) => throw null; + Diagnostic(ErrorCode.ERR_PartialMemberMissingDefinition, "C3").WithArguments("C3.C3(out int)").WithLocation(14, 13), + // (14,13): error CS0663: 'C3' cannot define an overloaded constructor that differs only on parameter modifiers 'out' and 'ref' + // partial C3(out int x) => throw null; + Diagnostic(ErrorCode.ERR_OverloadRefKind, "C3").WithArguments("C3", "constructor", "out", "ref").WithLocation(14, 13)); + } + + [Fact] + public void Difference_Params() + { + var source = """ + using System.Collections.Generic; + partial class C1 + { + partial C1(object[] x); + partial C1(params object[] x) { } + } + partial class C2 + { + partial C2(int x, params IEnumerable y); + partial C2(int x, IEnumerable y) { } + } + partial class C3 + { + partial C3(params IEnumerable x, int y); + partial C3(IEnumerable x, int y) { } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (5,13): error CS0758: Both partial member declarations must use a params parameter or neither may use a params parameter + // partial C1(params object[] x) { } + Diagnostic(ErrorCode.ERR_PartialMemberParamsDifference, "C1").WithLocation(5, 13), + // (10,13): error CS0758: Both partial member declarations must use a params parameter or neither may use a params parameter + // partial C2(int x, IEnumerable y) { } + Diagnostic(ErrorCode.ERR_PartialMemberParamsDifference, "C2").WithLocation(10, 13), + // (14,16): error CS0231: A params parameter must be the last parameter in a parameter list + // partial C3(params IEnumerable x, int y); + Diagnostic(ErrorCode.ERR_ParamsLast, "params IEnumerable x").WithLocation(14, 16)); + } + + [Fact] + public void Difference_ParameterNames() + { + var source = """ + var c = new C(x: 123); + + partial class C + { + public partial C(int x); + public partial C(int y) { System.Console.Write(y); } + } + """; + CompileAndVerify(source, + sourceSymbolValidator: validate, + symbolValidator: validate, + expectedOutput: "123") + .VerifyDiagnostics( + // (6,20): warning CS9256: Partial member declarations 'C.C(int x)' and 'C.C(int y)' have signature differences. + // public partial C(int y) { System.Console.Write(y); } + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "C").WithArguments("C.C(int x)", "C.C(int y)").WithLocation(6, 20)); + + static void validate(ModuleSymbol module) + { + var indexer = module.GlobalNamespace.GetMember("C..ctor"); + AssertEx.Equal("x", indexer.Parameters.Single().Name); + } + } + + [Fact] + public void Difference_ParameterNames_NameOf() + { + var source = """ + using System; + + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] + class A : Attribute { public A(string s) { } } + + partial class C + { + [A(nameof(p1))] + [A(nameof(p2))] // 1 + partial C( + [A(nameof(p1))] // 2 + [A(nameof(p2))] + int p1); + + [A(nameof(p1))] + [A(nameof(p2))] // 3 + partial C( + [A(nameof(p1))] // 4 + [A(nameof(p2))] + int p2) + { + Console.WriteLine(nameof(p1)); // 5 + Console.WriteLine(nameof(p2)); + } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (17,13): warning CS9256: Partial member declarations 'C.C(int p1)' and 'C.C(int p2)' have signature differences. + // partial C( + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "C").WithArguments("C.C(int p1)", "C.C(int p2)").WithLocation(17, 13), + // (18,19): error CS0103: The name 'p1' does not exist in the current context + // [A(nameof(p1))] // 4 + Diagnostic(ErrorCode.ERR_NameNotInContext, "p1").WithArguments("p1").WithLocation(18, 19), + // (11,19): error CS0103: The name 'p1' does not exist in the current context + // [A(nameof(p1))] // 2 + Diagnostic(ErrorCode.ERR_NameNotInContext, "p1").WithArguments("p1").WithLocation(11, 19), + // (9,15): error CS0103: The name 'p2' does not exist in the current context + // [A(nameof(p2))] // 1 + Diagnostic(ErrorCode.ERR_NameNotInContext, "p2").WithArguments("p2").WithLocation(9, 15), + // (16,15): error CS0103: The name 'p2' does not exist in the current context + // [A(nameof(p2))] // 3 + Diagnostic(ErrorCode.ERR_NameNotInContext, "p2").WithArguments("p2").WithLocation(16, 15), + // (22,34): error CS0103: The name 'p1' does not exist in the current context + // Console.WriteLine(nameof(p1)); // 5 + Diagnostic(ErrorCode.ERR_NameNotInContext, "p1").WithArguments("p1").WithLocation(22, 34)); + } + + [Fact] + public void Difference_OptionalParameters() + { + var source = """ + var c1 = new C1(); + var c2 = new C2(); + + partial class C1 + { + public partial C1(int x = 1); + public partial C1(int x) { } + } + partial class C2 + { + public partial C2(int x); + public partial C2(int x = 1) { } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (2,14): error CS7036: There is no argument given that corresponds to the required parameter 'x' of 'C2.C2(int)' + // var c2 = new C2(); + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "C2").WithArguments("x", "C2.C2(int)").WithLocation(2, 14), + // (12,27): warning CS1066: The default value specified for parameter 'x' will have no effect because it applies to a member that is used in contexts that do not allow optional arguments + // public partial C2(int x = 1) { } + Diagnostic(ErrorCode.WRN_DefaultValueForUnconsumedLocation, "x").WithArguments("x").WithLocation(12, 27)); + } + + [Fact] + public void Difference_DefaultParameterValues() + { + var source = """ + var c = new C(); + + partial class C + { + public partial C(int x = 1); + public partial C(int x = 2) { System.Console.Write(x); } + } + """; + CompileAndVerify(source, expectedOutput: "1").VerifyDiagnostics( + // (6,26): warning CS1066: The default value specified for parameter 'x' will have no effect because it applies to a member that is used in contexts that do not allow optional arguments + // public partial C(int x = 2) { System.Console.Write(x); } + Diagnostic(ErrorCode.WRN_DefaultValueForUnconsumedLocation, "x").WithArguments("x").WithLocation(6, 26)); + } + + [Fact] + public void Difference_Scoped() + { + var source = """ + using System.Diagnostics.CodeAnalysis; + partial class C1 + { + partial C1(scoped ref int x); + partial C1(ref int x) { } + } + partial class C2 + { + partial C2(ref int x); + partial C2(scoped ref int x) { } + } + partial class C3 + { + partial C3([UnscopedRef] ref int x); + partial C3(ref int x) { } + } + partial class C4 + { + partial C4(ref int x); + partial C4([UnscopedRef] ref int x) { } + } + """; + CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics( + // (5,13): error CS8988: The 'scoped' modifier of parameter 'x' doesn't match partial definition. + // partial C1(ref int x) { } + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "C1").WithArguments("x").WithLocation(5, 13), + // (10,13): error CS8988: The 'scoped' modifier of parameter 'x' doesn't match partial definition. + // partial C2(scoped ref int x) { } + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "C2").WithArguments("x").WithLocation(10, 13)); + } + + [Theory] + [InlineData("A(1)", "B(2)")] + [InlineData("B(2)", "A(1)")] + [InlineData("A(1), B(1)", "A(2), B(2)")] + public void Attributes(string declAttributes, string implAttributes) + { + var source1 = """ + using System; + + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] + class A : Attribute { public A(int i) { } } + + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] + class B : Attribute { public B(int i) { } } + """; + + var source2 = $$""" + public partial class C + { + [{{declAttributes}}] public partial C([{{declAttributes}}] int x); + [{{declAttributes}}] public partial event System.Action E; + } + """; + + var source3 = $$""" + public partial class C + { + [{{implAttributes}}] public partial C([{{implAttributes}}] int x) { } + [{{implAttributes}}] public partial event System.Action E { add { } remove { } } + } + """; + + CompileAndVerify([source1, source2, source3], + symbolValidator: validate, + sourceSymbolValidator: validate) + .VerifyDiagnostics(); + + CompileAndVerify([source1, source3, source2], + symbolValidator: validate, + sourceSymbolValidator: validate) + .VerifyDiagnostics(); + + void validate(ModuleSymbol module) + { + var ctor = module.GlobalNamespace.GetMember("C..ctor"); + assertEqual([declAttributes, implAttributes], ctor.GetAttributes()); + + var ctorParam = ctor.GetParameters().Single(); + assertEqual([implAttributes, declAttributes], ctorParam.GetAttributes()); + + var ev = module.GlobalNamespace.GetMember("C.E"); + assertEqual([declAttributes, implAttributes], ev.GetAttributes()); + + if (module is SourceModuleSymbol) + { + assertEqual([declAttributes, implAttributes], ((SourceConstructorSymbol)ctor).PartialImplementationPart!.GetAttributes()); + assertEqual([declAttributes, implAttributes], ((SourceEventSymbol)ev).PartialImplementationPart!.GetAttributes()); + } + } + + static void assertEqual(IEnumerable expected, ImmutableArray actual) + { + AssertEx.Equal(string.Join(", ", expected), actual.ToStrings().Join(", ")); + } + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/77254")] + public void Attributes_Locations() + { + // Note that [method:] is not allowed on partial events. + // Therefore users have no way to specify accessor attributes on the definition part. + // Ideally, this would be possible and we would join attributes from accessors with [method:] attributes from the event. + // However, current implementation of attribute matching is not strong enough to do that (there can be only one attribute owner symbol kind). + + var source = """ + using System; + + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] + public class A : Attribute { public A(int i) { } } + + partial class C + { + [A(1)] [method: A(11)] [param: A(21)] [return: A(31)] [event: A(41)] [field: A(51)] public partial event Action E; + [A(2)] [method: A(12)] [param: A(22)] [return: A(32)] [event: A(42)] [field: A(52)] public partial event Action E + { + [A(3)] [method: A(13)] [param: A(23)] [return: A(33)] [event: A(43)] [field: A(53)] add { } + [A(4)] [method: A(14)] [param: A(24)] [return: A(34)] [event: A(44)] [field: A(54)] remove { } + } + + [A(1)] [method: A(11)] [param: A(21)] [return: A(31)] [event: A(41)] [field: A(51)] public partial event Action F; + [A(2)] [method: A(12)] [param: A(22)] [return: A(32)] [event: A(42)] [field: A(52)] public extern partial event Action F; + } + """; + CompileAndVerify(source, + symbolValidator: validate, + sourceSymbolValidator: validate, + // PEVerify fails when extern methods lack an implementation + verify: Verification.FailsPEVerify with + { + PEVerifyMessage = """ + Error: Method marked Abstract, Runtime, InternalCall or Imported must have zero RVA, and vice versa. + Error: Method marked Abstract, Runtime, InternalCall or Imported must have zero RVA, and vice versa. + Type load failed. + """, + }) + .VerifyDiagnostics( + // (8,13): warning CS0657: 'method' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'event'. All attributes in this block will be ignored. + // [A(1)] [method: A(11)] [param: A(21)] [return: A(31)] [event: A(41)] [field: A(51)] public partial event Action E; + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "method").WithArguments("method", "event").WithLocation(8, 13), + // (8,29): warning CS0657: 'param' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'event'. All attributes in this block will be ignored. + // [A(1)] [method: A(11)] [param: A(21)] [return: A(31)] [event: A(41)] [field: A(51)] public partial event Action E; + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "param").WithArguments("param", "event").WithLocation(8, 29), + // (8,44): warning CS0657: 'return' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'event'. All attributes in this block will be ignored. + // [A(1)] [method: A(11)] [param: A(21)] [return: A(31)] [event: A(41)] [field: A(51)] public partial event Action E; + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "return").WithArguments("return", "event").WithLocation(8, 44), + // (8,75): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'event'. All attributes in this block will be ignored. + // [A(1)] [method: A(11)] [param: A(21)] [return: A(31)] [event: A(41)] [field: A(51)] public partial event Action E; + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "event").WithLocation(8, 75), + // (9,13): warning CS0657: 'method' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'event'. All attributes in this block will be ignored. + // [A(2)] [method: A(12)] [param: A(22)] [return: A(32)] [event: A(42)] [field: A(52)] public partial event Action E + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "method").WithArguments("method", "event").WithLocation(9, 13), + // (9,29): warning CS0657: 'param' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'event'. All attributes in this block will be ignored. + // [A(2)] [method: A(12)] [param: A(22)] [return: A(32)] [event: A(42)] [field: A(52)] public partial event Action E + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "param").WithArguments("param", "event").WithLocation(9, 29), + // (9,44): warning CS0657: 'return' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'event'. All attributes in this block will be ignored. + // [A(2)] [method: A(12)] [param: A(22)] [return: A(32)] [event: A(42)] [field: A(52)] public partial event Action E + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "return").WithArguments("return", "event").WithLocation(9, 44), + // (9,75): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'event'. All attributes in this block will be ignored. + // [A(2)] [method: A(12)] [param: A(22)] [return: A(32)] [event: A(42)] [field: A(52)] public partial event Action E + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "event").WithLocation(9, 75), + // (11,64): warning CS0657: 'event' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, param, return'. All attributes in this block will be ignored. + // [A(3)] [method: A(13)] [param: A(23)] [return: A(33)] [event: A(43)] [field: A(53)] add { } + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "event").WithArguments("event", "method, param, return").WithLocation(11, 64), + // (11,79): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, param, return'. All attributes in this block will be ignored. + // [A(3)] [method: A(13)] [param: A(23)] [return: A(33)] [event: A(43)] [field: A(53)] add { } + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "method, param, return").WithLocation(11, 79), + // (12,64): warning CS0657: 'event' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, param, return'. All attributes in this block will be ignored. + // [A(4)] [method: A(14)] [param: A(24)] [return: A(34)] [event: A(44)] [field: A(54)] remove { } + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "event").WithArguments("event", "method, param, return").WithLocation(12, 64), + // (12,79): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, param, return'. All attributes in this block will be ignored. + // [A(4)] [method: A(14)] [param: A(24)] [return: A(34)] [event: A(44)] [field: A(54)] remove { } + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "method, param, return").WithLocation(12, 79), + // (15,29): warning CS0657: 'param' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, event'. All attributes in this block will be ignored. + // [A(1)] [method: A(11)] [param: A(21)] [return: A(31)] [event: A(41)] [field: A(51)] public partial event Action F; + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "param").WithArguments("param", "method, event").WithLocation(15, 29), + // (15,44): warning CS0657: 'return' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, event'. All attributes in this block will be ignored. + // [A(1)] [method: A(11)] [param: A(21)] [return: A(31)] [event: A(41)] [field: A(51)] public partial event Action F; + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "return").WithArguments("return", "method, event").WithLocation(15, 44), + // (15,75): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, event'. All attributes in this block will be ignored. + // [A(1)] [method: A(11)] [param: A(21)] [return: A(31)] [event: A(41)] [field: A(51)] public partial event Action F; + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "method, event").WithLocation(15, 75), + // (16,29): warning CS0657: 'param' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, event'. All attributes in this block will be ignored. + // [A(2)] [method: A(12)] [param: A(22)] [return: A(32)] [event: A(42)] [field: A(52)] public extern partial event Action F; + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "param").WithArguments("param", "method, event").WithLocation(16, 29), + // (16,44): warning CS0657: 'return' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, event'. All attributes in this block will be ignored. + // [A(2)] [method: A(12)] [param: A(22)] [return: A(32)] [event: A(42)] [field: A(52)] public extern partial event Action F; + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "return").WithArguments("return", "method, event").WithLocation(16, 44), + // (16,75): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, event'. All attributes in this block will be ignored. + // [A(2)] [method: A(12)] [param: A(22)] [return: A(32)] [event: A(42)] [field: A(52)] public extern partial event Action F; + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "method, event").WithLocation(16, 75)); + + static void validate(ModuleSymbol module) + { + var isSource = module is SourceModuleSymbol; + ReadOnlySpan compiledGeneratedAttr = isSource ? [] : ["System.Runtime.CompilerServices.CompilerGeneratedAttribute"]; + + var e = module.GlobalNamespace.GetMember("C.E"); + AssertEx.Equal(["A(1)", "A(41)", "A(2)", "A(42)"], e.GetAttributes().ToStrings()); + AssertEx.Equal(["A(3)", "A(13)"], e.AddMethod!.GetAttributes().ToStrings()); + AssertEx.Equal(["A(23)"], e.AddMethod.Parameters.Single().GetAttributes().ToStrings()); + AssertEx.Equal(["A(33)"], e.AddMethod.GetReturnTypeAttributes().ToStrings()); + AssertEx.Equal(["A(4)", "A(14)"], e.RemoveMethod!.GetAttributes().ToStrings()); + AssertEx.Equal(["A(24)"], e.RemoveMethod.Parameters.Single().GetAttributes().ToStrings()); + AssertEx.Equal(["A(34)"], e.RemoveMethod.GetReturnTypeAttributes().ToStrings()); + + if (isSource) + { + var eImpl = ((SourceEventSymbol)e).PartialImplementationPart!; + AssertEx.Equal(["A(1)", "A(41)", "A(2)", "A(42)"], eImpl.GetAttributes().ToStrings()); + AssertEx.Equal(["A(3)", "A(13)"], eImpl.AddMethod!.GetAttributes().ToStrings()); + AssertEx.Equal(["A(23)"], eImpl.AddMethod.Parameters.Single().GetAttributes().ToStrings()); + AssertEx.Equal(["A(33)"], eImpl.AddMethod.GetReturnTypeAttributes().ToStrings()); + AssertEx.Equal(["A(4)", "A(14)"], eImpl.RemoveMethod!.GetAttributes().ToStrings()); + AssertEx.Equal(["A(24)"], eImpl.RemoveMethod.Parameters.Single().GetAttributes().ToStrings()); + AssertEx.Equal(["A(34)"], eImpl.RemoveMethod.GetReturnTypeAttributes().ToStrings()); + } + + var f = module.GlobalNamespace.GetMember("C.F"); + AssertEx.Equal(["A(1)", "A(41)", "A(2)", "A(42)"], f.GetAttributes().ToStrings()); + AssertEx.Equal([.. compiledGeneratedAttr, "A(11)", "A(12)"], f.AddMethod!.GetAttributes().ToStrings()); + AssertEx.Equal(["A(22)", "A(21)"], f.AddMethod.Parameters.Single().GetAttributes().ToStrings()); + AssertEx.Equal([], f.AddMethod.GetReturnTypeAttributes().ToStrings()); + AssertEx.Equal([.. compiledGeneratedAttr, "A(11)", "A(12)"], f.RemoveMethod!.GetAttributes().ToStrings()); + AssertEx.Equal(["A(22)", "A(21)"], f.RemoveMethod.Parameters.Single().GetAttributes().ToStrings()); + AssertEx.Equal([], f.RemoveMethod.GetReturnTypeAttributes().ToStrings()); + + if (isSource) + { + var fImpl = ((SourceEventSymbol)f).PartialImplementationPart!; + AssertEx.Equal(["A(1)", "A(41)", "A(2)", "A(42)"], fImpl.GetAttributes().ToStrings()); + AssertEx.Equal([.. compiledGeneratedAttr, "A(11)", "A(12)"], fImpl.AddMethod!.GetAttributes().ToStrings()); + AssertEx.Equal(["A(22)", "A(21)"], fImpl.AddMethod.Parameters.Single().GetAttributes().ToStrings()); + AssertEx.Equal([], fImpl.AddMethod.GetReturnTypeAttributes().ToStrings()); + AssertEx.Equal([.. compiledGeneratedAttr, "A(11)", "A(12)"], fImpl.RemoveMethod!.GetAttributes().ToStrings()); + AssertEx.Equal(["A(22)", "A(21)"], fImpl.RemoveMethod.Parameters.Single().GetAttributes().ToStrings()); + AssertEx.Equal([], fImpl.RemoveMethod.GetReturnTypeAttributes().ToStrings()); + } + } + } + + [Fact] + public void Attributes_Duplicates() + { + var source = """ + using System; + + class A1 : Attribute; + class A2 : Attribute; + class A3 : Attribute; + + partial class C + { + [A1] [method: A2] partial C( // def + [A1] [param: A2] int x); + [A1] [method: A2] partial C( // impl + [A1] [param: A2] int x) { } + + [A1] [method: A2] partial event Action E; + [A1] [method: A2] partial event Action E + { + [A1] [method: A1] [param: A2] add { } + [A1] [method: A1] [param: A2] remove { } + } + + [A1] [method: A2] [param: A3] partial event Action F; + [A1] [method: A2] [param: A3] extern partial event Action F; + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (10,10): error CS0579: Duplicate 'A1' attribute + // [A1] [param: A2] int x); + Diagnostic(ErrorCode.ERR_DuplicateAttribute, "A1").WithArguments("A1").WithLocation(10, 10), + // (10,22): error CS0579: Duplicate 'A2' attribute + // [A1] [param: A2] int x); + Diagnostic(ErrorCode.ERR_DuplicateAttribute, "A2").WithArguments("A2").WithLocation(10, 22), + // (11,6): error CS0579: Duplicate 'A1' attribute + // [A1] [method: A2] partial C( // impl + Diagnostic(ErrorCode.ERR_DuplicateAttribute, "A1").WithArguments("A1").WithLocation(11, 6), + // (11,19): error CS0579: Duplicate 'A2' attribute + // [A1] [method: A2] partial C( // impl + Diagnostic(ErrorCode.ERR_DuplicateAttribute, "A2").WithArguments("A2").WithLocation(11, 19), + // (14,11): warning CS0657: 'method' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'event'. All attributes in this block will be ignored. + // [A1] [method: A2] partial event Action E; + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "method").WithArguments("method", "event").WithLocation(14, 11), + // (15,6): error CS0579: Duplicate 'A1' attribute + // [A1] [method: A2] partial event Action E + Diagnostic(ErrorCode.ERR_DuplicateAttribute, "A1").WithArguments("A1").WithLocation(15, 6), + // (15,11): warning CS0657: 'method' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'event'. All attributes in this block will be ignored. + // [A1] [method: A2] partial event Action E + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "method").WithArguments("method", "event").WithLocation(15, 11), + // (17,23): error CS0579: Duplicate 'A1' attribute + // [A1] [method: A1] [param: A2] add { } + Diagnostic(ErrorCode.ERR_DuplicateAttribute, "A1").WithArguments("A1").WithLocation(17, 23), + // (18,23): error CS0579: Duplicate 'A1' attribute + // [A1] [method: A1] [param: A2] remove { } + Diagnostic(ErrorCode.ERR_DuplicateAttribute, "A1").WithArguments("A1").WithLocation(18, 23), + // (21,24): warning CS0657: 'param' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, event'. All attributes in this block will be ignored. + // [A1] [method: A2] [param: A3] partial event Action F; + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "param").WithArguments("param", "method, event").WithLocation(21, 24), + // (21,31): error CS0579: Duplicate 'A3' attribute + // [A1] [method: A2] [param: A3] partial event Action F; + Diagnostic(ErrorCode.ERR_DuplicateAttribute, "A3").WithArguments("A3").WithLocation(21, 31), + // (21,31): error CS0579: Duplicate 'A3' attribute + // [A1] [method: A2] [param: A3] partial event Action F; + Diagnostic(ErrorCode.ERR_DuplicateAttribute, "A3").WithArguments("A3").WithLocation(21, 31), + // (22,6): error CS0579: Duplicate 'A1' attribute + // [A1] [method: A2] [param: A3] extern partial event Action F; + Diagnostic(ErrorCode.ERR_DuplicateAttribute, "A1").WithArguments("A1").WithLocation(22, 6), + // (22,19): error CS0579: Duplicate 'A2' attribute + // [A1] [method: A2] [param: A3] extern partial event Action F; + Diagnostic(ErrorCode.ERR_DuplicateAttribute, "A2").WithArguments("A2").WithLocation(22, 19), + // (22,24): warning CS0657: 'param' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, event'. All attributes in this block will be ignored. + // [A1] [method: A2] [param: A3] extern partial event Action F; + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "param").WithArguments("param", "method, event").WithLocation(22, 24)); + } + + [Fact] + public void Attributes_CallerInfo() + { + var source1 = """ + using System; + using System.Runtime.CompilerServices; + + public partial class C + { + public partial C(int x, + [CallerLineNumber] int a = -1, + [CallerFilePath] string b = "f", + [CallerMemberName] string c = "m", + [CallerArgumentExpression(nameof(x))] string d = "e"); + public partial C(int x, int a, string b, string c, string d) + { + Console.WriteLine($"x='{x}' a='{a}' b='{b}' c='{c}' d='{d}'"); + } + + public partial C(string x, + int a = -1, + string b = "f", + string c = "m", + string d = "e"); + public partial C(string x, + [CallerLineNumber] int a, + [CallerFilePath] string b, + [CallerMemberName] string c, + [CallerArgumentExpression(nameof(x))] string d) + { + Console.WriteLine($"x='{x}' a='{a}' b='{b}' c='{c}' d='{d}'"); + } + } + """; + + var source2 = (""" + var c1 = new C(40 + 2); + var c2 = new C("s"); + """, "file.cs"); + + var expectedDiagnostics = new[] + { + // (22,10): warning CS4024: The CallerLineNumberAttribute applied to parameter 'a' will have no effect because it applies to a member that is used in contexts that do not allow optional arguments + // [CallerLineNumber] int a, + Diagnostic(ErrorCode.WRN_CallerLineNumberParamForUnconsumedLocation, "CallerLineNumber").WithArguments("a").WithLocation(22, 10), + // (23,10): warning CS4025: The CallerFilePathAttribute applied to parameter 'b' will have no effect because it applies to a member that is used in contexts that do not allow optional arguments + // [CallerFilePath] string b, + Diagnostic(ErrorCode.WRN_CallerFilePathParamForUnconsumedLocation, "CallerFilePath").WithArguments("b").WithLocation(23, 10), + // (24,10): warning CS4026: The CallerMemberNameAttribute applied to parameter 'c' will have no effect because it applies to a member that is used in contexts that do not allow optional arguments + // [CallerMemberName] string c, + Diagnostic(ErrorCode.WRN_CallerMemberNameParamForUnconsumedLocation, "CallerMemberName").WithArguments("c").WithLocation(24, 10), + // (25,10): warning CS8966: The CallerArgumentExpressionAttribute applied to parameter 'd' will have no effect because it applies to a member that is used in contexts that do not allow optional arguments + // [CallerArgumentExpression(nameof(x))] string d) + Diagnostic(ErrorCode.WRN_CallerArgumentExpressionParamForUnconsumedLocation, "CallerArgumentExpression").WithArguments("d").WithLocation(25, 10) + }; + + CompileAndVerify([source1, source2, CallerArgumentExpressionAttributeDefinition], + expectedOutput: """ + x='42' a='1' b='file.cs' c='
$' d='40 + 2' + x='s' a='-1' b='f' c='m' d='e' + """) + .VerifyDiagnostics(expectedDiagnostics); + + // Although caller info attributes on the implementation part have no effect in source, + // they are written to metadata as is demonstrated below. + // See https://github.com/dotnet/roslyn/issues/73482. + + var lib = CreateCompilation([source1, CallerArgumentExpressionAttributeDefinition]) + .VerifyDiagnostics(expectedDiagnostics) + .EmitToPortableExecutableReference(); + + CompileAndVerify(CreateCompilation(source2, references: [lib]), + expectedOutput: """ + x='42' a='1' b='file.cs' c='
$' d='40 + 2' + x='s' a='2' b='file.cs' c='
$' d='"s"' + """) + .VerifyDiagnostics(); + } + + [Fact] + public void Attributes_Nullable() + { + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + new C(default(I1)!, null); + new C(default(I2)!, null); + new C(default(I3)!, null); + new C(default(I4)!, null); + new C(default(I5)!, null); + new C(default(I6)!, null); + new C(default(I7)!, null); + new C(default(I8)!, null); + + interface I1; + interface I2; + interface I3; + interface I4; + interface I5; + interface I6; + interface I7; + interface I8; + + partial class C + { + public partial C(I1 i, [AllowNull] object x); + public partial C(I1 i, object x) { x.ToString(); } + + public partial C(I2 i, object x); + public partial C(I2 i, [AllowNull] object x) { x.ToString(); } + + public partial C(I3 i, [AllowNull] object x); + public partial C(I3 i, object? x) { x.ToString(); } + + public partial C(I4 i, object? x); + public partial C(I4 i, [AllowNull] object x) { x.ToString(); } + + public partial C(I5 i, [DisallowNull] object? x); + public partial C(I5 i, object? x) { x.ToString(); } + + public partial C(I6 i, object? x); + public partial C(I6 i, [DisallowNull] object? x) { x.ToString(); } + + public partial C(I7 i, [DisallowNull] object? x); + public partial C(I7 i, object x) { x.ToString(); } + + public partial C(I8 i, object x); + public partial C(I8 i, [DisallowNull] object? x) { x.ToString(); } + } + """; + CreateCompilation([source, AllowNullAttributeDefinition, DisallowNullAttributeDefinition]).VerifyDiagnostics( + // (8,21): warning CS8625: Cannot convert null literal to non-nullable reference type. + // new C(default(I5)!, null); + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(8, 21), + // (9,21): warning CS8625: Cannot convert null literal to non-nullable reference type. + // new C(default(I6)!, null); + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(9, 21), + // (10,21): warning CS8625: Cannot convert null literal to non-nullable reference type. + // new C(default(I7)!, null); + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(10, 21), + // (11,21): warning CS8625: Cannot convert null literal to non-nullable reference type. + // new C(default(I8)!, null); + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(11, 21), + // (25,40): warning CS8602: Dereference of a possibly null reference. + // public partial C(I1 i, object x) { x.ToString(); } + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(25, 40), + // (28,52): warning CS8602: Dereference of a possibly null reference. + // public partial C(I2 i, [AllowNull] object x) { x.ToString(); } + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(28, 52), + // (31,20): warning CS9256: Partial member declarations 'C.C(I3 i, object x)' and 'C.C(I3 i, object? x)' have signature differences. + // public partial C(I3 i, object? x) { x.ToString(); } + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "C").WithArguments("C.C(I3 i, object x)", "C.C(I3 i, object? x)").WithLocation(31, 20), + // (31,41): warning CS8602: Dereference of a possibly null reference. + // public partial C(I3 i, object? x) { x.ToString(); } + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(31, 41), + // (34,20): warning CS9256: Partial member declarations 'C.C(I4 i, object? x)' and 'C.C(I4 i, object x)' have signature differences. + // public partial C(I4 i, [AllowNull] object x) { x.ToString(); } + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "C").WithArguments("C.C(I4 i, object? x)", "C.C(I4 i, object x)").WithLocation(34, 20), + // (34,52): warning CS8602: Dereference of a possibly null reference. + // public partial C(I4 i, [AllowNull] object x) { x.ToString(); } + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(34, 52), + // (43,20): warning CS9256: Partial member declarations 'C.C(I7 i, object? x)' and 'C.C(I7 i, object x)' have signature differences. + // public partial C(I7 i, object x) { x.ToString(); } + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "C").WithArguments("C.C(I7 i, object? x)", "C.C(I7 i, object x)").WithLocation(43, 20), + // (46,20): warning CS9256: Partial member declarations 'C.C(I8 i, object x)' and 'C.C(I8 i, object? x)' have signature differences. + // public partial C(I8 i, [DisallowNull] object? x) { x.ToString(); } + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "C").WithArguments("C.C(I8 i, object x)", "C.C(I8 i, object? x)").WithLocation(46, 20)); + } + + [Fact] + public void Attributes_Obsolete() + { + var source = """ + using System; + + var c = new C(); + c = new C(2); + c.E += null; + c.E -= null; + c.F += null; + c.F -= null; + c.G += null; + c.G -= null; + c.H += null; + c.H -= null; + + partial class C + { + [Obsolete] public partial C(); + public partial C() { M(); } + + public partial C(int x = X); + [Obsolete] public partial C(int x) { M(); } + + [Obsolete] public partial event Action E; + public partial event Action E { add { M(); } remove { M(); } } + + public partial event Action F; + public partial event Action F + { + [Obsolete] add { M(); } + remove { M(); } + } + + [Obsolete] public partial event Action G; + public extern partial event Action G; + + [method: Obsolete] public partial event Action H; + public extern partial event Action H; + + [Obsolete] void M() { } + [Obsolete] const int X = 1; + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (3,9): warning CS0612: 'C.C()' is obsolete + // var c = new C(); + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "new C()").WithArguments("C.C()").WithLocation(3, 9), + // (4,5): warning CS0612: 'C.C(int)' is obsolete + // c = new C(2); + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "new C(2)").WithArguments("C.C(int)").WithLocation(4, 5), + // (5,1): warning CS0612: 'C.E' is obsolete + // c.E += null; + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "c.E").WithArguments("C.E").WithLocation(5, 1), + // (6,1): warning CS0612: 'C.E' is obsolete + // c.E -= null; + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "c.E").WithArguments("C.E").WithLocation(6, 1), + // (9,1): warning CS0612: 'C.G' is obsolete + // c.G += null; + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "c.G").WithArguments("C.G").WithLocation(9, 1), + // (10,1): warning CS0612: 'C.G' is obsolete + // c.G -= null; + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "c.G").WithArguments("C.G").WithLocation(10, 1), + // (28,10): error CS8423: Attribute 'System.ObsoleteAttribute' is not valid on event accessors. It is only valid on 'class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate' declarations. + // [Obsolete] add { M(); } + Diagnostic(ErrorCode.ERR_AttributeNotOnEventAccessor, "Obsolete").WithArguments("System.ObsoleteAttribute", "class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate").WithLocation(28, 10), + // (29,18): warning CS0612: 'C.M()' is obsolete + // remove { M(); } + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "M()").WithArguments("C.M()").WithLocation(29, 18), + // (35,14): error CS8423: Attribute 'System.ObsoleteAttribute' is not valid on event accessors. It is only valid on 'class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate' declarations. + // [method: Obsolete] public partial event Action H; + Diagnostic(ErrorCode.ERR_AttributeNotOnEventAccessor, "Obsolete").WithArguments("System.ObsoleteAttribute", "class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate").WithLocation(35, 14)); + } +} diff --git a/src/Compilers/CSharp/Test/Emit3/RefReadonlyParameterTests.cs b/src/Compilers/CSharp/Test/Emit3/RefReadonlyParameterTests.cs index 55808b02151ef..12482bd5997b1 100644 --- a/src/Compilers/CSharp/Test/Emit3/RefReadonlyParameterTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/RefReadonlyParameterTests.cs @@ -8664,4 +8664,51 @@ static void Main() // d = (ref int x) => { x = 42; }; // should be an error Diagnostic(ErrorCode.ERR_BadParamRef, "x").WithArguments("1", "in").WithLocation(7, 22)); } + + [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/77528")] + public void UnassignedField( + [CombinatorialValues("in", "ref")] string arg, + [CombinatorialValues("ref readonly", "in")] string param) + { + var source = $$""" + #pragma warning disable CS9191 // The 'ref' modifier for argument corresponding to 'in' parameter is equivalent to 'in'. Consider using 'in' instead. + + M({{arg}} C.F); + + static void M({{param}} int i) { } + + static class C + { + public static int F; + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (9,23): warning CS0649: Field 'C.F' is never assigned to, and will always have its default value 0 + // public static int F; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F").WithArguments("C.F", "0").WithLocation(9, 23)); + } + + [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/77528")] + public void UnassignedField_NamedArguments( + [CombinatorialValues("in", "ref")] string arg, + [CombinatorialValues("ref readonly", "in")] string param) + { + var source = $$""" + #pragma warning disable CS9191 // The 'ref' modifier for argument corresponding to 'in' parameter is equivalent to 'in'. Consider using 'in' instead. + + M(j: ref C.F1, i: {{arg}} C.F2); + + static void M({{param}} int i, ref int j) { } + + static class C + { + public static int F1; + public static int F2; + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (10,23): warning CS0649: Field 'C.F2' is never assigned to, and will always have its default value 0 + // public static int F2; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F2").WithArguments("C.F2", "0").WithLocation(10, 23)); + } } diff --git a/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs new file mode 100644 index 0000000000000..49b55402cfecc --- /dev/null +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs @@ -0,0 +1,31213 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +#nullable disable + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.VisualBasic; +using Roslyn.Test.Utilities; +using Xunit; +using Xunit.Sdk; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics; + +[CompilerTrait(CompilerFeature.Extensions)] +public class ExtensionTests : CompilingTestBase +{ + private static string ExpectedOutput(string output) + { + return ExecutionConditionUtil.IsMonoOrCoreClr ? output : null; + } + + private static void VerifyTypeIL(CompilationVerifier compilation, string typeName, string expected) + { + // .Net Core has different assemblies for the same standard library types as .Net Framework, meaning that that the emitted output will be different to the expected if we run them .Net Core + // Since we do not expect there to be any meaningful differences between output for .Net Core and .Net Framework, we will skip these tests on .Net Framework + if (ExecutionConditionUtil.IsCoreClr) + { + compilation.VerifyTypeIL(typeName, expected); + } + } + + private static void AssertEqualAndNoDuplicates(string[] expected, string[] actual) + { + Assert.True(expected.All(new HashSet().Add), $"Duplicates were found in '{nameof(expected)}'"); + Assert.True(actual.All(new HashSet().Add), $"Duplicates were found in '{nameof(actual)}'"); + AssertEx.SetEqual(expected, actual); + } + + private static void AssertExtensionDeclaration(INamedTypeSymbol symbol) + { + // Verify things that are common for all extension types + Assert.Equal(TypeKind.Extension, symbol.TypeKind); + Assert.True(symbol.IsExtension); + Assert.Null(symbol.BaseType); + Assert.Empty(symbol.Interfaces); + Assert.Empty(symbol.AllInterfaces); + Assert.True(symbol.IsReferenceType); + Assert.False(symbol.IsValueType); + Assert.False(symbol.IsAnonymousType); + Assert.False(symbol.IsTupleType); + Assert.False(symbol.IsNativeIntegerType); + Assert.Equal(SpecialType.None, symbol.SpecialType); + Assert.False(symbol.IsRefLikeType); + Assert.False(symbol.IsUnmanagedType); + Assert.False(symbol.IsReadOnly); + Assert.False(symbol.IsRecord); + Assert.Equal(CodeAnalysis.NullableAnnotation.None, symbol.NullableAnnotation); + Assert.Throws(() => { symbol.WithNullableAnnotation(CodeAnalysis.NullableAnnotation.Annotated); }); + + Assert.False(symbol.IsScriptClass); + Assert.False(symbol.IsImplicitClass); + Assert.False(symbol.IsComImport); + Assert.False(symbol.IsFileLocal); + Assert.Null(symbol.DelegateInvokeMethod); + Assert.Null(symbol.EnumUnderlyingType); + Assert.Null(symbol.AssociatedSymbol); + Assert.False(symbol.MightContainExtensionMethods); + Assert.Null(symbol.TupleUnderlyingType); + Assert.True(symbol.TupleElements.IsDefault); + Assert.False(symbol.IsSerializable); + Assert.Null(symbol.NativeIntegerUnderlyingType); + + Assert.Equal(SymbolKind.NamedType, symbol.Kind); + Assert.Equal("", symbol.Name); + Assert.Equal(SpecialType.None, symbol.SpecialType); + Assert.True(symbol.IsDefinition); + Assert.False(symbol.IsStatic); + Assert.False(symbol.IsVirtual); + Assert.False(symbol.IsOverride); + Assert.False(symbol.IsAbstract); + Assert.True(symbol.IsSealed); + Assert.False(symbol.IsExtern); + Assert.False(symbol.IsImplicitlyDeclared); + Assert.False(symbol.CanBeReferencedByName); + Assert.Equal(Accessibility.Public, symbol.DeclaredAccessibility); + + var namedTypeSymbol = symbol.GetSymbol(); + Assert.False(namedTypeSymbol.HasSpecialName); + Assert.False(namedTypeSymbol.IsImplicitlyDeclared); + } + + [Fact] + public void EmptyExtension() + { + var src = """ +public static class Extensions +{ + extension(object) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var verifier = CompileAndVerify(comp); + VerifyTypeIL(verifier, "Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [netstandard]System.Object +{ + .custom instance void [netstandard]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0' + extends [netstandard]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + object '' + ) cil managed + { + .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0'::'$' + } // end of class <>E__0 +} // end of class Extensions +"""); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(extension); + AssertExtensionDeclaration(symbol); + + Assert.Empty(symbol.MemberNames); + Assert.Empty(symbol.InstanceConstructors); + Assert.Empty(symbol.StaticConstructors); + Assert.Empty(symbol.Constructors); + + Assert.Equal(0, symbol.Arity); + Assert.False(symbol.IsGenericType); + Assert.False(symbol.IsUnboundGenericType); + Assert.Empty(symbol.TypeParameters); + Assert.Empty(symbol.TypeArguments); + Assert.Same(symbol, symbol.OriginalDefinition); + Assert.Same(symbol, symbol.ConstructedFrom); + Assert.Equal("Extensions", symbol.ContainingSymbol.Name); + Assert.Equal("Extensions", symbol.ContainingType.Name); + Assert.Equal("<>E__0", symbol.MetadataName); + + var member = symbol.ContainingType.GetMembers().Single(); + Assert.Equal("Extensions.<>E__0", member.ToTestDisplayString()); + + var format = new SymbolDisplayFormat(typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces); + Assert.Equal("Extensions.extension(System.Object)", symbol.ToDisplayString(format)); + + format = new SymbolDisplayFormat(kindOptions: SymbolDisplayKindOptions.IncludeTypeKeyword); + Assert.Equal("extension(Object)", symbol.ToDisplayString(format)); + + format = new SymbolDisplayFormat(); + Assert.Equal("extension(Object)", symbol.ToDisplayString(format)); + + format = new SymbolDisplayFormat(compilerInternalOptions: SymbolDisplayCompilerInternalOptions.UseMetadataMemberNames); + Assert.Equal("<>E__0", symbol.ToDisplayString(format)); + + var comp5 = CreateCompilation(src); + comp5.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_ExtensionAttribute__ctor); + comp5.VerifyEmitDiagnostics( + // (3,5): error CS1110: Cannot define a new extension because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? + // extension(object) { } + Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "extension").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(3, 5) + ); + } + + [Fact] + public void TypeParameters_01() + { + // Unconstrained type parameter + var src = """ +public static class Extensions +{ + extension(T) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var verifier = CompileAndVerify(comp); + VerifyTypeIL(verifier, "Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [netstandard]System.Object +{ + .custom instance void [netstandard]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0`1' + extends [netstandard]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + !T '' + ) cil managed + { + .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0`1'::'$' + } // end of class <>E__0`1 +} // end of class Extensions +"""); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(extension); + AssertExtensionDeclaration(symbol); + + Assert.Equal(1, symbol.Arity); + Assert.True(symbol.IsGenericType); + Assert.False(symbol.IsUnboundGenericType); + Assert.Equal(["T"], symbol.TypeParameters.ToTestDisplayStrings()); + Assert.Equal(["T"], symbol.TypeArguments.ToTestDisplayStrings()); + Assert.Same(symbol, symbol.OriginalDefinition); + Assert.Same(symbol, symbol.ConstructedFrom); + Assert.Equal("Extensions", symbol.ContainingSymbol.Name); + Assert.Equal("Extensions", symbol.ContainingType.Name); + Assert.Equal("<>E__0`1", symbol.MetadataName); + + var member = symbol.ContainingType.GetMembers().Single(); + Assert.Equal("Extensions.<>E__0", member.ToTestDisplayString()); + + var constructed = symbol.Construct(comp.GetSpecialType(SpecialType.System_Int32)); + Assert.True(constructed.IsExtension); + Assert.Equal("Extensions.<>E__0", constructed.ToTestDisplayString()); + Assert.Equal("<>E__0`1", constructed.MetadataName); + Assert.NotSame(symbol, constructed); + Assert.Same(symbol, constructed.OriginalDefinition); + Assert.Same(symbol, constructed.ConstructedFrom); + + var unbound = symbol.ConstructUnboundGenericType(); + Assert.Equal("Extensions.<>E__0<>", unbound.ToTestDisplayString()); + Assert.True(unbound.IsUnboundGenericType); + Assert.NotSame(symbol, unbound); + Assert.Same(symbol, unbound.OriginalDefinition); + Assert.Same(symbol, unbound.ConstructedFrom); + } + + [Fact] + public void TypeParameters_02() + { + // Constrained type parameter + var src = """ +public static class Extensions +{ + extension(T) where T : struct { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var verifier = CompileAndVerify(comp); + VerifyTypeIL(verifier, "Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [netstandard]System.Object +{ + .custom instance void [netstandard]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0`1' + extends [netstandard]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + !T '' + ) cil managed + { + .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0`1'::'$' + } // end of class <>E__0`1 +} // end of class Extensions +"""); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(extension); + + Assert.Equal(1, symbol.Arity); + Assert.True(symbol.IsGenericType); + Assert.Equal(["T"], symbol.TypeParameters.ToTestDisplayStrings()); + Assert.Equal(["T"], symbol.TypeArguments.ToTestDisplayStrings()); + Assert.True(symbol.TypeParameters.Single().IsValueType); + Assert.False(symbol.TypeParameters.Single().IsReferenceType); + Assert.Empty(symbol.TypeParameters.Single().ConstraintTypes); + + var format = new SymbolDisplayFormat(genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeTypeConstraints); + Assert.Equal("extension(T) where T : struct", symbol.ToDisplayString(format)); + } + + [Fact] + public void TypeParameters_03() + { + // Constraint on undefined type parameter + var src = """ +public static class Extensions +{ + extension(object) where T : struct { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,23): error CS0080: Constraints are not allowed on non-generic declarations + // extension(object) where T : struct { } + Diagnostic(ErrorCode.ERR_ConstraintOnlyAllowedOnGenericDecl, "where").WithLocation(3, 23)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(extension); + Assert.Equal(0, symbol.Arity); + Assert.False(symbol.IsGenericType); + Assert.Empty(symbol.TypeParameters.ToTestDisplayStrings()); + Assert.Empty(symbol.TypeArguments.ToTestDisplayStrings()); + } + + [Fact] + public void TypeParameters_04() + { + // Type parameter variance + var src = """ +public static class Extensions +{ + extension(T) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,15): error CS1960: Invalid variance modifier. Only interface and delegate type parameters can be specified as variant. + // extension(object) { } + Diagnostic(ErrorCode.ERR_IllegalVarianceSyntax, "out").WithLocation(3, 15)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(extension); + Assert.Equal(1, symbol.Arity); + Assert.True(symbol.IsGenericType); + Assert.Equal(["out T"], symbol.TypeParameters.ToTestDisplayStrings()); + Assert.Equal(["out T"], symbol.TypeArguments.ToTestDisplayStrings()); + } + + [Fact] + public void TypeParameters_05() + { + // Duplicate type parameter + var src = """ +public static class Extensions +{ + extension(T) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,18): error CS0692: Duplicate type parameter 'T' + // extension(T) { } + Diagnostic(ErrorCode.ERR_DuplicateTypeParameter, "T").WithArguments("T").WithLocation(3, 18), + // (3,21): error CS0229: Ambiguity between 'T' and 'T' + // extension(T) { } + Diagnostic(ErrorCode.ERR_AmbigMember, "T").WithArguments("T", "T").WithLocation(3, 21), + // (3,21): error CS9295: The extended type 'T' must reference all the type parameters declared by the extension, but type parameter 'T' is not referenced. + // extension(T) { } + Diagnostic(ErrorCode.ERR_UnderspecifiedExtension, "T").WithArguments("T", "T").WithLocation(3, 21), + // (3,21): error CS9295: The extended type 'T' must reference all the type parameters declared by the extension, but type parameter 'T' is not referenced. + // extension(T) { } + Diagnostic(ErrorCode.ERR_UnderspecifiedExtension, "T").WithArguments("T", "T").WithLocation(3, 21)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(extension); + Assert.Equal(2, symbol.Arity); + Assert.Equal(["T", "T"], symbol.TypeParameters.ToTestDisplayStrings()); + Assert.Equal(["T", "T"], symbol.TypeArguments.ToTestDisplayStrings()); + } + + [Fact] + public void TypeParameters_05_Nested() + { + // Duplicate type parameter + var src = """ +public static class Extensions +{ + extension(C) { } +} +class C { } +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,18): error CS0692: Duplicate type parameter 'T' + // extension(C) { } + Diagnostic(ErrorCode.ERR_DuplicateTypeParameter, "T").WithArguments("T").WithLocation(3, 18), + // (3,21): error CS9295: The extended type 'C' must reference all the type parameters declared by the extension, but type parameter 'T' is not referenced. + // extension(C) { } + Diagnostic(ErrorCode.ERR_UnderspecifiedExtension, "C").WithArguments("C", "T").WithLocation(3, 21), + // (3,21): error CS9295: The extended type 'C' must reference all the type parameters declared by the extension, but type parameter 'T' is not referenced. + // extension(C) { } + Diagnostic(ErrorCode.ERR_UnderspecifiedExtension, "C").WithArguments("C", "T").WithLocation(3, 21), + // (3,23): error CS0229: Ambiguity between 'T' and 'T' + // extension(C) { } + Diagnostic(ErrorCode.ERR_AmbigMember, "T").WithArguments("T", "T").WithLocation(3, 23)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(extension); + Assert.Equal(2, symbol.Arity); + Assert.Equal(["T", "T"], symbol.TypeParameters.ToTestDisplayStrings()); + Assert.Equal(["T", "T"], symbol.TypeArguments.ToTestDisplayStrings()); + } + + [Fact] + public void TypeParameters_06() + { + // Type parameter same as outer type parameter + var src = """ +public static class Extensions +{ + extension(T) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,5): error CS9283: Extensions must be declared in a top-level, non-generic, static class + // extension(object) { } + Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(3, 5), + // (3,15): warning CS0693: Type parameter 'T' has the same name as the type parameter from outer type 'Extensions' + // extension(object) { } + Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, "T").WithArguments("T", "Extensions").WithLocation(3, 15)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(extension); + Assert.Equal(1, symbol.Arity); + Assert.Equal(["T"], symbol.TypeParameters.ToTestDisplayStrings()); + Assert.Equal(["T"], symbol.TypeArguments.ToTestDisplayStrings()); + + var container = symbol.ContainingType; + var substitutedExtension = (INamedTypeSymbol)container.Construct(comp.GetSpecialType(SpecialType.System_Int32)).GetMembers().Single(); + Assert.Equal("Extensions.<>E__0", substitutedExtension.ToTestDisplayString()); + Assert.True(substitutedExtension.IsExtension); + } + + [Fact] + public void TypeParameters_07() + { + // Reserved type name for type parameter + var src = $$""" +public static class Extensions +{ + extension(record) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,15): warning CS8860: Types and aliases should not be named 'record'. + // extension(object) { } + Diagnostic(ErrorCode.WRN_RecordNamedDisallowed, "record").WithLocation(3, 15)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(extension); + Assert.Equal(["record"], symbol.TypeParameters.ToTestDisplayStrings()); + } + + [Fact] + public void TypeParameters_08() + { + // Reserved type name for type parameter + var src = $$""" +public static class Extensions +{ + extension(file) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,15): error CS9056: Types and aliases cannot be named 'file'. + // extension(object) { } + Diagnostic(ErrorCode.ERR_FileTypeNameDisallowed, "file").WithLocation(3, 15)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(extension); + Assert.Equal(["file"], symbol.TypeParameters.ToTestDisplayStrings()); + } + + [Fact] + public void TypeParameters_09() + { + // Member name same as type parameter + var src = $$""" +public static class Extensions +{ + extension(T) + { + void T() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void TypeParameters_10() + { + var src = $$""" +#nullable enable +public static class Extensions +{ + extension(T) where T : notnull + { + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + var verifier = CompileAndVerify(comp); + VerifyTypeIL(verifier, "Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [netstandard]System.Object +{ + .custom instance void [netstandard]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0`1' + extends [netstandard]System.Object + { + .custom instance void System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = ( + 01 00 01 00 00 + ) + // Methods + .method private hidebysig specialname static + void '$' ( + !T '' + ) cil managed + { + .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x209d + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0`1'::'$' + } // end of class <>E__0`1 +} // end of class Extensions +"""); + } + + [Fact] + public void BadContainer_Generic() + { + var src = """ +object.M(); + +public static class Extensions +{ + extension(object) { public static void M() { } } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,8): error CS0117: 'object' does not contain a definition for 'M' + // object.M(); + Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("object", "M").WithLocation(1, 8), + // (5,5): error CS9283: Extensions must be declared in a top-level, non-generic, static class + // extension(object) { public static void M() { } } + Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(5, 5)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(extension); + AssertExtensionDeclaration(symbol); + Assert.True(symbol.IsGenericType); + var members = symbol.ContainingType.GetMembers(); + Assert.Equal(["Extensions.<>E__0", "void Extensions.M()"], members.ToTestDisplayStrings()); + } + + [Fact] + public void BadContainer_TopLevel() + { + var src = """ +object.M(); + +extension(object) { public static void M() { } } +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,8): error CS0117: 'object' does not contain a definition for 'M' + // object.M(); + Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("object", "M").WithLocation(1, 8), + // (3,1): error CS9283: Extensions must be declared in a top-level, non-generic, static class + // extension(object) { public static void M() { } } + Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(3, 1)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(extension); + AssertExtensionDeclaration(symbol); + Assert.Null(symbol.ContainingType); + Assert.Equal("<>E__0", symbol.ToTestDisplayString()); + } + + [Fact] + public void BadContainer_Nested() + { + var src = """ +object.M(); + +public static class Extensions +{ + static void Method() + { + object.M(); + } + + public static class Extensions2 + { + extension(object) { public static void M() { } } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,8): error CS0117: 'object' does not contain a definition for 'M' + // object.M(); + Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("object", "M").WithLocation(1, 8), + // (7,16): error CS0117: 'object' does not contain a definition for 'M' + // object.M(); + Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("object", "M").WithLocation(7, 16), + // (12,9): error CS9283: Extensions must be declared in a top-level, non-generic, static class + // extension(object) { public static void M() { } } + Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(12, 9)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var nestedExtension = tree.GetRoot().DescendantNodes().OfType().Last(); + + var nestedExtensionSymbol = model.GetDeclaredSymbol(nestedExtension); + AssertExtensionDeclaration(nestedExtensionSymbol); + Assert.Equal("Extensions.Extensions2", nestedExtensionSymbol.ContainingType.ToTestDisplayString()); + var members = nestedExtensionSymbol.ContainingType.GetMembers(); + Assert.Equal(["Extensions.Extensions2.<>E__0", "void Extensions.Extensions2.M()"], members.ToTestDisplayStrings()); + } + + [Fact] + public void BadContainer_NestedInExtension() + { + var src = """ +string.M(); + +public static class Extensions +{ + static void Method2() + { + string.M(); + } + + extension(object) + { + static void Method() + { + string.M(); + } + + extension(string) { public static void M() { } } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,8): error CS0117: 'string' does not contain a definition for 'M' + // string.M(); + Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("string", "M").WithLocation(1, 8), + // (7,16): error CS0117: 'string' does not contain a definition for 'M' + // string.M(); + Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("string", "M").WithLocation(7, 16), + // (14,20): error CS0117: 'string' does not contain a definition for 'M' + // string.M(); + Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("string", "M").WithLocation(14, 20), + // (17,9): error CS9282: Extension declarations can include only methods or properties + // extension(string) { public static void M() { } } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "extension").WithLocation(17, 9)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var nestedExtension = tree.GetRoot().DescendantNodes().OfType().Last(); + + var nestedExtensionSymbol = model.GetDeclaredSymbol(nestedExtension); + AssertExtensionDeclaration(nestedExtensionSymbol); + Assert.Equal("Extensions.<>E__0", nestedExtensionSymbol.ContainingType.ToTestDisplayString()); + Assert.Equal(["void Extensions.<>E__0.$(System.Object)", "void Extensions.<>E__0.Method()", "Extensions.<>E__0.<>E__0"], nestedExtensionSymbol.ContainingType.GetMembers().ToTestDisplayStrings()); + } + + [Fact] + public void BadContainer_TypeKind() + { + var src = """ +object.M(); + +public static struct Extensions +{ + extension(object) { public static void M() { } } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,8): error CS0117: 'object' does not contain a definition for 'M' + // object.M(); + Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("object", "M").WithLocation(1, 8), + // (3,22): error CS0106: The modifier 'static' is not valid for this item + // public static struct Extensions + Diagnostic(ErrorCode.ERR_BadMemberFlag, "Extensions").WithArguments("static").WithLocation(3, 22), + // (5,5): error CS9283: Extensions must be declared in a top-level, non-generic, static class + // extension(object) { public static void M() { } } + Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(5, 5)); + } + + [Fact] + public void BadContainer_NotStatic() + { + var src = """ +object.M(); + +public class Extensions +{ + extension(object) { public static void M() { } } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,8): error CS0117: 'object' does not contain a definition for 'M' + // object.M(); + Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("object", "M").WithLocation(1, 8), + // (5,5): error CS9283: Extensions must be declared in a top-level, non-generic, static class + // extension(object) { public static void M() { } } + Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(5, 5)); + } + + [Theory, CombinatorialData] + public void ExtensionIndex_InPartial(bool reverseOrder) + { + var src1 = """ +public static partial class Extensions +{ + extension(object) { } +} +"""; + var src2 = """ +public static partial class Extensions +{ +} +"""; + + var src = reverseOrder ? new[] { src2, src1 } : new[] { src1, src2 }; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var verifier = CompileAndVerify(comp); + VerifyTypeIL(verifier, "Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [netstandard]System.Object +{ + .custom instance void [netstandard]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0' + extends [netstandard]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + object '' + ) cil managed + { + .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0'::'$' + } // end of class <>E__0 +} // end of class Extensions +"""); + + var tree = comp.SyntaxTrees[reverseOrder ? 1 : 0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(extension); + AssertExtensionDeclaration(symbol); + Assert.Equal("<>E__0", symbol.MetadataName); + } + + [Fact] + public void ExtensionIndex_InPartial_TwoExtension() + { + var src1 = """ +public static partial class Extensions +{ + extension(T t) { } +} +"""; + var src2 = """ +public static partial class Extensions +{ + extension((T1, T2) t) { } +} +"""; + + var comp = CreateCompilation([src1, src2]); + comp.VerifyEmitDiagnostics(); + + var tree1 = comp.SyntaxTrees[0]; + var model1 = comp.GetSemanticModel(tree1); + var extension1 = tree1.GetRoot().DescendantNodes().OfType().Single(); + var symbol1 = model1.GetDeclaredSymbol(extension1); + var sourceExtension1 = symbol1.GetSymbol(); + Assert.Equal("<>E__0`1", symbol1.MetadataName); + Assert.Equal("Extensions.<>E__0", sourceExtension1.ToTestDisplayString()); + + var tree2 = comp.SyntaxTrees[1]; + var extension2 = tree2.GetRoot().DescendantNodes().OfType().Single(); + var model2 = comp.GetSemanticModel(tree2); + var symbol2 = model2.GetDeclaredSymbol(extension2); + var sourceExtension2 = symbol2.GetSymbol(); + Assert.Equal("<>E__1`2", symbol2.MetadataName); + Assert.Equal("Extensions.<>E__1", sourceExtension2.ToTestDisplayString()); + } + + [Fact] + public void ExtensionIndex_InPartial_TwoExtensions() + { + var src = """ +public static partial class Extensions +{ + extension(T) { } +} +public static partial class Extensions +{ + extension((T1, T2)) { } +} +"""; + + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension1 = tree.GetRoot().DescendantNodes().OfType().First(); + var symbol1 = model.GetDeclaredSymbol(extension1); + Assert.Equal("<>E__0`1", symbol1.MetadataName); + Assert.Equal("Extensions.<>E__0", symbol1.ToTestDisplayString()); + + var extension2 = tree.GetRoot().DescendantNodes().OfType().Last(); + var symbol2 = model.GetDeclaredSymbol(extension2); + Assert.Equal("<>E__1`2", symbol2.MetadataName); + Assert.Equal("Extensions.<>E__1", symbol2.ToTestDisplayString()); + } + + [Fact] + public void ExtensionIndex_TwoExtensions_SameSignatures_01() + { + var src = """ +public static class Extensions +{ + extension(T) { } + extension(T) { } +} +"""; + + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension1 = tree.GetRoot().DescendantNodes().OfType().First(); + var symbol1 = model.GetDeclaredSymbol(extension1); + var sourceExtension1 = symbol1.GetSymbol(); + Assert.Equal("<>E__0`1", symbol1.MetadataName); + Assert.Equal("Extensions.<>E__0", symbol1.ToTestDisplayString()); + + var extension2 = tree.GetRoot().DescendantNodes().OfType().Last(); + var symbol2 = model.GetDeclaredSymbol(extension2); + var sourceExtension2 = symbol2.GetSymbol(); + Assert.Equal("<>E__1`1", symbol2.MetadataName); + Assert.Equal("Extensions.<>E__1", symbol2.ToTestDisplayString()); + } + + [Fact] + public void ExtensionIndex_TwoExtensions_SameSignatures_02() + { + var src = """ +public static class Extensions +{ + extension(T) { } + class C { } + extension(T) { } +} +"""; + + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension1 = tree.GetRoot().DescendantNodes().OfType().First(); + var symbol1 = model.GetDeclaredSymbol(extension1); + var sourceExtension1 = symbol1.GetSymbol(); + Assert.Equal("<>E__0`1", symbol1.MetadataName); + Assert.Equal("Extensions.<>E__0", symbol1.ToTestDisplayString()); + + var extension2 = tree.GetRoot().DescendantNodes().OfType().Last(); + var symbol2 = model.GetDeclaredSymbol(extension2); + var sourceExtension2 = symbol2.GetSymbol(); + Assert.Equal("<>E__2`1", symbol2.MetadataName); + Assert.Equal("Extensions.<>E__2", symbol2.ToTestDisplayString()); + } + + [Fact] + public void ExtensionIndex_TwoExtensions_SameSignatures_03() + { + var src = """ +extension(T) { } +class C { } +extension(T) { } +"""; + + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,1): error CS9283: Extensions must be declared in a top-level, non-generic, static class + // extension(object) { } + Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(1, 1), + // (3,1): error CS9283: Extensions must be declared in a top-level, non-generic, static class + // extension(object) { } + Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(3, 1)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension1 = tree.GetRoot().DescendantNodes().OfType().First(); + var symbol1 = model.GetDeclaredSymbol(extension1); + var sourceExtension1 = symbol1.GetSymbol(); + Assert.Equal("<>E__0`1", symbol1.MetadataName); + Assert.Equal("<>E__0", symbol1.ToTestDisplayString()); + + var extension2 = tree.GetRoot().DescendantNodes().OfType().Last(); + var symbol2 = model.GetDeclaredSymbol(extension2); + var sourceExtension2 = symbol2.GetSymbol(); + Assert.Equal("<>E__2`1", symbol2.MetadataName); + Assert.Equal("<>E__2", symbol2.ToTestDisplayString()); + } + + [Fact] + public void ExtensionIndex_TwoExtensions_DifferentSignatures_01() + { + var src = """ +public static class Extensions +{ + extension(T) { } + extension((T1, T2) t) { } +} +"""; + + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension1 = tree.GetRoot().DescendantNodes().OfType().First(); + var symbol1 = model.GetDeclaredSymbol(extension1); + var sourceExtension1 = symbol1.GetSymbol(); + Assert.Equal("<>E__0`1", symbol1.MetadataName); + Assert.Equal("Extensions.<>E__0", symbol1.ToTestDisplayString()); + + var extension2 = tree.GetRoot().DescendantNodes().OfType().Last(); + var symbol2 = model.GetDeclaredSymbol(extension2); + var sourceExtension2 = symbol2.GetSymbol(); + Assert.Equal("<>E__1`2", symbol2.MetadataName); + Assert.Equal("Extensions.<>E__1", symbol2.ToTestDisplayString()); + } + + [Fact] + public void ExtensionIndex_TwoExtensions_DifferentSignatures_02() + { + var src = """ +public static class Extensions +{ + extension(T) { } + extension(T1) where T1 : struct { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension1 = tree.GetRoot().DescendantNodes().OfType().First(); + var symbol1 = model.GetDeclaredSymbol(extension1); + var sourceExtension1 = symbol1.GetSymbol(); + Assert.Equal("<>E__0`1", symbol1.MetadataName); + Assert.Equal("Extensions.<>E__0", symbol1.ToTestDisplayString()); + + var extension2 = tree.GetRoot().DescendantNodes().OfType().Last(); + var symbol2 = model.GetDeclaredSymbol(extension2); + var sourceExtension2 = symbol2.GetSymbol(); + Assert.Equal("<>E__1`1", symbol2.MetadataName); + Assert.Equal("Extensions.<>E__1", symbol2.ToTestDisplayString()); + } + + [Fact] + public void ExtensionIndex_ElevenExtensions() + { + var src = """ +public static class Extensions +{ + extension(T1 o1) { } + extension(T2 o2) { } + extension(T3 o3) { } + extension(T4 o4) { } + extension(T5 o5) { } + extension(T6 o6) { } + extension(T7 o7) { } + extension(T8 o8) { } + extension(T9 o9) { } + extension(T10 o10) { } + extension(T11 o11) { } +} +"""; + + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Last(); + var symbol = model.GetDeclaredSymbol(extension); + var sourceExtension = symbol.GetSymbol(); + Assert.Equal("<>E__10`1", symbol.MetadataName); + Assert.Equal("Extensions.<>E__10", symbol.ToTestDisplayString()); + } + + [Fact] + public void Member_InstanceMethod() + { + var src = """ +public static class Extensions +{ + extension(object o) + { + void M() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var verifier = CompileAndVerify(comp); + + VerifyTypeIL(verifier, "Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [netstandard]System.Object +{ + .custom instance void [netstandard]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0' + extends [netstandard]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + object o + ) cil managed + { + .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0'::'$' + .method private hidebysig + instance void M () cil managed + { + // Method begins at RVA 0x2069 + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0'::M + } // end of class <>E__0 + // Methods + .method private hidebysig specialname static + void M ( + object o + ) cil managed + { + .custom instance void [netstandard]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method Extensions::M +} // end of class Extensions +"""); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(extension); + Assert.Equal(["M"], symbol.MemberNames); + Assert.Equal(["", "M"], symbol.ContainingType.MemberNames); + Assert.Equal("void Extensions.<>E__0.M()", symbol.GetMember("M").ToTestDisplayString()); + } + + [Fact] + public void Member_ExtensionMethod() + { + var src = """ +public static class Extensions +{ + extension(object o) + { + void M(this int i) { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (5,14): error CS1109: Extension methods must be defined in a top level static class; is a nested class + // void M(this int i) { } + Diagnostic(ErrorCode.ERR_ExtensionMethodsDecl, "M").WithArguments("").WithLocation(5, 14)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var method = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(method); + Assert.Equal("void Extensions.<>E__0.M(this System.Int32 i)", symbol.ToTestDisplayString()); + Assert.True(symbol.IsExtensionMethod); + } + + [Fact] + public void Member_StaticMethod() + { + var src = """ +public static class Extensions +{ + extension(object) + { + static void M() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var verifier = CompileAndVerify(comp); + + VerifyTypeIL(verifier, "Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [netstandard]System.Object +{ + .custom instance void [netstandard]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0' + extends [netstandard]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + object '' + ) cil managed + { + .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0'::'$' + .method private hidebysig static + void M () cil managed + { + // Method begins at RVA 0x2069 + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0'::M + } // end of class <>E__0 + // Methods + .method private hidebysig specialname static + void M () cil managed + { + // Method begins at RVA 0x2067 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method Extensions::M +} // end of class Extensions +"""); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(extension); + Assert.Equal(["M"], symbol.MemberNames); + Assert.Equal("void Extensions.<>E__0.M()", symbol.GetMember("M").ToTestDisplayString()); + } + + [Fact] + public void Member_InstanceMethod_ExplicitInterfaceImplementation() + { + var src = """ +public interface I +{ + void M(); +} + +public static class Extensions +{ + extension(object o) + { + void I.M() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (10,16): error CS0541: 'Extensions.extension(object).M()': explicit interface declaration can only be declared in a class, record, struct or interface + // void I.M() { } + Diagnostic(ErrorCode.ERR_ExplicitInterfaceImplementationInNonClassOrStruct, "M").WithArguments("Extensions.extension(object).M()").WithLocation(10, 16)); + } + + [Fact] + public void Member_InstanceMethod_ShadowingTypeParameter() + { + var src = """ +public static class Extensions +{ + extension(T o) + { + void M() { } + void M2(int T) { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (5,16): error CS9289: Type parameter 'T' has the same name as an extension container type parameter + // void M() { } + Diagnostic(ErrorCode.ERR_TypeParameterSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(5, 16), + // (6,21): error CS9288: 'T': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + // void M2(int T) { } + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(6, 21) + ); + } + + [Fact] + public void Member_InstanceProperty() + { + var src = """ +public static class Extensions +{ + extension(object o) + { + int Property { get => 42; set { } } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var verifier = CompileAndVerify(comp); + + VerifyTypeIL(verifier, "Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [netstandard]System.Object +{ + .custom instance void [netstandard]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0' + extends [netstandard]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + object o + ) cil managed + { + .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x206b + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0'::'$' + .method private hidebysig specialname + instance int32 get_Property () cil managed + { + // Method begins at RVA 0x206d + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0'::get_Property + .method private hidebysig specialname + instance void set_Property ( + int32 'value' + ) cil managed + { + // Method begins at RVA 0x206d + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0'::set_Property + // Properties + .property instance int32 Property() + { + .get instance int32 Extensions/'<>E__0'::get_Property() + .set instance void Extensions/'<>E__0'::set_Property(int32) + } + } // end of class <>E__0 + // Methods + .method private hidebysig specialname static + int32 get_Property ( + object o + ) cil managed + { + // Method begins at RVA 0x2067 + // Code size 3 (0x3) + .maxstack 8 + IL_0000: ldc.i4.s 42 + IL_0002: ret + } // end of method Extensions::get_Property + .method private hidebysig specialname static + void set_Property ( + object o, + int32 'value' + ) cil managed + { + // Method begins at RVA 0x206b + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method Extensions::set_Property +} // end of class Extensions +"""); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(extension); + Assert.Equal(["Property"], symbol.MemberNames); + Assert.Equal("System.Int32 Extensions.<>E__0.Property { get; set; }", symbol.GetMember("Property").ToTestDisplayString()); + + AssertEx.Equal([ + "void Extensions.<>E__0.$(System.Object o)", + "System.Int32 Extensions.<>E__0.Property { get; set; }", + "System.Int32 Extensions.<>E__0.Property.get", + "void Extensions.<>E__0.Property.set"], + symbol.GetMembers().ToTestDisplayStrings()); + } + + [Fact] + public void Member_InstanceProperty_Auto() + { + var src = """ +public static class Extensions +{ + extension(object o) + { + int Property { get; set; } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (5,13): error CS9282: Extension declarations can include only methods or properties + // int Property { get; set; } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "Property").WithLocation(5, 13)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(extension); + Assert.Equal(["Property"], symbol.MemberNames); + Assert.Equal("System.Int32 Extensions.<>E__0.Property { get; set; }", symbol.GetMember("Property").ToTestDisplayString()); + + AssertEx.Equal([ + "void Extensions.<>E__0.$(System.Object o)", + "System.Int32 Extensions.<>E__0.k__BackingField", + "System.Int32 Extensions.<>E__0.Property { get; set; }", + "System.Int32 Extensions.<>E__0.Property.get", + "void Extensions.<>E__0.Property.set"], + symbol.GetMembers().ToTestDisplayStrings()); + } + + [Fact] + public void Member_InstanceProperty_ExplicitInterfaceImplementation() + { + var src = """ +public interface I +{ + int Property { get; set; } +} +public static class Extensions +{ + extension(object o) + { + int I.Property { get => 42; set { } } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (9,15): error CS0541: 'Extensions.extension(object).Property': explicit interface declaration can only be declared in a class, record, struct or interface + // int I.Property { get => 42; set { } } + Diagnostic(ErrorCode.ERR_ExplicitInterfaceImplementationInNonClassOrStruct, "Property").WithArguments("Extensions.extension(object).Property").WithLocation(9, 15)); + } + + [Fact] + public void Member_StaticProperty() + { + var src = """ +public static class Extensions +{ + extension(object) + { + static int Property { get => 42; set { } } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var verifier = CompileAndVerify(comp); + + VerifyTypeIL(verifier, "Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions +extends [netstandard]System.Object +{ + .custom instance void [netstandard]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0' + extends [netstandard]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + object '' + ) cil managed + { + .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x206b + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0'::'$' + .method private hidebysig specialname static + int32 get_Property () cil managed + { + // Method begins at RVA 0x206d + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0'::get_Property + .method private hidebysig specialname static + void set_Property ( + int32 'value' + ) cil managed + { + // Method begins at RVA 0x206d + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0'::set_Property + // Properties + .property int32 Property() + { + .get int32 Extensions/'<>E__0'::get_Property() + .set void Extensions/'<>E__0'::set_Property(int32) + } + } // end of class <>E__0 + // Methods + .method private hidebysig specialname static + int32 get_Property () cil managed + { + // Method begins at RVA 0x2067 + // Code size 3 (0x3) + .maxstack 8 + IL_0000: ldc.i4.s 42 + IL_0002: ret + } // end of method Extensions::get_Property + .method private hidebysig specialname static + void set_Property ( + int32 'value' + ) cil managed + { + // Method begins at RVA 0x206b + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method Extensions::set_Property +} // end of class Extensions +"""); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(extension); + Assert.Equal(["Property"], symbol.MemberNames); + Assert.Equal("System.Int32 Extensions.<>E__0.Property { get; set; }", symbol.GetMember("Property").ToTestDisplayString()); + } + + [Fact] + public void Member_StaticProperty_Auto() + { + var src = """ +public static class Extensions +{ + extension(object) + { + static int Property { get; set; } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (5,20): error CS9282: Extension declarations can include only methods or properties + // static int Property { get; set; } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "Property").WithLocation(5, 20)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(extension); + Assert.Equal(["Property"], symbol.MemberNames); + AssertEx.Equal([ + "void Extensions.<>E__0.$(System.Object)", + "System.Int32 Extensions.<>E__0.k__BackingField", + "System.Int32 Extensions.<>E__0.Property { get; set; }", + "System.Int32 Extensions.<>E__0.Property.get", + "void Extensions.<>E__0.Property.set"], + symbol.GetMembers().ToTestDisplayStrings()); + + Assert.Equal("System.Int32 Extensions.<>E__0.Property { get; set; }", symbol.GetMember("Property").ToTestDisplayString()); + } + + [Fact] + public void Member_InstanceIndexer() + { + var src = """ +public static class Extensions +{ + extension(object o) + { + int this[int i] { get => 42; set { } } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var verifier = CompileAndVerify(comp); + + VerifyTypeIL(verifier, "Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [netstandard]System.Object +{ + .custom instance void [netstandard]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0' + extends [netstandard]System.Object + { + .custom instance void [netstandard]System.Reflection.DefaultMemberAttribute::.ctor(string) = ( + 01 00 04 49 74 65 6d 00 00 + ) + // Methods + .method private hidebysig specialname static + void '$' ( + object o + ) cil managed + { + .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x206b + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0'::'$' + .method private hidebysig specialname + instance int32 get_Item ( + int32 i + ) cil managed + { + // Method begins at RVA 0x206d + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0'::get_Item + .method private hidebysig specialname + instance void set_Item ( + int32 i, + int32 'value' + ) cil managed + { + // Method begins at RVA 0x206d + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0'::set_Item + // Properties + .property instance int32 Item( + int32 i + ) + { + .get instance int32 Extensions/'<>E__0'::get_Item(int32) + .set instance void Extensions/'<>E__0'::set_Item(int32, int32) + } + } // end of class <>E__0 + // Methods + .method private hidebysig specialname static + int32 get_Item ( + object o, + int32 i + ) cil managed + { + // Method begins at RVA 0x2067 + // Code size 3 (0x3) + .maxstack 8 + IL_0000: ldc.i4.s 42 + IL_0002: ret + } // end of method Extensions::get_Item + .method private hidebysig specialname static + void set_Item ( + object o, + int32 i, + int32 'value' + ) cil managed + { + // Method begins at RVA 0x206b + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method Extensions::set_Item +} // end of class Extensions +"""); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(extension); + Assert.Equal(["this[]"], symbol.MemberNames); + Assert.Equal("System.Int32 Extensions.<>E__0.this[System.Int32 i] { get; set; }", symbol.GetMember("this[]").ToTestDisplayString()); + + AssertEx.Equal([ + "void Extensions.<>E__0.$(System.Object o)", + "System.Int32 Extensions.<>E__0.this[System.Int32 i] { get; set; }", + "System.Int32 Extensions.<>E__0.this[System.Int32 i].get", + "void Extensions.<>E__0.this[System.Int32 i].set"], + symbol.GetMembers().ToTestDisplayStrings()); + + var comp5 = CreateCompilation(src); + comp5.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_ExtensionAttribute__ctor); + comp5.VerifyEmitDiagnostics( + // (3,5): error CS1110: Cannot define a new extension because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? + // extension(object o) + Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "extension").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(3, 5) + ); + } + + [Fact] + public void Member_StaticIndexer() + { + var src = """ +public static class Extensions +{ + extension(object o) + { + static int this[int i] { get => 42; set { } } + } +} +"""; + var comp = CreateCompilation(src); + comp.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_ExtensionAttribute__ctor); + comp.VerifyEmitDiagnostics( + // (3,5): error CS1110: Cannot define a new extension because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? + // extension(object o) + Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "extension").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(3, 5), + // (5,20): error CS0106: The modifier 'static' is not valid for this item + // static int this[int i] { get => 42; set { } } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "this").WithArguments("static").WithLocation(5, 20) + ); + } + + [Fact] + public void Member_Type() + { + var src = """ +public static class Extensions +{ + extension(object) + { + class Nested { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (5,15): error CS9282: Extension declarations can include only methods or properties + // class Nested { } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "Nested").WithLocation(5, 15)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(extension); + Assert.Empty(symbol.MemberNames); + Assert.Equal(["void Extensions.<>E__0.$(System.Object)", "Extensions.<>E__0.Nested"], symbol.GetMembers().ToTestDisplayStrings()); + Assert.Equal(["Extensions.<>E__0.Nested"], symbol.GetTypeMembers().ToTestDisplayStrings()); + Assert.Equal("Extensions.<>E__0.Nested", symbol.GetTypeMember("Nested").ToTestDisplayString()); + } + + [Fact] + public void Member_Constructor() + { + var src = """ +public static class Extensions +{ + extension(object) { Extensions() { } } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,25): error CS1520: Method must have a return type + // extension(object) { Extensions() { } } + Diagnostic(ErrorCode.ERR_MemberNeedsType, "Extensions").WithLocation(3, 25), + // (3,25): error CS9282: Extension declarations can include only methods or properties + // extension(object) { Extensions() { } } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "Extensions").WithLocation(3, 25)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(extension); + AssertExtensionDeclaration(symbol); + + Assert.Equal([".ctor"], symbol.MemberNames); + Assert.Equal(["Extensions.<>E__0..ctor()"], symbol.InstanceConstructors.ToTestDisplayStrings()); + Assert.Empty(symbol.StaticConstructors); + Assert.Equal(["Extensions.<>E__0..ctor()"], symbol.Constructors.ToTestDisplayStrings()); + } + + [Fact] + public void Member_Finalizer() + { + var src = """ +public static class Extensions +{ + extension(object) { ~Extensions() { } } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,26): error CS9282: Extension declarations can include only methods or properties + // extension(object) { ~Extensions() { } } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "Extensions").WithLocation(3, 26)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(extension); + AssertExtensionDeclaration(symbol); + + Assert.Equal(["Finalize"], symbol.MemberNames); + Assert.Equal(["void Extensions.<>E__0.$(System.Object)", "void Extensions.<>E__0.Finalize()"], symbol.GetMembers().ToTestDisplayStrings()); + } + + [Fact] + public void Member_Field() + { + var src = """ +_ = new object().field; + +public static class Extensions +{ + extension(object o) { int field = 0; } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,18): error CS1061: 'object' does not contain a definition for 'field' and no accessible extension method 'field' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) + // _ = new object().field; + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "field").WithArguments("object", "field").WithLocation(1, 18), + // (5,31): error CS9282: Extension declarations can include only methods or properties + // extension(object o) { int field = 0; } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "field").WithLocation(5, 31), + // (5,31): warning CS0169: The field 'Extensions.extension(object).field' is never used + // extension(object o) { int field = 0; } + Diagnostic(ErrorCode.WRN_UnreferencedField, "field").WithArguments("Extensions.extension(object).field").WithLocation(5, 31)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(extension); + AssertExtensionDeclaration(symbol); + + Assert.Equal(["field"], symbol.MemberNames); + Assert.Equal(["void Extensions.<>E__0.$(System.Object o)", "System.Int32 Extensions.<>E__0.field"], symbol.GetMembers().ToTestDisplayStrings()); + } + + [Fact] + public void Member_Const() + { + var src = """ +public static class Extensions +{ + extension(object) { const int i = 0; } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,35): error CS9282: Extension declarations can include only methods or properties + // extension(object) { const int i = 0; } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "i").WithLocation(3, 35)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(extension); + AssertExtensionDeclaration(symbol); + + Assert.Equal(["i"], symbol.MemberNames); + Assert.Equal(["void Extensions.<>E__0.$(System.Object)", "System.Int32 Extensions.<>E__0.i"], symbol.GetMembers().ToTestDisplayStrings()); + } + + [Fact] + public void Member_InstanceEvent_ExplicitInterfaceImplementation() + { + var src = """ +public interface I +{ + event System.Action E; +} +public static class Extensions +{ + extension(object o) + { + event System.Action I.E { add { } remove { } } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (9,31): error CS0541: 'Extensions.extension(object).E': explicit interface declaration can only be declared in a class, record, struct or interface + // event System.Action I.E { add { } remove { } } + Diagnostic(ErrorCode.ERR_ExplicitInterfaceImplementationInNonClassOrStruct, "E").WithArguments("Extensions.extension(object).E").WithLocation(9, 31), + // (9,31): error CS9282: Extension declarations can include only methods or properties + // event System.Action I.E { add { } remove { } } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "E").WithLocation(9, 31), + // (9,35): error CS9282: Extension declarations can include only methods or properties + // event System.Action I.E { add { } remove { } } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "add").WithLocation(9, 35), + // (9,43): error CS9282: Extension declarations can include only methods or properties + // event System.Action I.E { add { } remove { } } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "remove").WithLocation(9, 43)); + } + + [Theory] + [InlineData("class")] + [InlineData("struct")] + [InlineData("interface")] + [InlineData("record")] + [InlineData("record struct")] + public void IsExtension_MiscTypeKinds(string typeKind) + { + var src = $$""" +{{typeKind}} C { } +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var type = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(type); + Assert.False(symbol.IsExtension); + } + + [Fact] + public void IsExtension_Delegate() + { + var src = $$""" +delegate void C(); +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var type = tree.GetRoot().DescendantNodes().OfType().Single(); + var symbol = model.GetDeclaredSymbol(type); + Assert.False(symbol.IsExtension); + } + + [Fact] + public void IsExtension_Enum() + { + var src = $$""" +enum E { } +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var type = tree.GetRoot().DescendantNodes().OfType().Single(); + var symbol = model.GetDeclaredSymbol(type); + Assert.False(symbol.IsExtension); + } + + [Fact] + public void Attributes_01() + { + var src = """ +public static class Extensions +{ + [System.Obsolete] + extension(object) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,6): error CS0592: Attribute 'System.Obsolete' is not valid on this declaration type. It is only valid on 'class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate' declarations. + // [System.Obsolete] + Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "System.Obsolete").WithArguments("System.Obsolete", "class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate").WithLocation(3, 6)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var type = tree.GetRoot().DescendantNodes().OfType().Single(); + var symbol = model.GetDeclaredSymbol(type); + AssertEx.SetEqual(["System.ObsoleteAttribute"], symbol.GetAttributes().Select(a => a.ToString())); + } + + [Fact] + public void Attributes_02() + { + var src = """ +public static class Extensions +{ + [My(nameof(o)), My(nameof(Extensions))] + extension(object o) { } +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string s) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,6): error CS0592: Attribute 'My' is not valid on this declaration type. It is only valid on 'assembly, module, class, struct, enum, constructor, method, property, indexer, field, event, interface, parameter, delegate, return, type parameter' declarations. + // [My(nameof(o)), My(nameof(Extensions))] + Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "My").WithArguments("My", "assembly, module, class, struct, enum, constructor, method, property, indexer, field, event, interface, parameter, delegate, return, type parameter").WithLocation(3, 6), + // (3,21): error CS0579: Duplicate 'My' attribute + // [My(nameof(o)), My(nameof(Extensions))] + Diagnostic(ErrorCode.ERR_DuplicateAttribute, "My").WithArguments("My").WithLocation(3, 21) + ); + } + + [Fact] + public void ReceiverParameter() + { + var src = """ +public static class Extensions +{ + extension(object) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var type = tree.GetRoot().DescendantNodes().OfType().Single(); + var symbol = model.GetDeclaredSymbol(type); + Assert.Equal("System.Object", symbol.ExtensionParameter.ToTestDisplayString()); + } + + [Fact] + public void ReceiverParameter_WithIdentifier() + { + var src = """ +public static class Extensions +{ + extension(object o) + { + public object M() { return o; } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var type = tree.GetRoot().DescendantNodes().OfType().Single(); + var symbol = model.GetDeclaredSymbol(type); + Assert.Equal("System.Object o", symbol.ExtensionParameter.ToTestDisplayString()); + + var returnStatement = GetSyntax(tree, "return o;"); + Assert.Equal("System.Object o", model.GetSymbolInfo(returnStatement.Expression).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ReceiverParameter_Multiple() + { + var src = """ +public static class Extensions +{ + extension(int i, int j, C c) { } +} +class C { } +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,22): error CS9285: An extension container can have only one receiver parameter + // extension(int i, int j, C c) { } + Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "int j").WithLocation(3, 22), + // (3,29): error CS9285: An extension container can have only one receiver parameter + // extension(int i, int j, C c) { } + Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "C c").WithLocation(3, 29)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var type = tree.GetRoot().DescendantNodes().OfType().Single(); + var symbol = model.GetDeclaredSymbol(type); + var extensionParameter = symbol.ExtensionParameter; + + Assert.Equal("System.Int32 i", extensionParameter.ToTestDisplayString()); + Assert.True(extensionParameter.Equals(extensionParameter)); + + var parameterSyntaxes = tree.GetRoot().DescendantNodes().OfType().ToArray(); + Assert.Equal("System.Int32 i", model.GetDeclaredSymbol(parameterSyntaxes[0]).ToTestDisplayString()); + Assert.Same(extensionParameter, model.GetDeclaredSymbol(parameterSyntaxes[0])); + + Assert.Equal("System.Int32", model.GetTypeInfo(parameterSyntaxes[1].Type).Type.ToTestDisplayString()); + Assert.Null(model.GetDeclaredSymbol(parameterSyntaxes[1])); + + Assert.Equal("C", model.GetTypeInfo(parameterSyntaxes[2].Type).Type.ToTestDisplayString()); + Assert.Null(model.GetDeclaredSymbol(parameterSyntaxes[2])); + } + + [Fact] + public void ReceiverParameter_Multiple_MissingType() + { + var src = """ +public static class Extensions +{ + extension(int i, Type) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,22): error CS9285: An extension container can have only one receiver parameter + // extension(int i, Type) { } + Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "Type").WithLocation(3, 22)); + } + + [Fact] + public void ReceiverParameter_TypeParameter_Found() + { + var src = """ +public static class Extensions +{ + extension(T) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var type = tree.GetRoot().DescendantNodes().OfType().Single(); + var symbol = model.GetDeclaredSymbol(type); + var extensionParameter = symbol.ExtensionParameter; + Assert.Equal("T", extensionParameter.ToTestDisplayString()); + Assert.Same(extensionParameter.Type, symbol.TypeParameters[0]); + } + + [Fact] + public void ReceiverParameter_TypeParameter_Found_FromContainingType() + { + var src = """ +public static class Extensions +{ + extension(T) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,5): error CS9283: Extensions must be declared in a top-level, non-generic, static class + // extension(T) { } + Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(3, 5)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var type = tree.GetRoot().DescendantNodes().OfType().Single(); + var symbol = model.GetDeclaredSymbol(type); + var extensionParameter = symbol.ExtensionParameter; + Assert.Equal("T", extensionParameter.ToTestDisplayString()); + Assert.Same(extensionParameter.Type, symbol.ContainingType.TypeParameters[0]); + } + + [Fact] + public void ReceiverParameter_TypeParameter_Missing() + { + var src = """ +public static class Extensions +{ + extension(T) + { + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,15): error CS0246: The type or namespace name 'T' could not be found (are you missing a using directive or an assembly reference?) + // extension(T) + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "T").WithArguments("T").WithLocation(3, 15)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var type = tree.GetRoot().DescendantNodes().OfType().Single(); + var symbol = model.GetDeclaredSymbol(type); + var parameter = symbol.ExtensionParameter; + Assert.Equal("T", parameter.ToTestDisplayString()); + Assert.True(parameter.Type.IsErrorType()); + } + + [Fact] + public void ReceiverParameter_TypeParameter_Unreferenced_01() + { + var src = """ +int.M(); + +public static class Extensions +{ + extension(int) + { + public static void M() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,5): error CS1061: 'int' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'int' could be found (are you missing a using directive or an assembly reference?) + // int.M(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("int", "M").WithLocation(1, 5), + // (5,18): error CS9295: The extended type 'int' must reference all the type parameters declared by the extension, but type parameter 'T' is not referenced. + // extension(int) + Diagnostic(ErrorCode.ERR_UnderspecifiedExtension, "int").WithArguments("int", "T").WithLocation(5, 18)); + } + + [Fact] + public void ReceiverParameter_TypeParameter_Unreferenced_02() + { + var src = """ +int.M(); + +public static class Extensions +{ + extension(T1) + { + public static void M() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,5): error CS1061: 'int' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'int' could be found (are you missing a using directive or an assembly reference?) + // int.M(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("int", "M").WithLocation(1, 5), + // (5,23): error CS9295: The extended type 'T1' must reference all the type parameters declared by the extension, but type parameter 'T2' is not referenced. + // extension(T1) + Diagnostic(ErrorCode.ERR_UnderspecifiedExtension, "T1").WithArguments("T1", "T2").WithLocation(5, 23)); + } + + [Fact] + public void ReceiverParameter_TypeParameter_Unreferenced_03() + { + var src = """ +int.M(); + +public static class Extensions +{ + extension(T1) where T1 : class + { + public static void M() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,5): error CS1061: 'int' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'int' could be found (are you missing a using directive or an assembly reference?) + // int.M(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("int", "M").WithLocation(1, 5), + // (5,23): error CS9295: The extended type 'T1' must reference all the type parameters declared by the extension, but type parameter 'T2' is not referenced. + // extension(T1) where T1 : class + Diagnostic(ErrorCode.ERR_UnderspecifiedExtension, "T1").WithArguments("T1", "T2").WithLocation(5, 23)); + } + + [Fact] + public void ReceiverParameter_TypeParameter_Missing_Local() + { + var src = """ +public static class Extensions +{ + extension(T) + { + void T() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,15): error CS0246: The type or namespace name 'T' could not be found (are you missing a using directive or an assembly reference?) + // extension(T) + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "T").WithArguments("T").WithLocation(3, 15)); + } + + [Fact] + public void ReceiverParameter_Params() + { + var src = """ +public static class Extensions +{ + extension(params int[] i) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,15): error CS1670: params is not valid in this context + // extension(params int[] i) { } + Diagnostic(ErrorCode.ERR_IllegalParams, "params").WithLocation(3, 15)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var type1 = tree.GetRoot().DescendantNodes().OfType().First(); + var symbol1 = model.GetDeclaredSymbol(type1); + var parameter = symbol1.ExtensionParameter; + Assert.Equal("System.Int32[] i", parameter.ToTestDisplayString()); + Assert.False(parameter.IsParams); + } + + [Fact] + public void ReceiverParameter_Params_BadType() + { + var src = """ +public static class Extensions +{ + extension(params int i) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,15): error CS1670: params is not valid in this context + // extension(params int i) { } + Diagnostic(ErrorCode.ERR_IllegalParams, "params").WithLocation(3, 15)); + } + + [Fact] + public void ReceiverParameter_Params_NotLast() + { + var src = """ +public static class Extensions +{ + extension(params int[] i, int j) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,15): error CS1670: params is not valid in this context + // extension(params int[] i, int j) { } + Diagnostic(ErrorCode.ERR_IllegalParams, "params").WithLocation(3, 15), + // (3,31): error CS9285: An extension container can have only one receiver parameter + // extension(params int[] i, int j) { } + Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "int j").WithLocation(3, 31)); + } + + [Fact] + public void ReceiverParameter_ParameterTypeViolatesConstraint() + { + var src = """ +public static class Extensions +{ + extension(C) { } + extension(C) where T2 : struct { } +} + +public class C where T : struct { } +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,18): error CS0453: The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'C' + // extension(C) { } + Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "C").WithArguments("C", "T", "T").WithLocation(3, 18)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var type1 = tree.GetRoot().DescendantNodes().OfType().First(); + var symbol1 = model.GetDeclaredSymbol(type1); + Assert.Equal("C", symbol1.ExtensionParameter.ToTestDisplayString()); + } + + [Fact] + public void ReceiverParameter_DefaultValue() + { + var src = """ +public static class Extensions +{ + extension(int i = 0) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,15): error CS9284: The receiver parameter of an extension cannot have a default value + // extension(int i = 0) { } + Diagnostic(ErrorCode.ERR_ExtensionParameterDisallowsDefaultValue, "int i = 0").WithLocation(3, 15)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var type = tree.GetRoot().DescendantNodes().OfType().Single(); + var symbol = model.GetDeclaredSymbol(type); + Assert.True(symbol.ExtensionParameter.HasExplicitDefaultValue); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : consider not recognizing the default value entirely + } + + [Fact] + public void ReceiverParameter_DefaultValue_BeforeAnotherParameter() + { + var src = """ +public static class Extensions +{ + extension(int i = 0, object) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,15): error CS9284: The receiver parameter of an extension cannot have a default value + // extension(int i = 0, object) { } + Diagnostic(ErrorCode.ERR_ExtensionParameterDisallowsDefaultValue, "int i = 0").WithLocation(3, 15), + // (3,26): error CS9285: An extension container can have only one receiver parameter + // extension(int i = 0, object) { } + Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "object").WithLocation(3, 26)); + } + + [Fact] + public void ReceiverParameter_DefaultValue_BadValue() + { + var src = """ +public static class Extensions +{ + extension(int i = null) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,15): error CS9284: The receiver parameter of an extension cannot have a default value + // extension(int i = null) { } + Diagnostic(ErrorCode.ERR_ExtensionParameterDisallowsDefaultValue, "int i = null").WithLocation(3, 15)); + } + + [Fact] + public void ReceiverParameter_DefaultValue_RefReadonly() + { + var src = """ +public static class Extensions +{ + extension(ref readonly int x = 2) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,15): error CS9284: The receiver parameter of an extension cannot have a default value + // extension(ref readonly int x = 2) { } + Diagnostic(ErrorCode.ERR_ExtensionParameterDisallowsDefaultValue, "ref readonly int x = 2").WithLocation(3, 15)); + } + + [Fact] + public void ReceiverParameter_Attributes_01() + { + var src = """ +public static class Extensions +{ + extension([System.Runtime.InteropServices.DefaultParameterValue(1)] int o = 2) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,15): error CS9284: The receiver parameter of an extension cannot have a default value + // extension([System.Runtime.InteropServices.DefaultParameterValue(1)] int o = 2) { } + Diagnostic(ErrorCode.ERR_ExtensionParameterDisallowsDefaultValue, "[System.Runtime.InteropServices.DefaultParameterValue(1)] int o = 2").WithLocation(3, 15), + // (3,16): error CS1745: Cannot specify default parameter value in conjunction with DefaultParameterAttribute or OptionalAttribute + // extension([System.Runtime.InteropServices.DefaultParameterValue(1)] int o = 2) { } + Diagnostic(ErrorCode.ERR_DefaultValueUsedWithAttributes, "System.Runtime.InteropServices.DefaultParameterValue").WithLocation(3, 16)); + } + + [Fact] + public void ReceiverParameter_Attributes_02() + { + var src = """ +public static class Extensions +{ + extension([System.Runtime.InteropServices.Optional, System.Runtime.InteropServices.DefaultParameterValue(1)] ref readonly int i) { } + extension([System.Runtime.InteropServices.Optional, System.Runtime.InteropServices.DefaultParameterValue(2)] ref readonly int) { } +} +"""; + var comp = CreateCompilation(src); + // Note: we use "" name in the diagnostic for the second parameter + // Note: these attributes are allowed on the receiver parameter of an extension method + comp.VerifyEmitDiagnostics( + // (3,57): warning CS9200: A default value is specified for 'ref readonly' parameter 'i', but 'ref readonly' should be used only for references. Consider declaring the parameter as 'in'. + // extension([System.Runtime.InteropServices.Optional, System.Runtime.InteropServices.DefaultParameterValue(1)] ref readonly int i) { } + Diagnostic(ErrorCode.WRN_RefReadonlyParameterDefaultValue, "System.Runtime.InteropServices.DefaultParameterValue(1)").WithArguments("i").WithLocation(3, 57), + // (4,57): warning CS9200: A default value is specified for 'ref readonly' parameter '', but 'ref readonly' should be used only for references. Consider declaring the parameter as 'in'. + // extension([System.Runtime.InteropServices.Optional, System.Runtime.InteropServices.DefaultParameterValue(2)] ref readonly int) { } + Diagnostic(ErrorCode.WRN_RefReadonlyParameterDefaultValue, "System.Runtime.InteropServices.DefaultParameterValue(2)").WithArguments("").WithLocation(4, 57)); + } + + [Fact] + public void ReceiverParameter_Attributes_03() + { + var src = """ +public static class Extensions +{ + extension([System.Runtime.CompilerServices.ParamCollectionAttribute] int[] xs) { } +} +"""; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); + comp.VerifyEmitDiagnostics( + // (3,16): error CS0674: Do not use 'System.ParamArrayAttribute'/'System.Runtime.CompilerServices.ParamCollectionAttribute'. Use the 'params' keyword instead. + // extension([System.Runtime.CompilerServices.ParamCollectionAttribute] int[] xs) { } + Diagnostic(ErrorCode.ERR_ExplicitParamArrayOrCollection, "System.Runtime.CompilerServices.ParamCollectionAttribute").WithLocation(3, 16)); + } + + [Fact] + public void ReceiverParameter_Attributes_04() + { + var src = """ +public static class Extensions +{ + extension([System.Runtime.CompilerServices.CallerLineNumber] int x = 2) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,15): error CS9284: The receiver parameter of an extension cannot have a default value + // extension([System.Runtime.CompilerServices.CallerLineNumber] int x = 2) { } + Diagnostic(ErrorCode.ERR_ExtensionParameterDisallowsDefaultValue, "[System.Runtime.CompilerServices.CallerLineNumber] int x = 2").WithLocation(3, 15)); + } + + [Fact] + public void ReceiverParameter_Attributes_54() + { + var src = """ +public static class Extensions +{ + extension([System.Runtime.CompilerServices.CallerLineNumber] int x) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,16): error CS4020: The CallerLineNumberAttribute may only be applied to parameters with default values + // extension([System.Runtime.CompilerServices.CallerLineNumber] int x) { } + Diagnostic(ErrorCode.ERR_BadCallerLineNumberParamWithoutDefaultValue, "System.Runtime.CompilerServices.CallerLineNumber").WithLocation(3, 16)); + } + + [Fact] + public void ReceiverParameter_Attributes_06() + { + var src = """ +public static class Extensions +{ + extension([My] int x) { } +} +public class MyAttribute : System.Attribute { } +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var parameter = tree.GetRoot().DescendantNodes().OfType().Single(); + var parameterSymbol = model.GetDeclaredSymbol(parameter); + Assert.Equal("System.Int32 x", parameterSymbol.ToTestDisplayString()); + AssertEx.SetEqual(["MyAttribute"], parameterSymbol.GetAttributes().Select(a => a.ToString())); + + var type = tree.GetRoot().DescendantNodes().OfType().Single(); + var extensionSymbol = model.GetDeclaredSymbol(type); + AssertEx.SetEqual(["MyAttribute"], extensionSymbol.ExtensionParameter.GetAttributes().Select(a => a.ToString())); + } + + [Fact] + public void ReceiverParameter_This_01() + { + var src = """ +public static class Extensions +{ + extension(this int i) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,15): error CS0027: Keyword 'this' is not available in the current context + // extension(this int i) { } + Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(3, 15)); + } + + [Fact] + public void ReceiverParameter_This_02() + { + var src = """ +public static class Extensions +{ + extension(int i, this int j) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,22): error CS9285: An extension container can have only one receiver parameter + // extension(int i, this int j) { } + Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "this int j").WithLocation(3, 22)); + } + + [Fact] + public void ReceiverParameter_This_03() + { + var src = """ +public static class Extensions +{ + extension(this this int i) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,20): error CS1107: A parameter can only have one 'this' modifier + // extension(this this int i) { } + Diagnostic(ErrorCode.ERR_DupParamMod, "this").WithArguments("this").WithLocation(3, 20), + // (3,20): error CS0027: Keyword 'this' is not available in the current context + // extension(this this int i) { } + Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(3, 20)); + } + + [Fact] + public void ReceiverParameter_Ref_01() + { + var src = """ +int i = 42; +i.M(); +System.Console.Write(i); + +public static class Extensions +{ + extension(ref int i) + { + public void M() { System.Console.Write(i); i = 43; } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "4243").VerifyDiagnostics(); + } + + [Fact] + public void ReceiverParameter_Ref_02() + { + var src = """ +public static class Extensions +{ + extension(ref ref int i) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,19): error CS1107: A parameter can only have one 'ref' modifier + // extension(ref ref int i) { } + Diagnostic(ErrorCode.ERR_DupParamMod, "ref").WithArguments("ref").WithLocation(3, 19)); + } + + [Fact] + public void ReceiverParameter_Out_01() + { + var src = """ +public static class Extensions +{ + extension(out int i) + { + void M2() { } + static void M3() { } + } + static void M(this out int i) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,15): error CS8328: The parameter modifier 'out' cannot be used with 'extension' + // extension(out int i) + Diagnostic(ErrorCode.ERR_BadParameterModifiers, "out").WithArguments("out", "extension").WithLocation(3, 15), + // (5,14): error CS0177: The out parameter 'i' must be assigned to before control leaves the current method + // void M2() { } + Diagnostic(ErrorCode.ERR_ParamUnassigned, "M2").WithArguments("i").WithLocation(5, 14), + // (8,17): error CS0177: The out parameter 'i' must be assigned to before control leaves the current method + // static void M(this out int i) { } + Diagnostic(ErrorCode.ERR_ParamUnassigned, "M").WithArguments("i").WithLocation(8, 17), + // (8,24): error CS8328: The parameter modifier 'out' cannot be used with 'this' + // static void M(this out int i) { } + Diagnostic(ErrorCode.ERR_BadParameterModifiers, "out").WithArguments("out", "this").WithLocation(8, 24)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var type1 = tree.GetRoot().DescendantNodes().OfType().First(); + var symbol1 = model.GetDeclaredSymbol(type1); + var parameter = symbol1.ExtensionParameter; + Assert.Equal("out System.Int32 i", parameter.ToTestDisplayString()); + Assert.Equal(RefKind.Out, parameter.RefKind); + } + + [Fact] + public void ReceiverParameter_Out_02() + { + var src = """ +public static class Extensions +{ + extension(int i, out int j) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,22): error CS9285: An extension container can have only one receiver parameter + // extension(int i, out int j) { } + Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "out int j").WithLocation(3, 22)); + } + + [Fact] + public void ReceiverParameter_Out_03() + { + var src = """ +public static class Extensions +{ + extension(out out int i) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,15): error CS8328: The parameter modifier 'out' cannot be used with 'extension' + // extension(out out int i) { } + Diagnostic(ErrorCode.ERR_BadParameterModifiers, "out").WithArguments("out", "extension").WithLocation(3, 15), + // (3,19): error CS8328: The parameter modifier 'out' cannot be used with 'extension' + // extension(out out int i) { } + Diagnostic(ErrorCode.ERR_BadParameterModifiers, "out").WithArguments("out", "extension").WithLocation(3, 19)); + } + + [Fact] + public void ReceiverParameter_Out_04() + { + var src = """ +public static class Extensions +{ + extension(out int i) + { + void M2(bool b) { if (b) return; else return; } + } + static void M(this out int i, bool b) { if (b) return; else return; } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,15): error CS8328: The parameter modifier 'out' cannot be used with 'extension' + // extension(out int i) + Diagnostic(ErrorCode.ERR_BadParameterModifiers, "out").WithArguments("out", "extension").WithLocation(3, 15), + // (5,34): error CS0177: The out parameter 'i' must be assigned to before control leaves the current method + // void M2(bool b) { if (b) return; else return; } + Diagnostic(ErrorCode.ERR_ParamUnassigned, "return;").WithArguments("i").WithLocation(5, 34), + // (5,47): error CS0177: The out parameter 'i' must be assigned to before control leaves the current method + // void M2(bool b) { if (b) return; else return; } + Diagnostic(ErrorCode.ERR_ParamUnassigned, "return;").WithArguments("i").WithLocation(5, 47), + // (7,24): error CS8328: The parameter modifier 'out' cannot be used with 'this' + // static void M(this out int i, bool b) { if (b) return; else return; } + Diagnostic(ErrorCode.ERR_BadParameterModifiers, "out").WithArguments("out", "this").WithLocation(7, 24), + // (7,52): error CS0177: The out parameter 'i' must be assigned to before control leaves the current method + // static void M(this out int i, bool b) { if (b) return; else return; } + Diagnostic(ErrorCode.ERR_ParamUnassigned, "return;").WithArguments("i").WithLocation(7, 52), + // (7,65): error CS0177: The out parameter 'i' must be assigned to before control leaves the current method + // static void M(this out int i, bool b) { if (b) return; else return; } + Diagnostic(ErrorCode.ERR_ParamUnassigned, "return;").WithArguments("i").WithLocation(7, 65)); + } + + [Fact] + public void ReceiverParameter_Out_05() + { + var src = """ +public static class Extensions +{ + extension(out int i) + { + void M2(bool b) { i = 0; } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,15): error CS8328: The parameter modifier 'out' cannot be used with 'extension' + // extension(out int i) + Diagnostic(ErrorCode.ERR_BadParameterModifiers, "out").WithArguments("out", "extension").WithLocation(3, 15)); + } + + [Fact] + public void ReceiverParameter_In_01() + { + var src = """ +public static class Extensions +{ + extension(in int i) { } + static void M(this in int i) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void ReceiverParameter_In_02() + { + var src = """ +public static class Extensions +{ + extension(in in int i) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,18): error CS1107: A parameter can only have one 'in' modifier + // extension(in in int i) { } + Diagnostic(ErrorCode.ERR_DupParamMod, "in").WithArguments("in").WithLocation(3, 18)); + } + + [Fact] + public void ReceiverParameter_RefReadonly() + { + var src = """ +int i = 42; +i.M(); + +public static class Extensions +{ + extension(ref readonly int i) + { + public void M() { System.Console.Write(i); } + } + extension(ref readonly int) { } + static void M2(this ref readonly int i) { } +} +"""; + var comp = CreateCompilation(src); + + CompileAndVerify(comp, symbolValidator: (m) => + { + Assert.Equal(RefKind.RefReadOnlyParameter, m.GlobalNamespace.GetMember("Extensions.<>E__0.$").Parameters[0].RefKind); + Assert.Equal(RefKind.RefReadOnlyParameter, m.GlobalNamespace.GetMember("Extensions.<>E__1.$").Parameters[0].RefKind); + }, expectedOutput: "42").VerifyDiagnostics(); + } + + [Fact] + public void ReceiverParameter_ReadonlyRef() + { + var src = """ +public static class Extensions +{ + extension(readonly ref int i) { } + static void M(this readonly ref int i) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,15): error CS9190: 'readonly' modifier must be specified after 'ref'. + // extension(readonly ref int i) { } + Diagnostic(ErrorCode.ERR_RefReadOnlyWrongOrdering, "readonly").WithLocation(3, 15), + // (4,24): error CS9190: 'readonly' modifier must be specified after 'ref'. + // static void M(this readonly ref int i) { } + Diagnostic(ErrorCode.ERR_RefReadOnlyWrongOrdering, "readonly").WithLocation(4, 24)); + } + + [Fact] + public void ReceiverParameter_ArgList_01() + { + var src = """ +_ = object.M(); + +public static class Extensions +{ + extension(__arglist) + { + void M(){} + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,12): error CS0117: 'object' does not contain a definition for 'M' + // _ = object.M(); + Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("object", "M").WithLocation(1, 12), + // (5,15): error CS1669: __arglist is not valid in this context + // extension(__arglist) + Diagnostic(ErrorCode.ERR_IllegalVarArgs, "__arglist").WithLocation(5, 15)); + + Assert.Empty(comp.GetTypeByMetadataName("Extensions").GetMembers().OfType()); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var o = ((Compilation)comp).GetSpecialType(SpecialType.System_Object); + AssertEqualAndNoDuplicates(_objectMembers, model.LookupSymbols(position: 0, o, name: null, includeReducedExtensionMethods: true).ToTestDisplayStrings()); + } + + [Fact] + public void ReceiverParameter_ArgList_02() + { + var src = """ +public static class Extensions +{ + extension(__arglist, int i) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,15): error CS1669: __arglist is not valid in this context + // extension(__arglist, int i) { } + Diagnostic(ErrorCode.ERR_IllegalVarArgs, "__arglist").WithLocation(3, 15), + // (3,26): error CS9285: An extension container can have only one receiver parameter + // extension(__arglist, int i) { } + Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "int i").WithLocation(3, 26)); + } + + [Fact] + public void ReceiverParameter_StaticType_01() + { + var src = """ +public static class Extensions +{ + extension(Extensions) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void ReceiverParameter_StaticType_02() + { + var src = """ +public static class Extensions +{ + extension(object o, Extensions e) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,25): error CS9285: An extension container can have only one receiver parameter + // extension(object o, Extensions e) { } + Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "Extensions e").WithLocation(3, 25)); + } + + [Fact] + public void ReceiverParameter_StaticType_03() + { + var src = """ +public static class Extensions +{ + extension(Extensions e) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,15): error CS0721: 'Extensions': static types cannot be used as parameters + // extension(Extensions) { } + Diagnostic(ErrorCode.ERR_ParameterIsStaticClass, "Extensions").WithArguments("Extensions").WithLocation(3, 15)); + } + + [Fact] + public void ReceiverParameter_StaticType_04() + { + var src = """ +extension(C) { } +extension(C c) { } +public static class C { } +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,1): error CS9283: Extensions must be declared in a top-level, non-generic, static class + // extension(C) { } + Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(1, 1), + // (2,1): error CS9283: Extensions must be declared in a top-level, non-generic, static class + // extension(C c) { } + Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(2, 1), + // (2,11): error CS0721: 'C': static types cannot be used as parameters + // extension(C c) { } + Diagnostic(ErrorCode.ERR_ParameterIsStaticClass, "C").WithArguments("C").WithLocation(2, 11)); + } + + [Fact] + public void ReceiverParameter_StaticType_05() + { + var src = """ +static class Extensions +{ + extension(C) + { + } +} + +static class C {} +"""; + var comp = CreateCompilation(src); + + CompileAndVerify(comp).VerifyDiagnostics(); + } + + [Fact] + public void ReceiverParameter_InstanceType_01() + { + var src = """ +public static class Extensions +{ + extension(C c) { } + extension(C) { } +} +public class C { } +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void ReceiverParameter_ShadowingTypeParameter() + { + var src = """ +public static class Extensions +{ + extension(object T) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,5): error CS9283: Extensions must be declared in a top-level, non-generic, static class + // extension(object T) { } + Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(3, 5)); + } + + [Fact] + public void ReceiverParameter_Ref() + { + var src = """ +int i = 42; +i.M(43); + +public static class Extensions +{ + extension(ref int i) + { + public void M(int j) { System.Console.Write((i, j)); } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "(42, 43)").VerifyDiagnostics(); + } + + [Fact] + public void ReceiverParameter_Scoped_01() + { + var src = """ +public static class Extensions +{ + extension(scoped int i) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,15): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. + // extension(scoped int i) { } + Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped int i").WithLocation(3, 15)); + } + + [Fact] + public void ReceiverParameter_Scoped_02() + { + var src = """ +public static class Extensions +{ + extension(int i, scoped int j) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,22): error CS9285: An extension container can have only one receiver parameter + // extension(int i, scoped int j) { } + Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "scoped int j").WithLocation(3, 22)); + } + + [Fact] + public void ReceiverParameter_Scoped_03() + { + var src = """ +public static class Extensions +{ + extension(scoped System.Span i) { } + public static void M(this scoped System.Span i) { } +} +"""; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void ReceiverParameter_Nullable_01() + { + var src = """ +public static class Extensions +{ + extension(string?) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,21): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. + // extension(string?) { } + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(3, 21)); + } + + [Fact] + public void ReceiverParameter_Nullable_02() + { + var src = """ +#nullable enable +public static class Extensions +{ + extension(string?) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void ReceiverParameter_RestrictedType() + { + var src = """ +public static class Extensions +{ + extension(ref System.ArgIterator) { } + extension(ref System.Span) { } +} +"""; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); + comp.VerifyEmitDiagnostics( + // (3,15): error CS1601: Cannot make reference to variable of type 'ArgIterator' + // extension(ref System.ArgIterator) { } + Diagnostic(ErrorCode.ERR_MethodArgCantBeRefAny, "ref System.ArgIterator").WithArguments("System.ArgIterator").WithLocation(3, 15)); + } + + [Fact] + public void ReceiverParameter_Empty() + { + var src = """ +public static class Extensions +{ + extension() { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,15): error CS1031: Type expected + // extension() { } + Diagnostic(ErrorCode.ERR_TypeExpected, ")").WithLocation(3, 15)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var type = tree.GetRoot().DescendantNodes().OfType().Single(); + var symbol = model.GetDeclaredSymbol(type); + Assert.Equal("?", symbol.ExtensionParameter.ToTestDisplayString()); + } + + [Fact] + public void ReceiverParameter_ConstraintsCheck() + { + var src = """ +static class Extensions +{ + extension(System.Nullable receiver) + { + } + + extension(System.Nullable) + { + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (3,39): error CS0453: The type 'string' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'Nullable' + // extension(System.Nullable receiver) + Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "receiver").WithArguments("System.Nullable", "T", "string").WithLocation(3, 39), + // (7,15): error CS0453: The type 'string' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'Nullable' + // extension(System.Nullable) + Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "System.Nullable").WithArguments("System.Nullable", "T", "string").WithLocation(7, 15) + ); + } + + [Fact] + public void ReceiverParameter_RefScope() + { + var src = """ +static class Extensions +{ + extension(scoped ref int receiver) + { + } + + extension(scoped ref int) + { + } +} +"""; + var comp = CreateCompilation(src); + + CompileAndVerify(comp, symbolValidator: (m) => + { + AssertEx.Equal(ScopedKind.ScopedRef, m.GlobalNamespace.GetMember("Extensions.<>E__0.$").Parameters[0].EffectiveScope); + AssertEx.Equal(ScopedKind.ScopedRef, m.GlobalNamespace.GetMember("Extensions.<>E__1.$").Parameters[0].EffectiveScope); + }).VerifyDiagnostics(); + } + + [Fact] + public void ReceiverParameter_Nullability() + { + var src = """ +#nullable enable + +static class Extensions +{ + extension(string? receiver) + { + } + + extension(string?) + { + } +} +"""; + var comp = CreateCompilation(src); + + CompileAndVerify(comp, symbolValidator: (m) => + { + AssertEx.Equal("System.String?", m.GlobalNamespace.GetMember("Extensions.<>E__0.$").Parameters[0].TypeWithAnnotations.ToTestDisplayString()); + AssertEx.Equal("System.String?", m.GlobalNamespace.GetMember("Extensions.<>E__1.$").Parameters[0].TypeWithAnnotations.ToTestDisplayString()); + }).VerifyDiagnostics(); + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : verify nullability in GetDeclaredSymbol and GetSymbolInfo + } + + [Fact] + public void ReceiverParameter_NativeInteger() + { + var src = """ +#nullable enable + +static class Extensions +{ + extension(nint receiver) + { + } + + extension(nint) + { + } +} +"""; + var comp = CreateCompilation(src); + + CompileAndVerify(comp, symbolValidator: (m) => + { + Assert.True(m.GlobalNamespace.GetMember("Extensions.<>E__0.$").Parameters[0].Type.IsNativeIntegerType); + Assert.True(m.GlobalNamespace.GetMember("Extensions.<>E__1.$").Parameters[0].Type.IsNativeIntegerType); + }).VerifyDiagnostics(); + } + + [Fact] + public void ReceiverParameter_InconsistentTypeAccessibility_01() + { + var src = """ +public static class Extensions +{ + extension(C x) + { + public void M() {} + public int P { get => 0; set {}} + public int this[int i] { get => 0; set {}} + + private void M1() {} + private int P1 { get => 0; set {}} + private int this[long i] { get => 0; set {}} + + internal void M2() {} + internal int P2 { get => 0; set {}} + internal int this[byte i] { get => 0; set {}} + } +} + +class C {} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (5,21): error CS0051: Inconsistent accessibility: parameter type 'C' is less accessible than method 'Extensions.extension(C).M()' + // public void M() {} + Diagnostic(ErrorCode.ERR_BadVisParamType, "M").WithArguments("Extensions.extension(C).M()", "C").WithLocation(5, 21), + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Error wording, this isn't an indexer + // (6,20): error CS0055: Inconsistent accessibility: parameter type 'C' is less accessible than indexer 'Extensions.extension(C).P' + // public int P { get => 0; set {}} + Diagnostic(ErrorCode.ERR_BadVisIndexerParam, "P").WithArguments("Extensions.extension(C).P", "C").WithLocation(6, 20), + // (7,20): error CS0055: Inconsistent accessibility: parameter type 'C' is less accessible than indexer 'Extensions.extension(C).this[int]' + // public int this[int i] { get => 0; set {}} + Diagnostic(ErrorCode.ERR_BadVisIndexerParam, "this").WithArguments("Extensions.extension(C).this[int]", "C").WithLocation(7, 20) + ); + } + + [Fact] + public void ReceiverParameter_InconsistentTypeAccessibility_02() + { + var src = """ +public static class Extensions +{ + extension(C x) + { + } + + private class C {} +} +"""; + var comp = CreateCompilation(src); + + CompileAndVerify(comp).VerifyDiagnostics(); + } + + [Fact] + public void ReceiverParameter_InconsistentTypeAccessibility_03() + { + var src = """ +public static class Extensions +{ + extension(C x) + { + public void M() {} + public int P { get => 0; set {}} + public int this[int i] { get => 0; set {}} + + private void M1() {} + private int P1 { get => 0; set {}} + private int this[long i] { get => 0; set {}} + + internal void M2() {} + internal int P2 { get => 0; set {}} + internal int this[byte i] { get => 0; set {}} + } + + private class C {} +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (5,21): error CS0051: Inconsistent accessibility: parameter type 'Extensions.C' is less accessible than method 'Extensions.extension(Extensions.C).M()' + // public void M() {} + Diagnostic(ErrorCode.ERR_BadVisParamType, "M").WithArguments("Extensions.extension(Extensions.C).M()", "Extensions.C").WithLocation(5, 21), + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Error wording, this isn't an indexer + + // (6,20): error CS0055: Inconsistent accessibility: parameter type 'Extensions.C' is less accessible than indexer 'Extensions.extension(Extensions.C).P' + // public int P { get => 0; set {}} + Diagnostic(ErrorCode.ERR_BadVisIndexerParam, "P").WithArguments("Extensions.extension(Extensions.C).P", "Extensions.C").WithLocation(6, 20), + // (7,20): error CS0055: Inconsistent accessibility: parameter type 'Extensions.C' is less accessible than indexer 'Extensions.extension(Extensions.C).this[int]' + // public int this[int i] { get => 0; set {}} + Diagnostic(ErrorCode.ERR_BadVisIndexerParam, "this").WithArguments("Extensions.extension(Extensions.C).this[int]", "Extensions.C").WithLocation(7, 20), + // (13,23): error CS0051: Inconsistent accessibility: parameter type 'Extensions.C' is less accessible than method 'Extensions.extension(Extensions.C).M2()' + // internal void M2() {} + Diagnostic(ErrorCode.ERR_BadVisParamType, "M2").WithArguments("Extensions.extension(Extensions.C).M2()", "Extensions.C").WithLocation(13, 23), + // (14,22): error CS0055: Inconsistent accessibility: parameter type 'Extensions.C' is less accessible than indexer 'Extensions.extension(Extensions.C).P2' + // internal int P2 { get => 0; set {}} + Diagnostic(ErrorCode.ERR_BadVisIndexerParam, "P2").WithArguments("Extensions.extension(Extensions.C).P2", "Extensions.C").WithLocation(14, 22), + // (15,22): error CS0055: Inconsistent accessibility: parameter type 'Extensions.C' is less accessible than indexer 'Extensions.extension(Extensions.C).this[byte]' + // internal int this[byte i] { get => 0; set {}} + Diagnostic(ErrorCode.ERR_BadVisIndexerParam, "this").WithArguments("Extensions.extension(Extensions.C).this[byte]", "Extensions.C").WithLocation(15, 22) + ); + } + + [Fact] + public void InconsistentTypeAccessibility_01() + { + var src = """ +public static class Extensions +{ + extension(int x) + { + public void M1(C c) {} + private void M2(C c) {} + } + + extension(long x) + { + public static void M3(int y) + { + y.M2(new C()); + } + } + + public static void M4(int x) + { + x.M2(new C()); + } + + private class C {} +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (5,21): error CS0051: Inconsistent accessibility: parameter type 'Extensions.C' is less accessible than method 'Extensions.extension(int).M1(Extensions.C)' + // public void M1(C c) {} + Diagnostic(ErrorCode.ERR_BadVisParamType, "M1").WithArguments("Extensions.extension(int).M1(Extensions.C)", "Extensions.C").WithLocation(5, 21) + ); + } + + [Fact] + public void InconsistentTypeAccessibility_02() + { + var src = """ +public static class Extensions +{ + extension(int x) + { + public C M1 => null; + private C M2 => null; + } + + extension(long x) + { + public static void M3(int y) + { + _ = y.M2; + } + } + + public static void M4(int x) + { + _ = x.M2; + } + + private class C {} +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (5,18): error CS0053: Inconsistent accessibility: property type 'Extensions.C' is less accessible than property 'Extensions.extension(int).M1' + // public C M1 => null; + Diagnostic(ErrorCode.ERR_BadVisPropertyType, "M1").WithArguments("Extensions.extension(int).M1", "Extensions.C").WithLocation(5, 18) + ); + } + + [Fact] + public void Inaccessible_01() + { + var src = """ +static class Extensions +{ + extension(int x) + { + private void M2() {} + } + + private static void M3(this int x) {} +} + +class C +{ + void Test(int x) + { + x.M2(); + x.M3(); + Extensions.M2(x); + Extensions.M3(x); + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (15,11): error CS1061: 'int' does not contain a definition for 'M2' and no accessible extension method 'M2' accepting a first argument of type 'int' could be found (are you missing a using directive or an assembly reference?) + // x.M2(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M2").WithArguments("int", "M2").WithLocation(15, 11), + // (16,11): error CS1061: 'int' does not contain a definition for 'M3' and no accessible extension method 'M3' accepting a first argument of type 'int' could be found (are you missing a using directive or an assembly reference?) + // x.M3(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M3").WithArguments("int", "M3").WithLocation(16, 11), + // (17,20): error CS0122: 'Extensions.M2(int)' is inaccessible due to its protection level + // Extensions.M2(x); + Diagnostic(ErrorCode.ERR_BadAccess, "M2").WithArguments("Extensions.M2(int)").WithLocation(17, 20), + // (18,20): error CS0122: 'Extensions.M3(int)' is inaccessible due to its protection level + // Extensions.M3(x); + Diagnostic(ErrorCode.ERR_BadAccess, "M3").WithArguments("Extensions.M3(int)").WithLocation(18, 20) + ); + } + + [Fact] + public void ReceiverParameter_FileType_01() + { + var src = """ +file class C {} + +static class Extensions +{ + extension(C x) + { + } + + private static void M3(this C x) {} +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (5,14): error CS9051: File-local type 'C' cannot be used in a member signature in non-file-local type 'Extensions'. + // extension(C x) + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "(").WithArguments("C", "Extensions").WithLocation(5, 14), + // (9,25): error CS9051: File-local type 'C' cannot be used in a member signature in non-file-local type 'Extensions'. + // private static void M3(this C x) {} + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M3").WithArguments("C", "Extensions").WithLocation(9, 25) + ); + } + + [Fact] + public void ReceiverParameter_FileType_02() + { + var src = """ +file class C {} + +file static class Extensions +{ + extension(C x) + { + public void M1() {} + public int P => 0; + public int this[int i] => 0; + } + + public static void M2(this C x) {} + + private static void M3(this C x) {} +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void FileType_01() + { + var src = """ +file class C {} + +file static class Extensions +{ + extension(int x) + { + public void M1(C c) {} + public C P => null; + public C this[int y] => null; + public int this[C y] => 0; + } + + public static void M2(this int x, C c) {} +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void ReceiverParameter_PointerType() + { + string source = """ +unsafe static class E +{ + extension(int* i) + { + public static void M() { } + } + public static void M2(this int* i) { } +} +"""; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : missing validation + var comp = CreateCompilation(source, options: TestOptions.UnsafeDebugDll); + comp.VerifyEmitDiagnostics( + // (7,32): error CS1103: The first parameter of an extension method cannot be of type 'int*' + // public static void M2(this int* i) { } + Diagnostic(ErrorCode.ERR_BadTypeforThis, "int*").WithArguments("int*").WithLocation(7, 32)); + } + + [Fact] + public void Skeleton() + { + var src = """ +public static class Extensions +{ + extension(object) + { + void M() { System.Console.Write("ran"); } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var verifier = CompileAndVerify(comp); + verifier.VerifyIL("Extensions.<>E__0.M()", """ +{ + // Code size 2 (0x2) + .maxstack 1 + IL_0000: ldnull + IL_0001: throw +} +"""); + + verifier.VerifyIL("Extensions.M", """ +{ + // Code size 11 (0xb) + .maxstack 1 + IL_0000: ldstr "ran" + IL_0005: call "void System.Console.Write(string)" + IL_000a: ret +} +"""); + } + + [Fact] + public void GetDiagnosticsForSpan_NoReceiverParameter() + { + var src = """ +public static class Extensions +{ + extension(__arglist) + { + public int M() + { + return ""; + } + } +} +"""; + var comp = CreateCompilation(src); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var ext = tree.GetRoot().DescendantNodes().OfType().Single(); + var m = ext.DescendantNodes().OfType().Single(); + + model.GetDiagnostics(ext.ParameterList.Span).Verify( + // (3,15): error CS1669: __arglist is not valid in this context + // extension(__arglist) + Diagnostic(ErrorCode.ERR_IllegalVarArgs, "__arglist").WithLocation(3, 15) + ); + + model.GetDiagnostics(m.Body.Span).Verify( + // (7,20): error CS0029: Cannot implicitly convert type 'string' to 'int' + // return ""; + Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""""").WithArguments("string", "int").WithLocation(7, 20) + ); + + comp.VerifyDiagnostics( + // (7,20): error CS0029: Cannot implicitly convert type 'string' to 'int' + // return ""; + Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""""").WithArguments("string", "int").WithLocation(7, 20), + // (3,15): error CS1669: __arglist is not valid in this context + // extension(__arglist) + Diagnostic(ErrorCode.ERR_IllegalVarArgs, "__arglist").WithLocation(3, 15) + ); + } + + [Fact] + public void GetDiagnosticsForSpan_WithReceiverParameter() + { + var src = """ +public static class Extensions +{ + extension(object o = null) + { + public int M() + { + return ""; + } + } +} +"""; + var comp = CreateCompilation(src); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var ext = tree.GetRoot().DescendantNodes().OfType().Single(); + var m = ext.DescendantNodes().OfType().Single(); + + model.GetDiagnostics(ext.ParameterList.Span).Verify( + // (3,15): error CS9284: The receiver parameter of an extension cannot have a default value + // extension(object o = null) + Diagnostic(ErrorCode.ERR_ExtensionParameterDisallowsDefaultValue, "object o = null").WithLocation(3, 15) + ); + + model.GetDiagnostics(m.Body.Span).Verify( + // (7,20): error CS0029: Cannot implicitly convert type 'string' to 'int' + // return ""; + Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""""").WithArguments("string", "int").WithLocation(7, 20) + ); + + comp.VerifyDiagnostics( + // (3,15): error CS9284: The receiver parameter of an extension cannot have a default value + // extension(object o = null) + Diagnostic(ErrorCode.ERR_ExtensionParameterDisallowsDefaultValue, "object o = null").WithLocation(3, 15), + // (7,20): error CS0029: Cannot implicitly convert type 'string' to 'int' + // return ""; + Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""""").WithArguments("string", "int").WithLocation(7, 20) + ); + + Assert.Equal("[System.Object o = null]", model.GetDeclaredSymbol(ext.ParameterList.Parameters[0]).ToTestDisplayString()); + } + + [Fact] + public void ReceiverInScopeButIllegalInStaticMember() + { + var src = """ +public static class Extensions +{ + extension(object o) + { + static object M1() => o; + static object M2() { return o; } + static object P1 => o; + static object P2 { get { return o; } } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (5,31): error CS9293: Cannot use extension parameter 'object o' in this context. + // static object M1() => o; + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "o").WithArguments("object o").WithLocation(5, 31), + // (6,37): error CS9293: Cannot use extension parameter 'object o' in this context. + // static object M2() { return o; } + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "o").WithArguments("object o").WithLocation(6, 37), + // (7,29): error CS9293: Cannot use extension parameter 'object o' in this context. + // static object P1 => o; + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "o").WithArguments("object o").WithLocation(7, 29), + // (8,41): error CS9293: Cannot use extension parameter 'object o' in this context. + // static object P2 { get { return o; } } + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "o").WithArguments("object o").WithLocation(8, 41) + ); + } + + [Fact] + public void PassingValueForARefReceiver_01() + { + var src = """ +public class C +{ + static void Main() + { + GetInt().M1(); + GetInt().M2(); + _ = GetInt().P; + } + + static int GetInt() => 0; +} + +static class Extensions +{ + extension(ref int receiver) + { + public void M1() {} + public int P => 0; + } + + public static void M2 (this ref int receiver) + { + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (5,9): error CS1510: A ref or out value must be an assignable variable + // GetInt().M1(); + Diagnostic(ErrorCode.ERR_RefLvalueExpected, "GetInt()").WithLocation(5, 9), + // (6,9): error CS1510: A ref or out value must be an assignable variable + // GetInt().M2(); + Diagnostic(ErrorCode.ERR_RefLvalueExpected, "GetInt()").WithLocation(6, 9), + // (7,13): error CS1510: A ref or out value must be an assignable variable + // _ = GetInt().P; + Diagnostic(ErrorCode.ERR_RefLvalueExpected, "GetInt()").WithLocation(7, 13) + ); + } + + [Fact] + public void PassingValueForARefReceiver_02() + { + var src = """ +public class C +{ + static void Main() + { + GetInt().M1(); + GetInt().M2(); + _ = GetInt().P; + } + + static int GetInt() => 0; +} + +static class Extensions +{ + extension(ref readonly int receiver) + { + public void M1() {} + public int P => 0; + } + + public static void M2 (this ref readonly int receiver) + { + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics( + // (5,9): warning CS9193: Argument 0 should be a variable because it is passed to a 'ref readonly' parameter + // GetInt().M1(); + Diagnostic(ErrorCode.WRN_RefReadonlyNotVariable, "GetInt()").WithArguments("0").WithLocation(5, 9), + // (6,9): warning CS9193: Argument 0 should be a variable because it is passed to a 'ref readonly' parameter + // GetInt().M2(); + Diagnostic(ErrorCode.WRN_RefReadonlyNotVariable, "GetInt()").WithArguments("0").WithLocation(6, 9), + // (7,13): warning CS9193: Argument 0 should be a variable because it is passed to a 'ref readonly' parameter + // _ = GetInt().P; + Diagnostic(ErrorCode.WRN_RefReadonlyNotVariable, "GetInt()").WithArguments("0").WithLocation(7, 13) + ); + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Test emit and execution for a scenario like this + } + + [Fact] + public void PassingValueForARefReceiver_03() + { + var src = """ +public class C +{ + static void Main() + { + GetInt().M1(); + GetInt().M2(); + _ = GetInt().P; + } + + static int GetInt() => 0; +} + +static class Extensions +{ + extension(in int receiver) + { + public void M1() {} + public int P => 0; + } + + public static void M2 (this in int receiver) + { + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Test emit and execution for a scenario like this + } + + [Fact] + public void Implementation_InstanceMethod_01() + { + var src = """ +public static class Extensions +{ + extension(object o) + { + void M(string s) + { + o.ToString(); + _ = s.Length; + } + } +} +"""; + var comp = CreateCompilation(src); + var verifier = CompileAndVerify(comp).VerifyDiagnostics(); + + verifier.VerifyTypeIL("Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0' + extends [mscorlib]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + object o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2077 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0'::'$' + .method private hidebysig + instance void M ( + string s + ) cil managed + { + // Method begins at RVA 0x2079 + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0'::M + } // end of class <>E__0 + // Methods + .method private hidebysig specialname static + void M ( + object o, + string s + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 15 (0xf) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: callvirt instance string [mscorlib]System.Object::ToString() + IL_0006: pop + IL_0007: ldarg.1 + IL_0008: callvirt instance int32 [mscorlib]System.String::get_Length() + IL_000d: pop + IL_000e: ret + } // end of method Extensions::M +} // end of class Extensions +""".Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); + + CompileAndVerify( + comp, + emitOptions: EmitOptions.Default.WithEmitMetadataOnly(true).WithIncludePrivateMembers(false), + symbolValidator: (m) => + { + AssertEx.Equal("void Extensions.<>E__0.$(System.Object o)", m.GlobalNamespace.GetMember("Extensions.<>E__0.$").ToTestDisplayString()); + } + ).VerifyDiagnostics(); + } + + [Fact] + public void Implementation_InstanceMethod_02() + { + var src1 = """ +public static class Extensions +{ + extension(object o) + { + public string M(string s) => o + s; + } +} +"""; + var comp1 = CreateCompilation(src1); + + var verifier1 = CompileAndVerify(comp1, sourceSymbolValidator: verifySymbols, symbolValidator: verifySymbols).VerifyDiagnostics(); + + static void verifySymbols(ModuleSymbol m) + { + NamedTypeSymbol extensions = m.ContainingAssembly.GetTypeByMetadataName("Extensions"); + MethodSymbol implementation = extensions.GetMembers().OfType().Single(); + Assert.True(implementation.IsStatic); + Assert.Equal(MethodKind.Ordinary, implementation.MethodKind); + Assert.Equal(2, implementation.ParameterCount); + AssertEx.Equal("System.String Extensions.M(this System.Object o, System.String s)", implementation.ToTestDisplayString()); + Assert.Equal(m is not PEModuleSymbol, implementation.IsImplicitlyDeclared); + Assert.True(implementation.IsExtensionMethod); + Assert.True(implementation.HasSpecialName); + Assert.False(implementation.HasRuntimeSpecialName); + + Assert.True(implementation.ContainingType.MightContainExtensionMethods); + + Assert.Contains("M", extensions.MemberNames); + Assert.NotEmpty(extensions.GetSimpleNonTypeMembers("M")); + + if (m is PEModuleSymbol peModuleSymbol) + { + Assert.True(peModuleSymbol.Module.HasExtensionAttribute(((PEAssemblySymbol)peModuleSymbol.ContainingAssembly).Assembly.Handle, ignoreCase: false)); + } + } + + comp1 = CreateCompilation(src1); + NamedTypeSymbol extensions = comp1.GetTypeByMetadataName("Extensions"); + Assert.Contains("M", extensions.MemberNames); + + comp1 = CreateCompilation(src1); + extensions = comp1.GetTypeByMetadataName("Extensions"); + Assert.NotEmpty(extensions.GetSimpleNonTypeMembers("M")); + + var expectedTypeIL = """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0' + extends [mscorlib]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + object o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x207b + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0'::'$' + .method public hidebysig + instance string M ( + string s + ) cil managed + { + // Method begins at RVA 0x207d + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0'::M + } // end of class <>E__0 + // Methods + .method public hidebysig specialname static + string M ( + object o, + string s + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 19 (0x13) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: brtrue.s IL_0006 + IL_0003: ldnull + IL_0004: br.s IL_000c + IL_0006: ldarg.0 + IL_0007: callvirt instance string [mscorlib]System.Object::ToString() + IL_000c: ldarg.1 + IL_000d: call string [mscorlib]System.String::Concat(string, string) + IL_0012: ret + } // end of method Extensions::M +} // end of class Extensions +"""; + + verifier1.VerifyTypeIL("Extensions", expectedTypeIL.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); + + var src2 = """ +class Program +{ + static void Main() + { + System.Console.Write(Test("1")); + System.Console.Write("3".M2("4")); + } + + static string Test(object o) + { + return o.M("2"); + } +} + +static class Extensions +{ + extension(object o) + { + public string M2(string s) => o.M(s); + } +} +"""; + + var comp1MetadataReference = comp1.ToMetadataReference(); + var comp2 = CreateCompilation(src2, references: [comp1MetadataReference], options: TestOptions.DebugExe); + var verifier2 = CompileAndVerify(comp2, expectedOutput: "1234").VerifyDiagnostics(); + + var testIL = +@" +{ + // Code size 17 (0x11) + .maxstack 2 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldstr ""2"" + IL_0007: call ""string Extensions.M(object, string)"" + IL_000c: stloc.0 + IL_000d: br.s IL_000f + IL_000f: ldloc.0 + IL_0010: ret +} +"; + verifier2.VerifyIL("Program.Test", testIL); + + var m2IL = +@" +{ + // Code size 8 (0x8) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call ""string Extensions.M(object, string)"" + IL_0007: ret +} +"; + verifier2.VerifyIL("Extensions.M2", m2IL); + + var comp1ImageReference = comp1.EmitToImageReference(); + comp2 = CreateCompilation(src2, references: [comp1ImageReference], options: TestOptions.DebugExe); + verifier2 = CompileAndVerify(comp2, expectedOutput: "1234").VerifyDiagnostics(); + + verifier2.VerifyIL("Program.Test", testIL); + verifier2.VerifyIL("Extensions.M2", m2IL); + + comp2 = CreateCompilationWithIL(src2, expectedTypeIL, options: TestOptions.DebugExe); + CompileAndVerify(comp2, expectedOutput: "1234").VerifyDiagnostics(); + + var remove = """ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) +"""; + + comp2 = CreateCompilationWithIL(src2, expectedTypeIL.Remove(expectedTypeIL.IndexOf(remove), remove.Length)); + comp2.VerifyDiagnostics( + // (11,18): error CS1061: 'object' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) + // return o.M("2"); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("object", "M").WithLocation(11, 18), + // (19,41): error CS1061: 'object' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) + // public string M2(string s) => o.M(s); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("object", "M").WithLocation(19, 41) + ); + + src2 = """ +class Program +{ + static void Main() + { + System.Console.Write(Test("1")); + System.Console.Write("3".M2("4")); + } + + static string Test(object o) + { + return Extensions.M(o, "2"); + } +} + +static class Extensions_ +{ + extension(object o) + { + public string M2(string s) => Extensions.M(o, s); + } + + public static void NotUsed(this object o) {} +} +"""; + + comp2 = CreateCompilation(src2, references: [comp1MetadataReference], options: TestOptions.DebugExe); + verifier2 = CompileAndVerify(comp2, expectedOutput: "1234").VerifyDiagnostics(); + + verifier2.VerifyIL("Program.Test", testIL); + verifier2.VerifyIL("Extensions_.M2", m2IL); + + comp2 = CreateCompilation(src2, references: [comp1ImageReference], options: TestOptions.DebugExe); + verifier2 = CompileAndVerify(comp2, expectedOutput: "1234").VerifyDiagnostics(); + + verifier2.VerifyIL("Program.Test", testIL); + verifier2.VerifyIL("Extensions_.M2", m2IL); + + var vbComp = CreateVisualBasicCompilation(""" +Class Program + Shared Sub Main() + System.Console.Write(Test1("1")) + System.Console.Write(Test2("3")) + End Sub + + Shared Function Test1(o As String) As String + return o.M("2") + End Function + Shared Function Test2(o As String) As String + return Extensions.M(o, "4") + End Function +End Class +""", + referencedAssemblies: comp2.References, compilationOptions: new VisualBasicCompilationOptions(OutputKind.ConsoleApplication)); + + CompileAndVerify(vbComp, expectedOutput: "1234").VerifyDiagnostics(); + + if (!CompilationExtensions.EnableVerifyUsedAssemblies) // Tracked by https://github.com/dotnet/roslyn/issues/77542 + { + var src4 = """ +class Program +{ + static void Main() + { + System.Console.Write(Test("1")); + System.Console.Write("3".M2("4")); + } + + static string Test(object o) + { + System.Func d = o.M; + return d("2"); + } +} + +static class Extensions +{ + extension(object o) + { + public string M2(string s) => new System.Func(o.M)(s); + } +} +"""; + + var comp4 = CreateCompilation(src4, references: [comp1MetadataReference], options: TestOptions.DebugExe); + var verifier4 = CompileAndVerify(comp4, expectedOutput: "1234").VerifyDiagnostics(); + + testIL = + @" +{ + // Code size 30 (0x1e) + .maxstack 2 + .locals init (System.Func V_0, //d + string V_1) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldftn ""string Extensions.M(object, string)"" + IL_0008: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_000d: stloc.0 + IL_000e: ldloc.0 + IL_000f: ldstr ""2"" + IL_0014: callvirt ""string System.Func.Invoke(string)"" + IL_0019: stloc.1 + IL_001a: br.s IL_001c + IL_001c: ldloc.1 + IL_001d: ret +} +"; + verifier4.VerifyIL("Program.Test", testIL); + + m2IL = + @" +{ + // Code size 19 (0x13) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldftn ""string Extensions.M(object, string)"" + IL_0007: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_000c: ldarg.1 + IL_000d: callvirt ""string System.Func.Invoke(string)"" + IL_0012: ret +} +"; + verifier4.VerifyIL("Extensions.M2", m2IL); + + comp4 = CreateCompilation(src4, references: [comp1ImageReference], options: TestOptions.DebugExe); + verifier4 = CompileAndVerify(comp4, expectedOutput: "1234").VerifyDiagnostics(); + + verifier4.VerifyIL("Program.Test", testIL); + verifier4.VerifyIL("Extensions.M2", m2IL); + } + + var comp5 = CreateCompilation(src1); + comp5.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_ExtensionAttribute__ctor); + comp5.VerifyDiagnostics( + // (3,5): error CS1110: Cannot define a new extension because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? + // extension(object o) + Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "extension").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(3, 5) + ); + } + + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/77542")] + public void UseSiteInfoTracking_01() + { + var src1 = """ +public static class Extensions +{ + public static string M(this object o, string s) => o + s; +} +"""; + var comp1 = CreateCompilation(src1); + var verifier1 = CompileAndVerify(comp1).VerifyDiagnostics(); + + var src4 = """ +class Program +{ + static string Test(object o) + { + System.Func d = o.M; + return d("2"); + } +} +"""; + + var comp1MetadataReference = comp1.ToMetadataReference(); + var comp4 = CreateCompilation(src4, references: [comp1MetadataReference]); + comp4.VerifyEmitDiagnostics(); + var refs = comp4.GetUsedAssemblyReferences(); + Assert.Contains(comp1MetadataReference, refs); + } + + [Fact] + public void UseSiteInfoTracking_02() + { + var src1 = """ +public static class Extensions +{ + public static string M(this object o, string s) => o + s; +} +"""; + var comp1 = CreateCompilation(src1); + var verifier1 = CompileAndVerify(comp1).VerifyDiagnostics(); + + var src4 = """ +class Program +{ + static string Test(object o) + { + return o.M("2"); + } +} +"""; + + var comp1MetadataReference = comp1.ToMetadataReference(); + var comp4 = CreateCompilation(src4, references: [comp1MetadataReference]); + comp4.VerifyEmitDiagnostics(); + var refs = comp4.GetUsedAssemblyReferences(); + Assert.Contains(comp1MetadataReference, refs); + } + + [Fact] + public void Implementation_InstanceMethod_03_WithLocalFunction() + { + var src1 = """ +public static class Extensions +{ + extension(object o) + { + public string M(string s) + { + string local() => o + s; + return local(); + } + } +} +"""; + var comp1 = CreateCompilation(src1); + var verifier1 = CompileAndVerify(comp1).VerifyDiagnostics(); + + verifier1.VerifyTypeIL("Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0' + extends [mscorlib]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + object o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x20ab + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0'::'$' + .method public hidebysig + instance string M ( + string s + ) cil managed + { + // Method begins at RVA 0x20ad + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0'::M + } // end of class <>E__0 + .class nested private auto ansi sealed beforefieldinit '<>c__DisplayClass1_0' + extends [mscorlib]System.ValueType + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field public object o + .field public string s + } // end of class <>c__DisplayClass1_0 + // Methods + .method public hidebysig specialname static + string M ( + object o, + string s + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2068 + // Code size 24 (0x18) + .maxstack 2 + .locals init ( + [0] valuetype Extensions/'<>c__DisplayClass1_0' + ) + IL_0000: ldloca.s 0 + IL_0002: ldarg.0 + IL_0003: stfld object Extensions/'<>c__DisplayClass1_0'::o + IL_0008: ldloca.s 0 + IL_000a: ldarg.1 + IL_000b: stfld string Extensions/'<>c__DisplayClass1_0'::s + IL_0010: ldloca.s 0 + IL_0012: call string Extensions::'b__1_0'(valuetype Extensions/'<>c__DisplayClass1_0'&) + IL_0017: ret + } // end of method Extensions::M + .method assembly hidebysig static + string 'b__1_0' ( + valuetype Extensions/'<>c__DisplayClass1_0'& '' + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x208c + // Code size 30 (0x1e) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld object Extensions/'<>c__DisplayClass1_0'::o + IL_0006: dup + IL_0007: brtrue.s IL_000d + IL_0009: pop + IL_000a: ldnull + IL_000b: br.s IL_0012 + IL_000d: callvirt instance string [mscorlib]System.Object::ToString() + IL_0012: ldarg.0 + IL_0013: ldfld string Extensions/'<>c__DisplayClass1_0'::s + IL_0018: call string [mscorlib]System.String::Concat(string, string) + IL_001d: ret + } // end of method Extensions::'b__1_0' +} // end of class Extensions +""".Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); + + var src2 = """ +public static class Extensions +{ + extension(object o) + { + string M(string s) + { + string local() => o + s; + return local(); + } + } + + extension(object o) + { + string M(string s, int x) + { + string local() => o + s; + return local(); + } + } +} +"""; + var comp2 = CreateCompilation(src2); + CompileAndVerify(comp2).VerifyDiagnostics(); + + var src3 = """ +class Program +{ + static void Main() + { + System.Console.Write(Test("1")); + System.Console.Write("3".M2("4")); + } + + static string Test(object o) + { + string local() => o.M("2"); + return local(); + } +} + +static class Extensions +{ + extension(object o) + { + public string M2(string s) + { + string local() => o.M(s); + return local(); + } + } +} +"""; + + var comp3 = CreateCompilation(src3, references: [comp1.ToMetadataReference()], options: TestOptions.DebugExe); + CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); + + comp3 = CreateCompilation(src3, references: [comp1.EmitToImageReference()], options: TestOptions.DebugExe); + CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); + } + + [Fact] + public void Implementation_InstanceMethod_04_WithLambda() + { + var src1 = """ +public static class Extensions +{ + extension(object o) + { + public string M(string s) + { + System.Func local = () => o + s; + return local(); + } + } +} +"""; + var comp1 = CreateCompilation(src1); + var verifier1 = CompileAndVerify(comp1).VerifyDiagnostics(); + + verifier1.VerifyTypeIL("Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0' + extends [mscorlib]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + object o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x208c + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0'::'$' + .method public hidebysig + instance string M ( + string s + ) cil managed + { + // Method begins at RVA 0x208e + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0'::M + } // end of class <>E__0 + .class nested private auto ansi sealed beforefieldinit '<>c__DisplayClass1_0' + extends [mscorlib]System.Object + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field public object o + .field public string s + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x2091 + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method '<>c__DisplayClass1_0'::.ctor + .method assembly hidebysig + instance string 'b__0' () cil managed + { + // Method begins at RVA 0x2099 + // Code size 30 (0x1e) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld object Extensions/'<>c__DisplayClass1_0'::o + IL_0006: dup + IL_0007: brtrue.s IL_000d + IL_0009: pop + IL_000a: ldnull + IL_000b: br.s IL_0012 + IL_000d: callvirt instance string [mscorlib]System.Object::ToString() + IL_0012: ldarg.0 + IL_0013: ldfld string Extensions/'<>c__DisplayClass1_0'::s + IL_0018: call string [mscorlib]System.String::Concat(string, string) + IL_001d: ret + } // end of method '<>c__DisplayClass1_0'::'b__0' + } // end of class <>c__DisplayClass1_0 + // Methods + .method public hidebysig specialname static + string M ( + object o, + string s + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 36 (0x24) + .maxstack 8 + IL_0000: newobj instance void Extensions/'<>c__DisplayClass1_0'::.ctor() + IL_0005: dup + IL_0006: ldarg.0 + IL_0007: stfld object Extensions/'<>c__DisplayClass1_0'::o + IL_000c: dup + IL_000d: ldarg.1 + IL_000e: stfld string Extensions/'<>c__DisplayClass1_0'::s + IL_0013: ldftn instance string Extensions/'<>c__DisplayClass1_0'::'b__0'() + IL_0019: newobj instance void class [mscorlib]System.Func`1::.ctor(object, native int) + IL_001e: callvirt instance !0 class [mscorlib]System.Func`1::Invoke() + IL_0023: ret + } // end of method Extensions::M +} // end of class Extensions +""".Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); + + var src2 = """ +public static class Extensions +{ + extension(object o) + { + string M(string s) + { + System.Func local = () => o + s; + return local(); + } + } + + extension(object o) + { + string M(string s, int x) + { + System.Func local = () => o + s; + return local(); + } + } +} +"""; + var comp2 = CreateCompilation(src2); + CompileAndVerify(comp2).VerifyDiagnostics(); + + var src3 = """ +class Program +{ + static void Main() + { + System.Console.Write(Test("1")); + System.Console.Write("3".M2("4")); + } + + static string Test(object o) + { + System.Func local = () => o.M("2"); + return local(); + } +} + +static class Extensions +{ + extension(object o) + { + public string M2(string s) + { + System.Func local = () => o.M(s); + return local(); + } + } +} +"""; + + var comp3 = CreateCompilation(src3, references: [comp1.ToMetadataReference()], options: TestOptions.DebugExe); + CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); + + comp3 = CreateCompilation(src3, references: [comp1.EmitToImageReference()], options: TestOptions.DebugExe); + CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); + } + + [Fact] + public void Implementation_InstanceMethod_05_Iterator() + { + var src1 = """ +public static class Extensions +{ + extension(object o) + { + public System.Collections.Generic.IEnumerable M(string s) + { + yield return o + s; + } + } +} +"""; + var comp1 = CreateCompilation(src1); + var verifier1 = CompileAndVerify(comp1, symbolValidator: (m) => + { + MethodSymbol implementation = m.ContainingAssembly.GetTypeByMetadataName("Extensions").GetMembers().OfType().Single(); + AssertEx.Equal("System.Runtime.CompilerServices.IteratorStateMachineAttribute(typeof(Extensions.d__1))", implementation.GetAttributes().Single().ToString()); + }).VerifyDiagnostics(); + + verifier1.VerifyTypeIL("Extensions", (""" +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0' + extends [mscorlib]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + object o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x207e + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0'::'$' + .method public hidebysig + instance class [mscorlib]System.Collections.Generic.IEnumerable`1 M ( + string s + ) cil managed + { + // Method begins at RVA 0x2080 + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0'::M + } // end of class <>E__0 + .class nested private auto ansi sealed beforefieldinit 'd__1' + extends [mscorlib]System.Object + implements class [mscorlib]System.Collections.Generic.IEnumerable`1, + [mscorlib]System.Collections.IEnumerable, + class [mscorlib]System.Collections.Generic.IEnumerator`1, + +""" + + (ExecutionConditionUtil.IsMonoOrCoreClr ? +""" + [mscorlib]System.Collections.IEnumerator, + [mscorlib]System.IDisposable + +""" : +""" + [mscorlib]System.IDisposable, + [mscorlib]System.Collections.IEnumerator + +""") + +""" + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field private int32 '<>1__state' + .field private string '<>2__current' + .field private int32 '<>l__initialThreadId' + .field private object o + .field public object '<>3__o' + .field private string s + .field public string '<>3__s' + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor ( + int32 '<>1__state' + ) cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2083 + // Code size 25 (0x19) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: stfld int32 Extensions/'d__1'::'<>1__state' + IL_000d: ldarg.0 + IL_000e: call int32 [mscorlib]System.Environment::get_CurrentManagedThreadId() + IL_0013: stfld int32 Extensions/'d__1'::'<>l__initialThreadId' + IL_0018: ret + } // end of method 'd__1'::.ctor + .method private final hidebysig newslot virtual + instance void System.IDisposable.Dispose () cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance void [mscorlib]System.IDisposable::Dispose() + // Method begins at RVA 0x209d + // Code size 9 (0x9) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.s -2 + IL_0003: stfld int32 Extensions/'d__1'::'<>1__state' + IL_0008: ret + } // end of method 'd__1'::System.IDisposable.Dispose + .method private final hidebysig newslot virtual + instance bool MoveNext () cil managed + { + .override method instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() + // Method begins at RVA 0x20a8 + // Code size 76 (0x4c) + .maxstack 3 + .locals init ( + [0] int32 + ) + IL_0000: ldarg.0 + IL_0001: ldfld int32 Extensions/'d__1'::'<>1__state' + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_0010 + IL_000a: ldloc.0 + IL_000b: ldc.i4.1 + IL_000c: beq.s IL_0043 + IL_000e: ldc.i4.0 + IL_000f: ret + IL_0010: ldarg.0 + IL_0011: ldc.i4.m1 + IL_0012: stfld int32 Extensions/'d__1'::'<>1__state' + IL_0017: ldarg.0 + IL_0018: ldarg.0 + IL_0019: ldfld object Extensions/'d__1'::o + IL_001e: dup + IL_001f: brtrue.s IL_0025 + IL_0021: pop + IL_0022: ldnull + IL_0023: br.s IL_002a + IL_0025: callvirt instance string [mscorlib]System.Object::ToString() + IL_002a: ldarg.0 + IL_002b: ldfld string Extensions/'d__1'::s + IL_0030: call string [mscorlib]System.String::Concat(string, string) + IL_0035: stfld string Extensions/'d__1'::'<>2__current' + IL_003a: ldarg.0 + IL_003b: ldc.i4.1 + IL_003c: stfld int32 Extensions/'d__1'::'<>1__state' + IL_0041: ldc.i4.1 + IL_0042: ret + IL_0043: ldarg.0 + IL_0044: ldc.i4.m1 + IL_0045: stfld int32 Extensions/'d__1'::'<>1__state' + IL_004a: ldc.i4.0 + IL_004b: ret + } // end of method 'd__1'::MoveNext + .method private final hidebysig specialname newslot virtual + instance string 'System.Collections.Generic.IEnumerator.get_Current' () cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1::get_Current() + // Method begins at RVA 0x2100 + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld string Extensions/'d__1'::'<>2__current' + IL_0006: ret + } // end of method 'd__1'::'System.Collections.Generic.IEnumerator.get_Current' + .method private final hidebysig newslot virtual + instance void System.Collections.IEnumerator.Reset () cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance void [mscorlib]System.Collections.IEnumerator::Reset() + // Method begins at RVA 0x2108 + // Code size 6 (0x6) + .maxstack 8 + IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() + IL_0005: throw + } // end of method 'd__1'::System.Collections.IEnumerator.Reset + .method private final hidebysig specialname newslot virtual + instance object System.Collections.IEnumerator.get_Current () cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance object [mscorlib]System.Collections.IEnumerator::get_Current() + // Method begins at RVA 0x2100 + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld string Extensions/'d__1'::'<>2__current' + IL_0006: ret + } // end of method 'd__1'::System.Collections.IEnumerator.get_Current + .method private final hidebysig newslot virtual + instance class [mscorlib]System.Collections.Generic.IEnumerator`1 'System.Collections.Generic.IEnumerable.GetEnumerator' () cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance class [mscorlib]System.Collections.Generic.IEnumerator`1 class [mscorlib]System.Collections.Generic.IEnumerable`1::GetEnumerator() + // Method begins at RVA 0x2110 + // Code size 67 (0x43) + .maxstack 2 + .locals init ( + [0] class Extensions/'d__1' + ) + IL_0000: ldarg.0 + IL_0001: ldfld int32 Extensions/'d__1'::'<>1__state' + IL_0006: ldc.i4.s -2 + IL_0008: bne.un.s IL_0022 + IL_000a: ldarg.0 + IL_000b: ldfld int32 Extensions/'d__1'::'<>l__initialThreadId' + IL_0010: call int32 [mscorlib]System.Environment::get_CurrentManagedThreadId() + IL_0015: bne.un.s IL_0022 + IL_0017: ldarg.0 + IL_0018: ldc.i4.0 + IL_0019: stfld int32 Extensions/'d__1'::'<>1__state' + IL_001e: ldarg.0 + IL_001f: stloc.0 + IL_0020: br.s IL_0029 + IL_0022: ldc.i4.0 + IL_0023: newobj instance void Extensions/'d__1'::.ctor(int32) + IL_0028: stloc.0 + IL_0029: ldloc.0 + IL_002a: ldarg.0 + IL_002b: ldfld object Extensions/'d__1'::'<>3__o' + IL_0030: stfld object Extensions/'d__1'::o + IL_0035: ldloc.0 + IL_0036: ldarg.0 + IL_0037: ldfld string Extensions/'d__1'::'<>3__s' + IL_003c: stfld string Extensions/'d__1'::s + IL_0041: ldloc.0 + IL_0042: ret + } // end of method 'd__1'::'System.Collections.Generic.IEnumerable.GetEnumerator' + .method private final hidebysig newslot virtual + instance class [mscorlib]System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.IEnumerable::GetEnumerator() + // Method begins at RVA 0x215f + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance class [mscorlib]System.Collections.Generic.IEnumerator`1 Extensions/'d__1'::'System.Collections.Generic.IEnumerable.GetEnumerator'() + IL_0006: ret + } // end of method 'd__1'::System.Collections.IEnumerable.GetEnumerator + // Properties + .property instance string 'System.Collections.Generic.IEnumerator.Current'() + { + .get instance string Extensions/'d__1'::'System.Collections.Generic.IEnumerator.get_Current'() + } + .property instance object System.Collections.IEnumerator.Current() + { + .get instance object Extensions/'d__1'::System.Collections.IEnumerator.get_Current() + } + } // end of class d__1 + // Methods + .method public hidebysig specialname static + class [mscorlib]System.Collections.Generic.IEnumerable`1 M ( + object o, + string s + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.IteratorStateMachineAttribute::.ctor(class [mscorlib]System.Type) = ( + 01 00 12 45 78 74 65 6e 73 69 6f 6e 73 2b 3c 4d + 3e 64 5f 5f 31 00 00 + ) + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 22 (0x16) + .maxstack 8 + IL_0000: ldc.i4.s -2 + IL_0002: newobj instance void Extensions/'d__1'::.ctor(int32) + IL_0007: dup + IL_0008: ldarg.0 + IL_0009: stfld object Extensions/'d__1'::'<>3__o' + IL_000e: dup + IL_000f: ldarg.1 + IL_0010: stfld string Extensions/'d__1'::'<>3__s' + IL_0015: ret + } // end of method Extensions::M +} // end of class Extensions +""").Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); + + var src2 = """ +public static class Extensions +{ + extension(object o) + { + System.Collections.Generic.IEnumerable M(string s) + { + yield return o + s; + } + } + + extension(object o) + { + System.Collections.Generic.IEnumerable M(string s, int x) + { + yield return o + s; + } + } +} +"""; + var comp2 = CreateCompilation(src2); + CompileAndVerify(comp2).VerifyDiagnostics(); + + var src3 = """ +class Program +{ + static void Main() + { + foreach (var s in Test("1")) + System.Console.Write(s); + foreach (var s in "3".M2("4")) + System.Console.Write(s); + } + + static System.Collections.Generic.IEnumerable Test(object o) + { + return o.M("2"); + } +} + +static class Extensions +{ + extension(object o) + { + public System.Collections.Generic.IEnumerable M2(string s) => o.M(s); + } +} +"""; + + var comp3 = CreateCompilation(src3, references: [comp1.ToMetadataReference()], options: TestOptions.DebugExe); + var verifier3 = CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); + + var testIL = +@" +{ + // Code size 17 (0x11) + .maxstack 2 + .locals init (System.Collections.Generic.IEnumerable V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldstr ""2"" + IL_0007: call ""System.Collections.Generic.IEnumerable Extensions.M(object, string)"" + IL_000c: stloc.0 + IL_000d: br.s IL_000f + IL_000f: ldloc.0 + IL_0010: ret +} +"; + verifier3.VerifyIL("Program.Test", testIL); + + var m2IL = +@" +{ + // Code size 8 (0x8) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call ""System.Collections.Generic.IEnumerable Extensions.M(object, string)"" + IL_0007: ret +} +"; + verifier3.VerifyIL("Extensions.M2", m2IL); + + comp3 = CreateCompilation(src3, references: [comp1.EmitToImageReference()], options: TestOptions.DebugExe); + verifier3 = CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); + + verifier3.VerifyIL("Program.Test", testIL); + verifier3.VerifyIL("Extensions.M2", m2IL); + } + + [Fact] + public void Implementation_InstanceMethod_06_Async() + { + var src1 = """ +public static class Extensions +{ + extension(object o) + { + public async System.Threading.Tasks.Task M(string s) + { + await System.Threading.Tasks.Task.Yield(); + return o + s; + } + } +} +"""; + var comp1 = CreateCompilation(src1); + var verifier1 = CompileAndVerify(comp1, symbolValidator: (m) => + { + MethodSymbol implementation = m.ContainingAssembly.GetTypeByMetadataName("Extensions").GetMembers().OfType().Single(); + AssertEx.Equal("System.Runtime.CompilerServices.AsyncStateMachineAttribute(typeof(Extensions.d__1))", implementation.GetAttributes().Single().ToString()); + }).VerifyDiagnostics(); + + verifier1.VerifyTypeIL("Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0' + extends [mscorlib]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + object o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x20b3 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0'::'$' + .method public hidebysig + instance class [mscorlib]System.Threading.Tasks.Task`1 M ( + string s + ) cil managed + { + // Method begins at RVA 0x20b5 + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0'::M + } // end of class <>E__0 + .class nested private auto ansi sealed beforefieldinit 'd__1' + extends [mscorlib]System.ValueType + implements [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field public int32 '<>1__state' + .field public valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 '<>t__builder' + .field public object o + .field public string s + .field private valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter '<>u__1' + // Methods + .method private final hidebysig newslot virtual + instance void MoveNext () cil managed + { + .override method instance void [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine::MoveNext() + // Method begins at RVA 0x20b8 + // Code size 178 (0xb2) + .maxstack 3 + .locals init ( + [0] int32, + [1] string, + [2] valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter, + [3] valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable, + [4] class [mscorlib]System.Exception + ) + IL_0000: ldarg.0 + IL_0001: ldfld int32 Extensions/'d__1'::'<>1__state' + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_0041 + IL_000a: call valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable [mscorlib]System.Threading.Tasks.Task::Yield() + IL_000f: stloc.3 + IL_0010: ldloca.s 3 + IL_0012: call instance valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter [mscorlib]System.Runtime.CompilerServices.YieldAwaitable::GetAwaiter() + IL_0017: stloc.2 + IL_0018: ldloca.s 2 + IL_001a: call instance bool [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter::get_IsCompleted() + IL_001f: brtrue.s IL_005d + IL_0021: ldarg.0 + IL_0022: ldc.i4.0 + IL_0023: dup + IL_0024: stloc.0 + IL_0025: stfld int32 Extensions/'d__1'::'<>1__state' + IL_002a: ldarg.0 + IL_002b: ldloc.2 + IL_002c: stfld valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter Extensions/'d__1'::'<>u__1' + IL_0031: ldarg.0 + IL_0032: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 Extensions/'d__1'::'<>t__builder' + IL_0037: ldloca.s 2 + IL_0039: ldarg.0 + IL_003a: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::AwaitUnsafeOnCompletedd__1'>(!!0&, !!1&) + IL_003f: leave.s IL_00b1 + IL_0041: ldarg.0 + IL_0042: ldfld valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter Extensions/'d__1'::'<>u__1' + IL_0047: stloc.2 + IL_0048: ldarg.0 + IL_0049: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter Extensions/'d__1'::'<>u__1' + IL_004e: initobj [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter + IL_0054: ldarg.0 + IL_0055: ldc.i4.m1 + IL_0056: dup + IL_0057: stloc.0 + IL_0058: stfld int32 Extensions/'d__1'::'<>1__state' + IL_005d: ldloca.s 2 + IL_005f: call instance void [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter::GetResult() + IL_0064: ldarg.0 + IL_0065: ldfld object Extensions/'d__1'::o + IL_006a: dup + IL_006b: brtrue.s IL_0071 + IL_006d: pop + IL_006e: ldnull + IL_006f: br.s IL_0076 + IL_0071: callvirt instance string [mscorlib]System.Object::ToString() + IL_0076: ldarg.0 + IL_0077: ldfld string Extensions/'d__1'::s + IL_007c: call string [mscorlib]System.String::Concat(string, string) + IL_0081: stloc.1 + IL_0082: leave.s IL_009d + } // end .try + catch [mscorlib]System.Exception + { + IL_0084: stloc.s 4 + IL_0086: ldarg.0 + IL_0087: ldc.i4.s -2 + IL_0089: stfld int32 Extensions/'d__1'::'<>1__state' + IL_008e: ldarg.0 + IL_008f: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 Extensions/'d__1'::'<>t__builder' + IL_0094: ldloc.s 4 + IL_0096: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetException(class [mscorlib]System.Exception) + IL_009b: leave.s IL_00b1 + } // end handler + IL_009d: ldarg.0 + IL_009e: ldc.i4.s -2 + IL_00a0: stfld int32 Extensions/'d__1'::'<>1__state' + IL_00a5: ldarg.0 + IL_00a6: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 Extensions/'d__1'::'<>t__builder' + IL_00ab: ldloc.1 + IL_00ac: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetResult(!0) + IL_00b1: ret + } // end of method 'd__1'::MoveNext + .method private final hidebysig newslot virtual + instance void SetStateMachine ( + class [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine stateMachine + ) cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance void [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine::SetStateMachine(class [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine) + // Method begins at RVA 0x2188 + // Code size 13 (0xd) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 Extensions/'d__1'::'<>t__builder' + IL_0006: ldarg.1 + IL_0007: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetStateMachine(class [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine) + IL_000c: ret + } // end of method 'd__1'::SetStateMachine + } // end of class d__1 + // Methods + .method public hidebysig specialname static + class [mscorlib]System.Threading.Tasks.Task`1 M ( + object o, + string s + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.AsyncStateMachineAttribute::.ctor(class [mscorlib]System.Type) = ( + 01 00 12 45 78 74 65 6e 73 69 6f 6e 73 2b 3c 4d + 3e 64 5f 5f 31 00 00 + ) + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2068 + // Code size 63 (0x3f) + .maxstack 2 + .locals init ( + [0] valuetype Extensions/'d__1' + ) + IL_0000: ldloca.s 0 + IL_0002: call valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::Create() + IL_0007: stfld valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 Extensions/'d__1'::'<>t__builder' + IL_000c: ldloca.s 0 + IL_000e: ldarg.0 + IL_000f: stfld object Extensions/'d__1'::o + IL_0014: ldloca.s 0 + IL_0016: ldarg.1 + IL_0017: stfld string Extensions/'d__1'::s + IL_001c: ldloca.s 0 + IL_001e: ldc.i4.m1 + IL_001f: stfld int32 Extensions/'d__1'::'<>1__state' + IL_0024: ldloca.s 0 + IL_0026: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 Extensions/'d__1'::'<>t__builder' + IL_002b: ldloca.s 0 + IL_002d: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::Startd__1'>(!!0&) + IL_0032: ldloca.s 0 + IL_0034: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 Extensions/'d__1'::'<>t__builder' + IL_0039: call instance class [mscorlib]System.Threading.Tasks.Task`1 valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::get_Task() + IL_003e: ret + } // end of method Extensions::M +} // end of class Extensions +""".Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); + + var src2 = """ +public static class Extensions +{ + extension(object o) + { + async System.Threading.Tasks.Task M(string s) + { + await System.Threading.Tasks.Task.Yield(); + return o + s; + } + } + + extension(object o) + { + async System.Threading.Tasks.Task M(string s, int x) + { + await System.Threading.Tasks.Task.Yield(); + return o + s; + } + } +} +"""; + var comp2 = CreateCompilation(src2); + CompileAndVerify(comp2).VerifyDiagnostics(); + + var src3 = """ +class Program +{ + static void Main() + { + System.Console.Write(Test("1").Result); + System.Console.Write("3".M2("4").Result); + } + + async static System.Threading.Tasks.Task Test(object o) + { + await System.Threading.Tasks.Task.Yield(); + return await o.M("2"); + } +} + +static class Extensions +{ + extension(object o) + { + async public System.Threading.Tasks.Task M2(string s) + { + await System.Threading.Tasks.Task.Yield(); + return await o.M(s); + } + } +} +"""; + + var comp3 = CreateCompilation(src3, references: [comp1.ToMetadataReference()], options: TestOptions.DebugExe); + CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); + + comp3 = CreateCompilation(src3, references: [comp1.EmitToImageReference()], options: TestOptions.DebugExe); + CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); + } + + [Fact] + public void Implementation_InstanceMethod_07_Generic() + { + var src1 = """ +public static class Extensions +{ + extension(C o) + { + public string M(T t, U u) + { + return o.GetString() + u.ToString() + t.ToString(); + } + } +} + +public class C(string v) +{ + public string GetString() => v; +} +"""; + var comp1 = CreateCompilation(src1); + + MethodSymbol implementation = comp1.GetTypeByMetadataName("Extensions").GetMembers().OfType().Single(); + Assert.True(implementation.IsStatic); + Assert.Equal(MethodKind.Ordinary, implementation.MethodKind); + Assert.Equal(3, implementation.ParameterCount); + AssertEx.Equal("System.String Extensions.M(this C o, T t, U u)", implementation.ToTestDisplayString()); + Assert.True(implementation.IsImplicitlyDeclared); + Assert.True(implementation.IsExtensionMethod); + Assert.True(implementation.HasSpecialName); + Assert.False(implementation.HasRuntimeSpecialName); + + var verifier1 = CompileAndVerify(comp1).VerifyDiagnostics(); + + verifier1.VerifyTypeIL("Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0`1' + extends [mscorlib]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + class C`1 o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x20a5 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0`1'::'$' + .method public hidebysig + instance string M ( + !T t, + !!U u + ) cil managed + { + // Method begins at RVA 0x20a7 + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0`1'::M + } // end of class <>E__0`1 + // Methods + .method public hidebysig specialname static + string M ( + class C`1 o, + !!T t, + !!U u + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 38 (0x26) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: callvirt instance string class C`1::GetString() + IL_0006: ldarga.s u + IL_0008: constrained. !!U + IL_000e: callvirt instance string [mscorlib]System.Object::ToString() + IL_0013: ldarga.s t + IL_0015: constrained. !!T + IL_001b: callvirt instance string [mscorlib]System.Object::ToString() + IL_0020: call string [mscorlib]System.String::Concat(string, string, string) + IL_0025: ret + } // end of method Extensions::M +} // end of class Extensions +""".Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); + + var src3 = """ +class Program +{ + static void Main() + { + System.Console.Write(Test(new C("1"), "2", 3)); + System.Console.Write(new C("4").M2("5", 6)); + } + + static string Test(C o, T t, U u) + { + return o.M(t, u); + } +} + +static class Extensions +{ + extension(C o) + { + public string M2(T t, U u) => o.M(t, u); + } +} +"""; + + var comp1MetadataReference = comp1.ToMetadataReference(); + var comp3 = CreateCompilation(src3, references: [comp1MetadataReference], options: TestOptions.DebugExe); + var verifier3 = CompileAndVerify(comp3, expectedOutput: "132465").VerifyDiagnostics(); + + var testIL = +@" +{ + // Code size 14 (0xe) + .maxstack 3 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldarg.1 + IL_0003: ldarg.2 + IL_0004: call ""string Extensions.M(C, T, U)"" + IL_0009: stloc.0 + IL_000a: br.s IL_000c + IL_000c: ldloc.0 + IL_000d: ret +} +"; + verifier3.VerifyIL("Program.Test(C, T, U)", testIL); + + var m2IL = +@" +{ + // Code size 9 (0x9) + .maxstack 3 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: ldarg.2 + IL_0003: call ""string Extensions.M(C, T, U)"" + IL_0008: ret +} +"; + verifier3.VerifyIL("Extensions.M2(this C, T, U)", m2IL); + + var comp1ImageReference = comp1.EmitToImageReference(); + comp3 = CreateCompilation(src3, references: [comp1ImageReference], options: TestOptions.DebugExe); + verifier3 = CompileAndVerify(comp3, expectedOutput: "132465").VerifyDiagnostics(); + + verifier3.VerifyIL("Program.Test(C, T, U)", testIL); + verifier3.VerifyIL("Extensions.M2(this C, T, U)", m2IL); + + if (!CompilationExtensions.EnableVerifyUsedAssemblies) // Tracked by https://github.com/dotnet/roslyn/issues/77542 + { + src3 = """ +class Program +{ + static void Main() + { + System.Console.Write(Test(new C("1"), "2", 3)); + System.Console.Write(new C("4").M2("5", 6)); + } + + static string Test(C o, T t, U u) + { + System.Func d = o.M; + return d(t, u); + } +} + +static class Extensions +{ + extension(C o) + { + public string M2(T t, U u) => new System.Func(o.M)(t, u); + } +} +"""; + + comp3 = CreateCompilation(src3, references: [comp1MetadataReference], options: TestOptions.DebugExe); + verifier3 = CompileAndVerify(comp3, expectedOutput: "132465").VerifyDiagnostics(); + + testIL = +@" +{ + // Code size 27 (0x1b) + .maxstack 3 + .locals init (System.Func V_0, //d + string V_1) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldftn ""string Extensions.M(C, T, U)"" + IL_0008: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_000d: stloc.0 + IL_000e: ldloc.0 + IL_000f: ldarg.1 + IL_0010: ldarg.2 + IL_0011: callvirt ""string System.Func.Invoke(T, U)"" + IL_0016: stloc.1 + IL_0017: br.s IL_0019 + IL_0019: ldloc.1 + IL_001a: ret +} +"; + verifier3.VerifyIL("Program.Test(C, T, U)", testIL); + + m2IL = +@" +{ + // Code size 20 (0x14) + .maxstack 3 + IL_0000: ldarg.0 + IL_0001: ldftn ""string Extensions.M(C, T, U)"" + IL_0007: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_000c: ldarg.1 + IL_000d: ldarg.2 + IL_000e: callvirt ""string System.Func.Invoke(T, U)"" + IL_0013: ret +} +"; + verifier3.VerifyIL("Extensions.M2(this C, T, U)", m2IL); + + comp3 = CreateCompilation(src3, references: [comp1ImageReference], options: TestOptions.DebugExe); + + verifier3 = CompileAndVerify(comp3, expectedOutput: "132465").VerifyDiagnostics(); + + verifier3.VerifyIL("Program.Test(C, T, U)", testIL); + verifier3.VerifyIL("Extensions.M2(this C, T, U)", m2IL); + } + } + + [Fact] + public void Implementation_InstanceMethod_08_WithLocalFunction_Generic() + { + var src1 = """ +public static class Extensions +{ + extension(C o) + { + public C M(T t1, U u1) + { + C local(T t2, U u2, X x2, Y y2, Z z2) + { + return new C(o.GetString() + u1.ToString() + t1.ToString() + u2.ToString() + t2.ToString() + x2.ToString() + y2.ToString() + z2.ToString()); + }; + + return local(t1, u1, 0, t1, u1); + } + } +} + +public class C(string val) +{ + public string GetString() => val; +} +"""; + var comp1 = CreateCompilation(src1); + var verifier1 = CompileAndVerify(comp1).VerifyDiagnostics(); + + verifier1.VerifyTypeIL("Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0`1' + extends [mscorlib]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + class C`1 o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x216d + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0`1'::'$' + .method public hidebysig + instance class C`1 M ( + !T t1, + !!U u1 + ) cil managed + { + // Method begins at RVA 0x216f + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0`1'::M + } // end of class <>E__0`1 + .class nested private auto ansi sealed beforefieldinit '<>c__DisplayClass1_0`2' + extends [mscorlib]System.ValueType + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field public class C`1 o + .field public !U u1 + .field public !T t1 + } // end of class <>c__DisplayClass1_0`2 + // Methods + .method public hidebysig specialname static + class C`1 M ( + class C`1 o, + !!T t1, + !!U u1 + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2068 + // Code size 57 (0x39) + .maxstack 6 + .locals init ( + [0] valuetype Extensions/'<>c__DisplayClass1_0`2' + ) + IL_0000: ldloca.s 0 + IL_0002: ldarg.0 + IL_0003: stfld class C`1 valuetype Extensions/'<>c__DisplayClass1_0`2'::o + IL_0008: ldloca.s 0 + IL_000a: ldarg.2 + IL_000b: stfld !1 valuetype Extensions/'<>c__DisplayClass1_0`2'::u1 + IL_0010: ldloca.s 0 + IL_0012: ldarg.1 + IL_0013: stfld !0 valuetype Extensions/'<>c__DisplayClass1_0`2'::t1 + IL_0018: ldloc.0 + IL_0019: ldfld !0 valuetype Extensions/'<>c__DisplayClass1_0`2'::t1 + IL_001e: ldloc.0 + IL_001f: ldfld !1 valuetype Extensions/'<>c__DisplayClass1_0`2'::u1 + IL_0024: ldc.i4.0 + IL_0025: ldloc.0 + IL_0026: ldfld !0 valuetype Extensions/'<>c__DisplayClass1_0`2'::t1 + IL_002b: ldloc.0 + IL_002c: ldfld !1 valuetype Extensions/'<>c__DisplayClass1_0`2'::u1 + IL_0031: ldloca.s 0 + IL_0033: call class C`1 Extensions::'b__1_0'(!!0, !!1, !!2, !!3, !!4, valuetype Extensions/'<>c__DisplayClass1_0`2'&) + IL_0038: ret + } // end of method Extensions::M + .method assembly hidebysig static + class C`1 'b__1_0' ( + !!T t2, + !!U u2, + !!X x2, + !!Y y2, + !!Z z2, + valuetype Extensions/'<>c__DisplayClass1_0`2'& '' + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x20b0 + // Code size 154 (0x9a) + .maxstack 4 + IL_0000: ldc.i4.8 + IL_0001: newarr [mscorlib]System.String + IL_0006: dup + IL_0007: ldc.i4.0 + IL_0008: ldarg.s 5 + IL_000a: ldfld class C`1 valuetype Extensions/'<>c__DisplayClass1_0`2'::o + IL_000f: callvirt instance string class C`1::GetString() + IL_0014: stelem.ref + IL_0015: dup + IL_0016: ldc.i4.1 + IL_0017: ldarg.s 5 + IL_0019: ldflda !1 valuetype Extensions/'<>c__DisplayClass1_0`2'::u1 + IL_001e: constrained. !!U + IL_0024: callvirt instance string [mscorlib]System.Object::ToString() + IL_0029: stelem.ref + IL_002a: dup + IL_002b: ldc.i4.2 + IL_002c: ldarg.s 5 + IL_002e: ldflda !0 valuetype Extensions/'<>c__DisplayClass1_0`2'::t1 + IL_0033: constrained. !!T + IL_0039: callvirt instance string [mscorlib]System.Object::ToString() + IL_003e: stelem.ref + IL_003f: dup + IL_0040: ldc.i4.3 + IL_0041: ldarga.s u2 + IL_0043: constrained. !!U + IL_0049: callvirt instance string [mscorlib]System.Object::ToString() + IL_004e: stelem.ref + IL_004f: dup + IL_0050: ldc.i4.4 + IL_0051: ldarga.s t2 + IL_0053: constrained. !!T + IL_0059: callvirt instance string [mscorlib]System.Object::ToString() + IL_005e: stelem.ref + IL_005f: dup + IL_0060: ldc.i4.5 + IL_0061: ldarga.s x2 + IL_0063: constrained. !!X + IL_0069: callvirt instance string [mscorlib]System.Object::ToString() + IL_006e: stelem.ref + IL_006f: dup + IL_0070: ldc.i4.6 + IL_0071: ldarga.s y2 + IL_0073: constrained. !!Y + IL_0079: callvirt instance string [mscorlib]System.Object::ToString() + IL_007e: stelem.ref + IL_007f: dup + IL_0080: ldc.i4.7 + IL_0081: ldarga.s z2 + IL_0083: constrained. !!Z + IL_0089: callvirt instance string [mscorlib]System.Object::ToString() + IL_008e: stelem.ref + IL_008f: call string [mscorlib]System.String::Concat(string[]) + IL_0094: newobj instance void class C`1::.ctor(string) + IL_0099: ret + } // end of method Extensions::'b__1_0' +} // end of class Extensions +""".Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); + + var src2 = """ +public static class Extensions +{ + extension(C o) + { + string M(T t1, U u1) + { + U local(T t2, U u2, X x2, Y y2, Z z2) + { + _ = o.GetString() + u1.ToString() + t1.ToString() + u2.ToString() + t2.ToString() + x2.ToString() + y2.ToString() + z2.ToString(); + return u2; + }; + + return local(t1, u1, 0, t1, u1).ToString(); + } + } + + extension(C o) + { + string M(T t1, U u1, int x) + { + U local(T t2, U u2, X x2, Y y2, Z z2) + { + _ = o.GetString() + u1.ToString() + t1.ToString() + u2.ToString() + t2.ToString() + x2.ToString() + y2.ToString() + z2.ToString(); + return u2; + }; + + return local(t1, u1, 0, t1, u1).ToString(); + } + } +} + +public class C +{ + public string GetString() => null; +} +"""; + var comp2 = CreateCompilation(src2); + CompileAndVerify(comp2).VerifyDiagnostics(); + + var src3 = """ +class Program +{ + static void Main() + { + System.Console.Write(Test(new C("1"), 2, "3").GetString()); + System.Console.Write(new C("4").M2(5, "6").GetString()); + } + + static C Test(C o, T t1, U u1) + { + C local(T t2, X x2) + { + return o.M(t2, x2); + }; + + return local(t1, u1); + } +} + +static class Extensions +{ + extension(C o) + { + public C M2(T t1, U u1) + { + C local(T t2, X x2) + { + return o.M(t2, x2); + }; + + return local(t1, u1); + } + } +} +"""; + + var comp3 = CreateCompilation(src3, references: [comp1.ToMetadataReference()], options: TestOptions.DebugExe); + CompileAndVerify(comp3, expectedOutput: "1323202346565056").VerifyDiagnostics(); + + comp3 = CreateCompilation(src3, references: [comp1.EmitToImageReference()], options: TestOptions.DebugExe); + CompileAndVerify(comp3, expectedOutput: "1323202346565056").VerifyDiagnostics(); + } + + [Fact] + public void Implementation_InstanceMethod_09_WithLambda_Generic() + { + var src1 = """ +public static class Extensions +{ + extension(C o) + { + public C M(T t1, U u1) + { + System.Func> local = (T t2, U u2) => + { + return new C(o.GetString() + u1.ToString() + t1.ToString() + u2.ToString() + t2.ToString()); + }; + + return local(t1, u1); + } + } +} + +public class C(string val) +{ + public string GetString() => val; +} +"""; + var comp1 = CreateCompilation(src1); + var verifier1 = CompileAndVerify(comp1).VerifyDiagnostics(); + + verifier1.VerifyTypeIL("Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0`1' + extends [mscorlib]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + class C`1 o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x20c4 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0`1'::'$' + .method public hidebysig + instance class C`1 M ( + !T t1, + !!U u1 + ) cil managed + { + // Method begins at RVA 0x20c6 + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0`1'::M + } // end of class <>E__0`1 + .class nested private auto ansi sealed beforefieldinit '<>c__DisplayClass1_0`2' + extends [mscorlib]System.Object + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field public class C`1 o + .field public !U u1 + .field public !T t1 + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x20c9 + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method '<>c__DisplayClass1_0`2'::.ctor + .method assembly hidebysig + instance class C`1 'b__0' ( + !T t2, + !U u2 + ) cil managed + { + // Method begins at RVA 0x20d4 + // Code size 103 (0x67) + .maxstack 4 + IL_0000: ldc.i4.5 + IL_0001: newarr [mscorlib]System.String + IL_0006: dup + IL_0007: ldc.i4.0 + IL_0008: ldarg.0 + IL_0009: ldfld class C`1 class Extensions/'<>c__DisplayClass1_0`2'::o + IL_000e: callvirt instance string class C`1::GetString() + IL_0013: stelem.ref + IL_0014: dup + IL_0015: ldc.i4.1 + IL_0016: ldarg.0 + IL_0017: ldflda !1 class Extensions/'<>c__DisplayClass1_0`2'::u1 + IL_001c: constrained. !U + IL_0022: callvirt instance string [mscorlib]System.Object::ToString() + IL_0027: stelem.ref + IL_0028: dup + IL_0029: ldc.i4.2 + IL_002a: ldarg.0 + IL_002b: ldflda !0 class Extensions/'<>c__DisplayClass1_0`2'::t1 + IL_0030: constrained. !T + IL_0036: callvirt instance string [mscorlib]System.Object::ToString() + IL_003b: stelem.ref + IL_003c: dup + IL_003d: ldc.i4.3 + IL_003e: ldarga.s u2 + IL_0040: constrained. !U + IL_0046: callvirt instance string [mscorlib]System.Object::ToString() + IL_004b: stelem.ref + IL_004c: dup + IL_004d: ldc.i4.4 + IL_004e: ldarga.s t2 + IL_0050: constrained. !T + IL_0056: callvirt instance string [mscorlib]System.Object::ToString() + IL_005b: stelem.ref + IL_005c: call string [mscorlib]System.String::Concat(string[]) + IL_0061: newobj instance void class C`1::.ctor(string) + IL_0066: ret + } // end of method '<>c__DisplayClass1_0`2'::'b__0' + } // end of class <>c__DisplayClass1_0`2 + // Methods + .method public hidebysig specialname static + class C`1 M ( + class C`1 o, + !!T t1, + !!U u1 + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2068 + // Code size 57 (0x39) + .maxstack 3 + .locals init ( + [0] class Extensions/'<>c__DisplayClass1_0`2' + ) + IL_0000: newobj instance void class Extensions/'<>c__DisplayClass1_0`2'::.ctor() + IL_0005: stloc.0 + IL_0006: ldloc.0 + IL_0007: ldarg.0 + IL_0008: stfld class C`1 class Extensions/'<>c__DisplayClass1_0`2'::o + IL_000d: ldloc.0 + IL_000e: ldarg.2 + IL_000f: stfld !1 class Extensions/'<>c__DisplayClass1_0`2'::u1 + IL_0014: ldloc.0 + IL_0015: ldarg.1 + IL_0016: stfld !0 class Extensions/'<>c__DisplayClass1_0`2'::t1 + IL_001b: ldloc.0 + IL_001c: ldftn instance class C`1 class Extensions/'<>c__DisplayClass1_0`2'::'b__0'(!0, !1) + IL_0022: newobj instance void class [mscorlib]System.Func`3>::.ctor(object, native int) + IL_0027: ldloc.0 + IL_0028: ldfld !0 class Extensions/'<>c__DisplayClass1_0`2'::t1 + IL_002d: ldloc.0 + IL_002e: ldfld !1 class Extensions/'<>c__DisplayClass1_0`2'::u1 + IL_0033: callvirt instance !2 class [mscorlib]System.Func`3>::Invoke(!0, !1) + IL_0038: ret + } // end of method Extensions::M +} // end of class Extensions +""".Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); + + var src2 = """ +public static class Extensions +{ + extension(C o) + { + string M(T t1, U u1) + { + System.Func local = (T t2, U u2) => + { + _ = o.GetString() + u1.ToString() + t1.ToString() + u2.ToString() + t2.ToString(); + return u2; + }; + + return local(t1, u1).ToString(); + } + } + + extension(C o) + { + string M(T t1, U u1, int x) + { + System.Func local = (T t2, U u2) => + { + _ = o.GetString() + u1.ToString() + t1.ToString() + u2.ToString() + t2.ToString(); + return u2; + }; + + return local(t1, u1).ToString(); + } + } +} + +public class C +{ + public string GetString() => null; +} +"""; + var comp2 = CreateCompilation(src2); + CompileAndVerify(comp2).VerifyDiagnostics(); + + var src3 = """ +class Program +{ + static void Main() + { + System.Console.Write(Test(new C("1"), 2, "3").GetString()); + System.Console.Write(new C("4").M2(5, "6").GetString()); + } + + static C Test(C o, T t1, U u1) + { + System.Func> local = (T t2, U u2) => + { + return o.M(t2, u2); + }; + + return local(t1, u1); + } +} + +static class Extensions +{ + extension(C o) + { + public C M2(T t1, U u1) + { + System.Func> local = (T t2, U u2) => + { + return o.M(t2, u2); + }; + + return local(t1, u1); + } + } +} +"""; + + var comp3 = CreateCompilation(src3, references: [comp1.ToMetadataReference()], options: TestOptions.DebugExe); + CompileAndVerify(comp3, expectedOutput: "1323246565").VerifyDiagnostics(); + + comp3 = CreateCompilation(src3, references: [comp1.EmitToImageReference()], options: TestOptions.DebugExe); + CompileAndVerify(comp3, expectedOutput: "1323246565").VerifyDiagnostics(); + } + + [Fact] + public void Implementation_InstanceMethod_10_Iterator_Generic() + { + var src1 = """ +public static class Extensions +{ + extension(C o) + { + public System.Collections.Generic.IEnumerable M(T t1, U u1) + { + yield return o.GetString() + u1.ToString() + t1.ToString(); + } + } +} + +public class C(string val) +{ + public string GetString() => val; +} +"""; + var comp1 = CreateCompilation(src1); + var verifier1 = CompileAndVerify(comp1, symbolValidator: (m) => + { + MethodSymbol implementation = m.ContainingAssembly.GetTypeByMetadataName("Extensions").GetMembers().OfType().Single(); + AssertEx.Equal("System.Runtime.CompilerServices.IteratorStateMachineAttribute(typeof(Extensions.d__1<,>))", implementation.GetAttributes().Single().ToString()); + }).VerifyDiagnostics(); + + verifier1.VerifyTypeIL("Extensions", (""" +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0`1' + extends [mscorlib]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + class C`1 o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x209c + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0`1'::'$' + .method public hidebysig + instance class [mscorlib]System.Collections.Generic.IEnumerable`1 M ( + !T t1, + !!U u1 + ) cil managed + { + // Method begins at RVA 0x209e + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0`1'::M + } // end of class <>E__0`1 + .class nested private auto ansi sealed beforefieldinit 'd__1`2' + extends [mscorlib]System.Object + implements class [mscorlib]System.Collections.Generic.IEnumerable`1, + [mscorlib]System.Collections.IEnumerable, + class [mscorlib]System.Collections.Generic.IEnumerator`1, + +""" + + (ExecutionConditionUtil.IsMonoOrCoreClr ? +""" + [mscorlib]System.Collections.IEnumerator, + [mscorlib]System.IDisposable + +""" : +""" + [mscorlib]System.IDisposable, + [mscorlib]System.Collections.IEnumerator + +""") + +""" + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field private int32 '<>1__state' + .field private string '<>2__current' + .field private int32 '<>l__initialThreadId' + .field private class C`1 o + .field public class C`1 '<>3__o' + .field private !U u1 + .field public !U '<>3__u1' + .field private !T t1 + .field public !T '<>3__t1' + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor ( + int32 '<>1__state' + ) cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x20a1 + // Code size 25 (0x19) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: stfld int32 class Extensions/'d__1`2'::'<>1__state' + IL_000d: ldarg.0 + IL_000e: call int32 [mscorlib]System.Environment::get_CurrentManagedThreadId() + IL_0013: stfld int32 class Extensions/'d__1`2'::'<>l__initialThreadId' + IL_0018: ret + } // end of method 'd__1`2'::.ctor + .method private final hidebysig newslot virtual + instance void System.IDisposable.Dispose () cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance void [mscorlib]System.IDisposable::Dispose() + // Method begins at RVA 0x20bb + // Code size 9 (0x9) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.s -2 + IL_0003: stfld int32 class Extensions/'d__1`2'::'<>1__state' + IL_0008: ret + } // end of method 'd__1`2'::System.IDisposable.Dispose + .method private final hidebysig newslot virtual + instance bool MoveNext () cil managed + { + .override method instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() + // Method begins at RVA 0x20c8 + // Code size 97 (0x61) + .maxstack 4 + .locals init ( + [0] int32 + ) + IL_0000: ldarg.0 + IL_0001: ldfld int32 class Extensions/'d__1`2'::'<>1__state' + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_0010 + IL_000a: ldloc.0 + IL_000b: ldc.i4.1 + IL_000c: beq.s IL_0058 + IL_000e: ldc.i4.0 + IL_000f: ret + IL_0010: ldarg.0 + IL_0011: ldc.i4.m1 + IL_0012: stfld int32 class Extensions/'d__1`2'::'<>1__state' + IL_0017: ldarg.0 + IL_0018: ldarg.0 + IL_0019: ldfld class C`1 class Extensions/'d__1`2'::o + IL_001e: callvirt instance string class C`1::GetString() + IL_0023: ldarg.0 + IL_0024: ldflda !1 class Extensions/'d__1`2'::u1 + IL_0029: constrained. !U + IL_002f: callvirt instance string [mscorlib]System.Object::ToString() + IL_0034: ldarg.0 + IL_0035: ldflda !0 class Extensions/'d__1`2'::t1 + IL_003a: constrained. !T + IL_0040: callvirt instance string [mscorlib]System.Object::ToString() + IL_0045: call string [mscorlib]System.String::Concat(string, string, string) + IL_004a: stfld string class Extensions/'d__1`2'::'<>2__current' + IL_004f: ldarg.0 + IL_0050: ldc.i4.1 + IL_0051: stfld int32 class Extensions/'d__1`2'::'<>1__state' + IL_0056: ldc.i4.1 + IL_0057: ret + IL_0058: ldarg.0 + IL_0059: ldc.i4.m1 + IL_005a: stfld int32 class Extensions/'d__1`2'::'<>1__state' + IL_005f: ldc.i4.0 + IL_0060: ret + } // end of method 'd__1`2'::MoveNext + .method private final hidebysig specialname newslot virtual + instance string 'System.Collections.Generic.IEnumerator.get_Current' () cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1::get_Current() + // Method begins at RVA 0x2135 + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld string class Extensions/'d__1`2'::'<>2__current' + IL_0006: ret + } // end of method 'd__1`2'::'System.Collections.Generic.IEnumerator.get_Current' + .method private final hidebysig newslot virtual + instance void System.Collections.IEnumerator.Reset () cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance void [mscorlib]System.Collections.IEnumerator::Reset() + // Method begins at RVA 0x213d + // Code size 6 (0x6) + .maxstack 8 + IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() + IL_0005: throw + } // end of method 'd__1`2'::System.Collections.IEnumerator.Reset + .method private final hidebysig specialname newslot virtual + instance object System.Collections.IEnumerator.get_Current () cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance object [mscorlib]System.Collections.IEnumerator::get_Current() + // Method begins at RVA 0x2135 + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld string class Extensions/'d__1`2'::'<>2__current' + IL_0006: ret + } // end of method 'd__1`2'::System.Collections.IEnumerator.get_Current + .method private final hidebysig newslot virtual + instance class [mscorlib]System.Collections.Generic.IEnumerator`1 'System.Collections.Generic.IEnumerable.GetEnumerator' () cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance class [mscorlib]System.Collections.Generic.IEnumerator`1 class [mscorlib]System.Collections.Generic.IEnumerable`1::GetEnumerator() + // Method begins at RVA 0x2144 + // Code size 79 (0x4f) + .maxstack 2 + .locals init ( + [0] class Extensions/'d__1`2' + ) + IL_0000: ldarg.0 + IL_0001: ldfld int32 class Extensions/'d__1`2'::'<>1__state' + IL_0006: ldc.i4.s -2 + IL_0008: bne.un.s IL_0022 + IL_000a: ldarg.0 + IL_000b: ldfld int32 class Extensions/'d__1`2'::'<>l__initialThreadId' + IL_0010: call int32 [mscorlib]System.Environment::get_CurrentManagedThreadId() + IL_0015: bne.un.s IL_0022 + IL_0017: ldarg.0 + IL_0018: ldc.i4.0 + IL_0019: stfld int32 class Extensions/'d__1`2'::'<>1__state' + IL_001e: ldarg.0 + IL_001f: stloc.0 + IL_0020: br.s IL_0029 + IL_0022: ldc.i4.0 + IL_0023: newobj instance void class Extensions/'d__1`2'::.ctor(int32) + IL_0028: stloc.0 + IL_0029: ldloc.0 + IL_002a: ldarg.0 + IL_002b: ldfld class C`1 class Extensions/'d__1`2'::'<>3__o' + IL_0030: stfld class C`1 class Extensions/'d__1`2'::o + IL_0035: ldloc.0 + IL_0036: ldarg.0 + IL_0037: ldfld !0 class Extensions/'d__1`2'::'<>3__t1' + IL_003c: stfld !0 class Extensions/'d__1`2'::t1 + IL_0041: ldloc.0 + IL_0042: ldarg.0 + IL_0043: ldfld !1 class Extensions/'d__1`2'::'<>3__u1' + IL_0048: stfld !1 class Extensions/'d__1`2'::u1 + IL_004d: ldloc.0 + IL_004e: ret + } // end of method 'd__1`2'::'System.Collections.Generic.IEnumerable.GetEnumerator' + .method private final hidebysig newslot virtual + instance class [mscorlib]System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.IEnumerable::GetEnumerator() + // Method begins at RVA 0x219f + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance class [mscorlib]System.Collections.Generic.IEnumerator`1 class Extensions/'d__1`2'::'System.Collections.Generic.IEnumerable.GetEnumerator'() + IL_0006: ret + } // end of method 'd__1`2'::System.Collections.IEnumerable.GetEnumerator + // Properties + .property instance string 'System.Collections.Generic.IEnumerator.Current'() + { + .get instance string Extensions/'d__1`2'::'System.Collections.Generic.IEnumerator.get_Current'() + } + .property instance object System.Collections.IEnumerator.Current() + { + .get instance object Extensions/'d__1`2'::System.Collections.IEnumerator.get_Current() + } + } // end of class d__1`2 + // Methods + .method public hidebysig specialname static + class [mscorlib]System.Collections.Generic.IEnumerable`1 M ( + class C`1 o, + !!T t1, + !!U u1 + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.IteratorStateMachineAttribute::.ctor(class [mscorlib]System.Type) = ( + 01 00 14 45 78 74 65 6e 73 69 6f 6e 73 2b 3c 4d + 3e 64 5f 5f 31 60 32 00 00 + ) + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 29 (0x1d) + .maxstack 8 + IL_0000: ldc.i4.s -2 + IL_0002: newobj instance void class Extensions/'d__1`2'::.ctor(int32) + IL_0007: dup + IL_0008: ldarg.0 + IL_0009: stfld class C`1 class Extensions/'d__1`2'::'<>3__o' + IL_000e: dup + IL_000f: ldarg.1 + IL_0010: stfld !0 class Extensions/'d__1`2'::'<>3__t1' + IL_0015: dup + IL_0016: ldarg.2 + IL_0017: stfld !1 class Extensions/'d__1`2'::'<>3__u1' + IL_001c: ret + } // end of method Extensions::M +} // end of class Extensions +""").Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); + + var src2 = """ +public static class Extensions +{ + extension(C o) + { + System.Collections.Generic.IEnumerable M(T t1, U u1) + { + yield return o.GetString() + u1.ToString() + t1.ToString(); + } + } + + extension(C o) + { + System.Collections.Generic.IEnumerable M(T t1, U u1, int x) + { + yield return o.GetString() + u1.ToString() + t1.ToString(); + } + } +} + +public class C +{ + public string GetString() => null; +} +"""; + var comp2 = CreateCompilation(src2); + CompileAndVerify(comp2).VerifyDiagnostics(); + + var src3 = """ +class Program +{ + static void Main() + { + foreach (var s in Test(new C("1"), 2, "3")) + System.Console.Write(s); + foreach (var s in new C("4").M2(5, "6")) + System.Console.Write(s); + } + + static System.Collections.Generic.IEnumerable Test(C o, T t1, U u1) + { + return o.M(t1, u1); + } +} + +static class Extensions +{ + extension(C o) + { + public System.Collections.Generic.IEnumerable M2(T t1, U u1) => o.M(t1, u1); + } +} +"""; + + var comp3 = CreateCompilation(src3, references: [comp1.ToMetadataReference()], options: TestOptions.DebugExe); + CompileAndVerify(comp3, expectedOutput: "132465").VerifyDiagnostics(); + + comp3 = CreateCompilation(src3, references: [comp1.EmitToImageReference()], options: TestOptions.DebugExe); + CompileAndVerify(comp3, expectedOutput: "132465").VerifyDiagnostics(); + } + + [Fact] + public void Implementation_InstanceMethod_11_Async_Generic() + { + var src1 = """ +public static class Extensions +{ + extension(C o) + { + public async System.Threading.Tasks.Task M(T t1, U u1) + { + await System.Threading.Tasks.Task.Yield(); + return o.GetString() + u1.ToString() + t1.ToString(); + } + } +} + +public class C(string val) +{ + public string GetString() => val; +} +"""; + var comp1 = CreateCompilation(src1); + var verifier1 = CompileAndVerify(comp1, symbolValidator: (m) => + { + MethodSymbol implementation = m.ContainingAssembly.GetTypeByMetadataName("Extensions").GetMembers().OfType().Single(); + AssertEx.Equal("System.Runtime.CompilerServices.AsyncStateMachineAttribute(typeof(Extensions.d__1<,>))", implementation.GetAttributes().Single().ToString()); + }).VerifyDiagnostics(); + + verifier1.VerifyTypeIL("Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0`1' + extends [mscorlib]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + class C`1 o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x20d2 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0`1'::'$' + .method public hidebysig + instance class [mscorlib]System.Threading.Tasks.Task`1 M ( + !T t1, + !!U u1 + ) cil managed + { + // Method begins at RVA 0x20d4 + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0`1'::M + } // end of class <>E__0`1 + .class nested private auto ansi sealed beforefieldinit 'd__1`2' + extends [mscorlib]System.ValueType + implements [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field public int32 '<>1__state' + .field public valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 '<>t__builder' + .field public class C`1 o + .field public !U u1 + .field public !T t1 + .field private valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter '<>u__1' + // Methods + .method private final hidebysig newslot virtual + instance void MoveNext () cil managed + { + .override method instance void [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine::MoveNext() + // Method begins at RVA 0x20d8 + // Code size 202 (0xca) + .maxstack 3 + .locals init ( + [0] int32, + [1] string, + [2] valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter, + [3] valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable, + [4] class [mscorlib]System.Exception + ) + IL_0000: ldarg.0 + IL_0001: ldfld int32 valuetype Extensions/'d__1`2'::'<>1__state' + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_0044 + IL_000a: call valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable [mscorlib]System.Threading.Tasks.Task::Yield() + IL_000f: stloc.3 + IL_0010: ldloca.s 3 + IL_0012: call instance valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter [mscorlib]System.Runtime.CompilerServices.YieldAwaitable::GetAwaiter() + IL_0017: stloc.2 + IL_0018: ldloca.s 2 + IL_001a: call instance bool [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter::get_IsCompleted() + IL_001f: brtrue.s IL_0060 + IL_0021: ldarg.0 + IL_0022: ldc.i4.0 + IL_0023: dup + IL_0024: stloc.0 + IL_0025: stfld int32 valuetype Extensions/'d__1`2'::'<>1__state' + IL_002a: ldarg.0 + IL_002b: ldloc.2 + IL_002c: stfld valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter valuetype Extensions/'d__1`2'::'<>u__1' + IL_0031: ldarg.0 + IL_0032: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype Extensions/'d__1`2'::'<>t__builder' + IL_0037: ldloca.s 2 + IL_0039: ldarg.0 + IL_003a: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::AwaitUnsafeOnCompletedd__1`2'>(!!0&, !!1&) + IL_003f: leave IL_00c9 + IL_0044: ldarg.0 + IL_0045: ldfld valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter valuetype Extensions/'d__1`2'::'<>u__1' + IL_004a: stloc.2 + IL_004b: ldarg.0 + IL_004c: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter valuetype Extensions/'d__1`2'::'<>u__1' + IL_0051: initobj [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter + IL_0057: ldarg.0 + IL_0058: ldc.i4.m1 + IL_0059: dup + IL_005a: stloc.0 + IL_005b: stfld int32 valuetype Extensions/'d__1`2'::'<>1__state' + IL_0060: ldloca.s 2 + IL_0062: call instance void [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter::GetResult() + IL_0067: ldarg.0 + IL_0068: ldfld class C`1 valuetype Extensions/'d__1`2'::o + IL_006d: callvirt instance string class C`1::GetString() + IL_0072: ldarg.0 + IL_0073: ldflda !1 valuetype Extensions/'d__1`2'::u1 + IL_0078: constrained. !U + IL_007e: callvirt instance string [mscorlib]System.Object::ToString() + IL_0083: ldarg.0 + IL_0084: ldflda !0 valuetype Extensions/'d__1`2'::t1 + IL_0089: constrained. !T + IL_008f: callvirt instance string [mscorlib]System.Object::ToString() + IL_0094: call string [mscorlib]System.String::Concat(string, string, string) + IL_0099: stloc.1 + IL_009a: leave.s IL_00b5 + } // end .try + catch [mscorlib]System.Exception + { + IL_009c: stloc.s 4 + IL_009e: ldarg.0 + IL_009f: ldc.i4.s -2 + IL_00a1: stfld int32 valuetype Extensions/'d__1`2'::'<>1__state' + IL_00a6: ldarg.0 + IL_00a7: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype Extensions/'d__1`2'::'<>t__builder' + IL_00ac: ldloc.s 4 + IL_00ae: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetException(class [mscorlib]System.Exception) + IL_00b3: leave.s IL_00c9 + } // end handler + IL_00b5: ldarg.0 + IL_00b6: ldc.i4.s -2 + IL_00b8: stfld int32 valuetype Extensions/'d__1`2'::'<>1__state' + IL_00bd: ldarg.0 + IL_00be: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype Extensions/'d__1`2'::'<>t__builder' + IL_00c3: ldloc.1 + IL_00c4: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetResult(!0) + IL_00c9: ret + } // end of method 'd__1`2'::MoveNext + .method private final hidebysig newslot virtual + instance void SetStateMachine ( + class [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine stateMachine + ) cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance void [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine::SetStateMachine(class [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine) + // Method begins at RVA 0x21c0 + // Code size 13 (0xd) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype Extensions/'d__1`2'::'<>t__builder' + IL_0006: ldarg.1 + IL_0007: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetStateMachine(class [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine) + IL_000c: ret + } // end of method 'd__1`2'::SetStateMachine + } // end of class d__1`2 + // Methods + .method public hidebysig specialname static + class [mscorlib]System.Threading.Tasks.Task`1 M ( + class C`1 o, + !!T t1, + !!U u1 + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.AsyncStateMachineAttribute::.ctor(class [mscorlib]System.Type) = ( + 01 00 14 45 78 74 65 6e 73 69 6f 6e 73 2b 3c 4d + 3e 64 5f 5f 31 60 32 00 00 + ) + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2068 + // Code size 71 (0x47) + .maxstack 2 + .locals init ( + [0] valuetype Extensions/'d__1`2' + ) + IL_0000: ldloca.s 0 + IL_0002: call valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::Create() + IL_0007: stfld valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype Extensions/'d__1`2'::'<>t__builder' + IL_000c: ldloca.s 0 + IL_000e: ldarg.0 + IL_000f: stfld class C`1 valuetype Extensions/'d__1`2'::o + IL_0014: ldloca.s 0 + IL_0016: ldarg.1 + IL_0017: stfld !0 valuetype Extensions/'d__1`2'::t1 + IL_001c: ldloca.s 0 + IL_001e: ldarg.2 + IL_001f: stfld !1 valuetype Extensions/'d__1`2'::u1 + IL_0024: ldloca.s 0 + IL_0026: ldc.i4.m1 + IL_0027: stfld int32 valuetype Extensions/'d__1`2'::'<>1__state' + IL_002c: ldloca.s 0 + IL_002e: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype Extensions/'d__1`2'::'<>t__builder' + IL_0033: ldloca.s 0 + IL_0035: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::Startd__1`2'>(!!0&) + IL_003a: ldloca.s 0 + IL_003c: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype Extensions/'d__1`2'::'<>t__builder' + IL_0041: call instance class [mscorlib]System.Threading.Tasks.Task`1 valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::get_Task() + IL_0046: ret + } // end of method Extensions::M +} // end of class Extensions +""".Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); + + var src2 = """ +public static class Extensions +{ + extension(C o) + { + async System.Threading.Tasks.Task M(T t1, U u1) + { + await System.Threading.Tasks.Task.Yield(); + return o.GetString() + u1.ToString() + t1.ToString(); + } + } + + extension(C o) + { + async System.Threading.Tasks.Task M(T t1, U u1, int x) + { + await System.Threading.Tasks.Task.Yield(); + return o.GetString() + u1.ToString() + t1.ToString(); + } + } +} + +public class C +{ + public string GetString() => null; +} +"""; + var comp2 = CreateCompilation(src2); + CompileAndVerify(comp2).VerifyDiagnostics(); + + var src3 = """ +class Program +{ + static void Main() + { + System.Console.Write(Test(new C("1"), 2, "3").Result); + System.Console.Write(new C("4").M2(5, "6").Result); + } + + async static System.Threading.Tasks.Task Test(C o, T t1, U u1) + { + await System.Threading.Tasks.Task.Yield(); + return await o.M(t1, u1); + } +} + +static class Extensions +{ + extension(C o) + { + async public System.Threading.Tasks.Task M2(T t1, U u1) + { + await System.Threading.Tasks.Task.Yield(); + return await o.M(t1, u1); + } + } +} +"""; + + var comp3 = CreateCompilation(src3, references: [comp1.ToMetadataReference()], options: TestOptions.DebugExe); + CompileAndVerify(comp3, expectedOutput: "132465").VerifyDiagnostics(); + + comp3 = CreateCompilation(src3, references: [comp1.EmitToImageReference()], options: TestOptions.DebugExe); + CompileAndVerify(comp3, expectedOutput: "132465").VerifyDiagnostics(); + } + + [Fact] + public void Implementation_StaticMethod_01() + { + var src1 = """ +public static class Extensions +{ + extension(object _) + { + public static string M(object o, string s) + { + return o + s; + } + } +} +"""; + var comp1 = CreateCompilation(src1); + + var verifier1 = CompileAndVerify(comp1, sourceSymbolValidator: verifySymbols, symbolValidator: verifySymbols).VerifyDiagnostics(); + + static void verifySymbols(ModuleSymbol m) + { + MethodSymbol implementation = m.ContainingAssembly.GetTypeByMetadataName("Extensions").GetMembers().OfType().Single(); + Assert.True(implementation.IsStatic); + Assert.Equal(MethodKind.Ordinary, implementation.MethodKind); + Assert.Equal(2, implementation.ParameterCount); + AssertEx.Equal("System.String Extensions.M(System.Object o, System.String s)", implementation.ToTestDisplayString()); + Assert.Equal(m is not PEModuleSymbol, implementation.IsImplicitlyDeclared); + Assert.False(implementation.IsExtensionMethod); + Assert.True(implementation.HasSpecialName); + Assert.False(implementation.HasRuntimeSpecialName); + + Assert.True(implementation.ContainingType.MightContainExtensionMethods); + + if (m is PEModuleSymbol peModuleSymbol) + { + Assert.True(peModuleSymbol.Module.HasExtensionAttribute(((PEAssemblySymbol)peModuleSymbol.ContainingAssembly).Assembly.Handle, ignoreCase: false)); + } + } + + var expectedTypeIL = """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0' + extends [mscorlib]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + object _ + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x207b + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0'::'$' + .method public hidebysig static + string M ( + object o, + string s + ) cil managed + { + // Method begins at RVA 0x207d + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0'::M + } // end of class <>E__0 + // Methods + .method public hidebysig specialname static + string M ( + object o, + string s + ) cil managed + { + // Method begins at RVA 0x2067 + // Code size 19 (0x13) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: brtrue.s IL_0006 + IL_0003: ldnull + IL_0004: br.s IL_000c + IL_0006: ldarg.0 + IL_0007: callvirt instance string [mscorlib]System.Object::ToString() + IL_000c: ldarg.1 + IL_000d: call string [mscorlib]System.String::Concat(string, string) + IL_0012: ret + } // end of method Extensions::M +} // end of class Extensions +"""; + + verifier1.VerifyTypeIL("Extensions", expectedTypeIL.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); + + var src2 = """ +class Program +{ + static void Main() + { + System.Console.Write(Test("1")); + System.Console.Write(object.M2("3", "4")); + } + + static string Test(object o) + { + return object.M(o, "2"); + } +} + +static class Extensions +{ + extension(object o) + { + public static string M2(object o1, string s) + { + return object.M(o1, s); + } + } +} +"""; + + var comp1MetadataReference = comp1.ToMetadataReference(); + var comp2 = CreateCompilation(src2, references: [comp1MetadataReference], options: TestOptions.DebugExe); + var verifier2 = CompileAndVerify(comp2, expectedOutput: "1234").VerifyDiagnostics(); + + var testIL = +@" +{ + // Code size 17 (0x11) + .maxstack 2 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldstr ""2"" + IL_0007: call ""string Extensions.M(object, string)"" + IL_000c: stloc.0 + IL_000d: br.s IL_000f + IL_000f: ldloc.0 + IL_0010: ret +} +"; + verifier2.VerifyIL("Program.Test", testIL); + + var m2IL = +@" +{ + // Code size 9 (0x9) + .maxstack 2 + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldarg.1 + IL_0003: call ""string Extensions.M(object, string)"" + IL_0008: ret +} +"; + verifier2.VerifyIL("Extensions.M2", m2IL); + + var comp1ImageReference = comp1.EmitToImageReference(); + comp2 = CreateCompilation(src2, references: [comp1ImageReference], options: TestOptions.DebugExe); + verifier2 = CompileAndVerify(comp2, expectedOutput: "1234").VerifyDiagnostics(); + + verifier2.VerifyIL("Program.Test", testIL); + verifier2.VerifyIL("Extensions.M2", m2IL); + + comp2 = CreateCompilationWithIL(src2, expectedTypeIL, options: TestOptions.DebugExe); + CompileAndVerify(comp2, expectedOutput: "1234").VerifyDiagnostics(); + + var remove = """ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) +"""; + + comp2 = CreateCompilationWithIL(src2, expectedTypeIL.Remove(expectedTypeIL.IndexOf(remove), remove.Length)); + comp2.VerifyDiagnostics( + // (11,23): error CS0117: 'object' does not contain a definition for 'M' + // return object.M(o, "2"); + Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("object", "M").WithLocation(11, 23), + // (21,27): error CS0117: 'object' does not contain a definition for 'M' + // return object.M(o, s); + Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("object", "M").WithLocation(21, 27) + ); + + src2 = """ +class Program +{ + static void Main() + { + System.Console.Write(Test("1")); + System.Console.Write(object.M2("3", "4")); + } + + static string Test(object o) + { + return Extensions.M(o, "2"); + } +} + +static class Extensions_ +{ + extension(object o) + { + public static string M2(object o1, string s) + { + return Extensions.M(o1, s); + } + } +} +"""; + + comp2 = CreateCompilation(src2, references: [comp1MetadataReference], options: TestOptions.DebugExe); + verifier2 = CompileAndVerify(comp2, expectedOutput: "1234").VerifyDiagnostics(); + + verifier2.VerifyIL("Program.Test", testIL); + verifier2.VerifyIL("Extensions_.M2", m2IL); + + comp2 = CreateCompilation(src2, references: [comp1ImageReference], options: TestOptions.DebugExe); + verifier2 = CompileAndVerify(comp2, expectedOutput: "1234").VerifyDiagnostics(); + + verifier2.VerifyIL("Program.Test", testIL); + verifier2.VerifyIL("Extensions_.M2", m2IL); + + var vbComp = CreateVisualBasicCompilation(""" +Class Program + Shared Sub Main() + System.Console.Write(Test2("3")) + End Sub + + Shared Function Test2(o As String) As String + return Extensions.M(o, "4") + End Function +End Class +""", + referencedAssemblies: comp2.References, compilationOptions: new VisualBasicCompilationOptions(OutputKind.ConsoleApplication)); + + CompileAndVerify(vbComp, expectedOutput: "34").VerifyDiagnostics(); + + if (!CompilationExtensions.EnableVerifyUsedAssemblies) // Tracked by https://github.com/dotnet/roslyn/issues/77542 + { + src2 = """ +class Program +{ + static void Main() + { + System.Console.Write(Test("1")); + System.Console.Write(object.M2("3", "4")); + } + + static string Test(object o) + { + System.Func d = object.M; + return d(o, "2"); + } +} + +static class Extensions +{ + extension(object o) + { + public static string M2(object o1, string s) + { + return new System.Func(object.M)(o1, s); + } + } +} +"""; + + comp2 = CreateCompilation(src2, references: [comp1MetadataReference], options: TestOptions.DebugExe); + verifier2 = CompileAndVerify(comp2, expectedOutput: "1234").VerifyDiagnostics(); + + testIL = + @" +{ + // Code size 46 (0x2e) + .maxstack 3 + .locals init (System.Func V_0, //d + string V_1) + IL_0000: nop + IL_0001: ldsfld ""System.Func Program.<>O.<0>__M"" + IL_0006: dup + IL_0007: brtrue.s IL_001c + IL_0009: pop + IL_000a: ldnull + IL_000b: ldftn ""string Extensions.M(object, string)"" + IL_0011: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0016: dup + IL_0017: stsfld ""System.Func Program.<>O.<0>__M"" + IL_001c: stloc.0 + IL_001d: ldloc.0 + IL_001e: ldarg.0 + IL_001f: ldstr ""2"" + IL_0024: callvirt ""string System.Func.Invoke(object, string)"" + IL_0029: stloc.1 + IL_002a: br.s IL_002c + IL_002c: ldloc.1 + IL_002d: ret +} +"; + verifier2.VerifyIL("Program.Test", testIL); + + m2IL = + @" +{ + // Code size 21 (0x15) + .maxstack 3 + IL_0000: nop + IL_0001: ldnull + IL_0002: ldftn ""string Extensions.M(object, string)"" + IL_0008: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_000d: ldarg.0 + IL_000e: ldarg.1 + IL_000f: callvirt ""string System.Func.Invoke(object, string)"" + IL_0014: ret +} +"; + verifier2.VerifyIL("Extensions.M2", m2IL); + + comp2 = CreateCompilation(src2, references: [comp1ImageReference], options: TestOptions.DebugExe); + verifier2 = CompileAndVerify(comp2, expectedOutput: "1234").VerifyDiagnostics(); + + verifier2.VerifyIL("Program.Test", testIL); + verifier2.VerifyIL("Extensions.M2", m2IL); + + src2 = """ +class Program +{ + static void Main() + { + System.Console.Write(Test("1")); + System.Console.Write(object.M2("3", "4")); + } + + static string Test(object o) + { + System.Func d = Extensions.M; + return d(o, "2"); + } +} + +static class Extensions_ +{ + extension(object o) + { + public static string M2(object o1, string s) + { + return new System.Func(Extensions.M)(o1, s); + } + } +} +"""; + + comp2 = CreateCompilation(src2, references: [comp1MetadataReference], options: TestOptions.DebugExe); + verifier2 = CompileAndVerify(comp2, expectedOutput: "1234").VerifyDiagnostics(); + + verifier2.VerifyIL("Program.Test", testIL); + verifier2.VerifyIL("Extensions_.M2", m2IL); + + comp2 = CreateCompilation(src2, references: [comp1ImageReference], options: TestOptions.DebugExe); + verifier2 = CompileAndVerify(comp2, expectedOutput: "1234").VerifyDiagnostics(); + + verifier2.VerifyIL("Program.Test", testIL); + verifier2.VerifyIL("Extensions_.M2", m2IL); + + src2 = """ +class Program +{ + static void Main() + { + System.Console.Write(Test("1")); + System.Console.Write(object.M2("3", "4")); + } + + unsafe static string Test(object o) + { + delegate* d = &object.M; + return d(o, "2"); + } +} + +static class Extensions +{ + extension(object o) + { + unsafe public static string M2(object o1, string s) + { + return ((delegate*)&object.M)(o1, s); + } + } +} +"""; + + comp2 = CreateCompilation(src2, references: [comp1MetadataReference], options: TestOptions.DebugExe.WithAllowUnsafe(true)); + verifier2 = CompileAndVerify(comp2, expectedOutput: "1234", verify: Verification.Skipped).VerifyDiagnostics(); + + testIL = +@" +{ + // Code size 27 (0x1b) + .maxstack 3 + .locals init (delegate* V_0, //d + delegate* V_1, + string V_2) + IL_0000: nop + IL_0001: ldftn ""string Extensions.M(object, string)"" + IL_0007: stloc.0 + IL_0008: ldloc.0 + IL_0009: stloc.1 + IL_000a: ldarg.0 + IL_000b: ldstr ""2"" + IL_0010: ldloc.1 + IL_0011: calli ""delegate*"" + IL_0016: stloc.2 + IL_0017: br.s IL_0019 + IL_0019: ldloc.2 + IL_001a: ret +} +"; + verifier2.VerifyIL("Program.Test", testIL); + + m2IL = +@" +{ + // Code size 17 (0x11) + .maxstack 3 + .locals init (delegate* V_0) + IL_0000: nop + IL_0001: ldftn ""string Extensions.M(object, string)"" + IL_0007: stloc.0 + IL_0008: ldarg.0 + IL_0009: ldarg.1 + IL_000a: ldloc.0 + IL_000b: calli ""delegate*"" + IL_0010: ret +} +"; + verifier2.VerifyIL("Extensions.M2", m2IL); + + comp2 = CreateCompilation(src2, references: [comp1ImageReference], options: TestOptions.DebugExe.WithAllowUnsafe(true)); + verifier2 = CompileAndVerify(comp2, expectedOutput: "1234", verify: Verification.Skipped).VerifyDiagnostics(); + + verifier2.VerifyIL("Program.Test", testIL); + verifier2.VerifyIL("Extensions.M2", m2IL); + + src2 = """ +class Program +{ + static void Main() + { + System.Console.Write(Test("1")); + System.Console.Write(object.M2("3", "4")); + } + + unsafe static string Test(object o) + { + delegate* d = &Extensions.M; + return d(o, "2"); + } +} + +static class Extensions_ +{ + extension(object o) + { + unsafe public static string M2(object o1, string s) + { + return ((delegate*)&Extensions.M)(o1, s); + } + } +} +"""; + + comp2 = CreateCompilation(src2, references: [comp1MetadataReference], options: TestOptions.DebugExe.WithAllowUnsafe(true)); + verifier2 = CompileAndVerify(comp2, expectedOutput: "1234", verify: Verification.Skipped).VerifyDiagnostics(); + + verifier2.VerifyIL("Program.Test", testIL); + verifier2.VerifyIL("Extensions_.M2", m2IL); + + comp2 = CreateCompilation(src2, references: [comp1ImageReference], options: TestOptions.DebugExe.WithAllowUnsafe(true)); + verifier2 = CompileAndVerify(comp2, expectedOutput: "1234", verify: Verification.Skipped).VerifyDiagnostics(); + + verifier2.VerifyIL("Program.Test", testIL); + verifier2.VerifyIL("Extensions_.M2", m2IL); + } + + var comp5 = CreateCompilation(src1); + comp5.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_ExtensionAttribute__ctor); + comp5.VerifyEmitDiagnostics( + // (3,5): error CS1110: Cannot define a new extension because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? + // extension(object _) + Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "extension").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(3, 5) + ); + } + + [Fact] + public void Implementation_StaticMethod_02_WithLocalFunction() + { + var src1 = """ +public static class Extensions +{ + extension(object _) + { + public static string M(object o, string s) + { + string local() => o + s; + return local(); + } + } +} +"""; + var comp1 = CreateCompilation(src1); + var verifier1 = CompileAndVerify(comp1).VerifyDiagnostics(); + + verifier1.VerifyTypeIL("Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0' + extends [mscorlib]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + object _ + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x20ab + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0'::'$' + .method public hidebysig static + string M ( + object o, + string s + ) cil managed + { + // Method begins at RVA 0x20ad + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0'::M + } // end of class <>E__0 + .class nested private auto ansi sealed beforefieldinit '<>c__DisplayClass1_0' + extends [mscorlib]System.ValueType + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field public object o + .field public string s + } // end of class <>c__DisplayClass1_0 + // Methods + .method public hidebysig specialname static + string M ( + object o, + string s + ) cil managed + { + // Method begins at RVA 0x2068 + // Code size 24 (0x18) + .maxstack 2 + .locals init ( + [0] valuetype Extensions/'<>c__DisplayClass1_0' + ) + IL_0000: ldloca.s 0 + IL_0002: ldarg.0 + IL_0003: stfld object Extensions/'<>c__DisplayClass1_0'::o + IL_0008: ldloca.s 0 + IL_000a: ldarg.1 + IL_000b: stfld string Extensions/'<>c__DisplayClass1_0'::s + IL_0010: ldloca.s 0 + IL_0012: call string Extensions::'b__1_0'(valuetype Extensions/'<>c__DisplayClass1_0'&) + IL_0017: ret + } // end of method Extensions::M + .method assembly hidebysig static + string 'b__1_0' ( + valuetype Extensions/'<>c__DisplayClass1_0'& '' + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x208c + // Code size 30 (0x1e) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld object Extensions/'<>c__DisplayClass1_0'::o + IL_0006: dup + IL_0007: brtrue.s IL_000d + IL_0009: pop + IL_000a: ldnull + IL_000b: br.s IL_0012 + IL_000d: callvirt instance string [mscorlib]System.Object::ToString() + IL_0012: ldarg.0 + IL_0013: ldfld string Extensions/'<>c__DisplayClass1_0'::s + IL_0018: call string [mscorlib]System.String::Concat(string, string) + IL_001d: ret + } // end of method Extensions::'b__1_0' +} // end of class Extensions +""".Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); + + var src2 = """ +public static class Extensions +{ + extension(object _) + { + static string M(object o, string s) + { + string local() => o + s; + return local(); + } + } + + extension(object) + { + static string M(object o, string s, int x) + { + string local() => o + s; + return local(); + } + } +} +"""; + var comp2 = CreateCompilation(src2); + CompileAndVerify(comp2).VerifyDiagnostics(); + + var src3 = """ +class Program +{ + static void Main() + { + System.Console.Write(Test("1")); + System.Console.Write(object.M2("3","4")); + } + + static string Test(object o) + { + string local() => object.M(o, "2"); + return local(); + } +} + +static class Extensions +{ + extension(object _) + { + public static string M2(object o, string s) + { + string local() => object.M(o, s); + return local(); + } + } +} +"""; + + var comp3 = CreateCompilation(src3, references: [comp1.ToMetadataReference()], options: TestOptions.DebugExe); + CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); + + comp3 = CreateCompilation(src3, references: [comp1.EmitToImageReference()], options: TestOptions.DebugExe); + CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); + } + + [Fact] + public void Implementation_StaticMethod_03_WithLambda() + { + var src1 = """ +public static class Extensions +{ + extension(object _) + { + public static string M(object o, string s) + { + System.Func local = () => o + s; + return local(); + } + } +} +"""; + var comp1 = CreateCompilation(src1); + var verifier1 = CompileAndVerify(comp1).VerifyDiagnostics(); + + verifier1.VerifyTypeIL("Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0' + extends [mscorlib]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + object _ + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x208c + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0'::'$' + .method public hidebysig static + string M ( + object o, + string s + ) cil managed + { + // Method begins at RVA 0x208e + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0'::M + } // end of class <>E__0 + .class nested private auto ansi sealed beforefieldinit '<>c__DisplayClass1_0' + extends [mscorlib]System.Object + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field public object o + .field public string s + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x2091 + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method '<>c__DisplayClass1_0'::.ctor + .method assembly hidebysig + instance string 'b__0' () cil managed + { + // Method begins at RVA 0x2099 + // Code size 30 (0x1e) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld object Extensions/'<>c__DisplayClass1_0'::o + IL_0006: dup + IL_0007: brtrue.s IL_000d + IL_0009: pop + IL_000a: ldnull + IL_000b: br.s IL_0012 + IL_000d: callvirt instance string [mscorlib]System.Object::ToString() + IL_0012: ldarg.0 + IL_0013: ldfld string Extensions/'<>c__DisplayClass1_0'::s + IL_0018: call string [mscorlib]System.String::Concat(string, string) + IL_001d: ret + } // end of method '<>c__DisplayClass1_0'::'b__0' + } // end of class <>c__DisplayClass1_0 + // Methods + .method public hidebysig specialname static + string M ( + object o, + string s + ) cil managed + { + // Method begins at RVA 0x2067 + // Code size 36 (0x24) + .maxstack 8 + IL_0000: newobj instance void Extensions/'<>c__DisplayClass1_0'::.ctor() + IL_0005: dup + IL_0006: ldarg.0 + IL_0007: stfld object Extensions/'<>c__DisplayClass1_0'::o + IL_000c: dup + IL_000d: ldarg.1 + IL_000e: stfld string Extensions/'<>c__DisplayClass1_0'::s + IL_0013: ldftn instance string Extensions/'<>c__DisplayClass1_0'::'b__0'() + IL_0019: newobj instance void class [mscorlib]System.Func`1::.ctor(object, native int) + IL_001e: callvirt instance !0 class [mscorlib]System.Func`1::Invoke() + IL_0023: ret + } // end of method Extensions::M +} // end of class Extensions +""".Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); + + var src2 = """ +public static class Extensions +{ + extension(object _) + { + static string M(object o, string s) + { + System.Func local = () => o + s; + return local(); + } + } + + extension(object) + { + static string M(object o, string s, int x) + { + System.Func local = () => o + s; + return local(); + } + } +} +"""; + var comp2 = CreateCompilation(src2); + CompileAndVerify(comp2).VerifyDiagnostics(); + + var src3 = """ +class Program +{ + static void Main() + { + System.Console.Write(Test("1")); + System.Console.Write(object.M2("3","4")); + } + + static string Test(object o) + { + System.Func local = () => object.M(o, "2"); + return local(); + } +} + +static class Extensions +{ + extension(object _) + { + public static string M2(object o, string s) + { + System.Func local = () => object.M(o, s); + return local(); + } + } +} +"""; + + var comp3 = CreateCompilation(src3, references: [comp1.ToMetadataReference()], options: TestOptions.DebugExe); + CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); + + comp3 = CreateCompilation(src3, references: [comp1.EmitToImageReference()], options: TestOptions.DebugExe); + CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); + } + + [Fact] + public void Implementation_StaticMethod_04_Iterator() + { + var src1 = """ +public static class Extensions +{ + extension(object _) + { + public static System.Collections.Generic.IEnumerable M(object o, string s) + { + yield return o + s; + } + } +} +"""; + var comp1 = CreateCompilation(src1); + var verifier1 = CompileAndVerify(comp1, symbolValidator: (m) => + { + MethodSymbol implementation = m.ContainingAssembly.GetTypeByMetadataName("Extensions").GetMembers().OfType().Single(); + AssertEx.Equal("System.Runtime.CompilerServices.IteratorStateMachineAttribute(typeof(Extensions.d__1))", implementation.GetAttributes().Single().ToString()); + }).VerifyDiagnostics(); + + verifier1.VerifyTypeIL("Extensions", (""" +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0' + extends [mscorlib]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + object _ + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x207e + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0'::'$' + .method public hidebysig static + class [mscorlib]System.Collections.Generic.IEnumerable`1 M ( + object o, + string s + ) cil managed + { + // Method begins at RVA 0x2080 + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0'::M + } // end of class <>E__0 + .class nested private auto ansi sealed beforefieldinit 'd__1' + extends [mscorlib]System.Object + implements class [mscorlib]System.Collections.Generic.IEnumerable`1, + [mscorlib]System.Collections.IEnumerable, + class [mscorlib]System.Collections.Generic.IEnumerator`1, + +""" + + (ExecutionConditionUtil.IsMonoOrCoreClr ? +""" + [mscorlib]System.Collections.IEnumerator, + [mscorlib]System.IDisposable + +""" : +""" + [mscorlib]System.IDisposable, + [mscorlib]System.Collections.IEnumerator + +""") + +""" + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field private int32 '<>1__state' + .field private string '<>2__current' + .field private int32 '<>l__initialThreadId' + .field private object o + .field public object '<>3__o' + .field private string s + .field public string '<>3__s' + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor ( + int32 '<>1__state' + ) cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2083 + // Code size 25 (0x19) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: stfld int32 Extensions/'d__1'::'<>1__state' + IL_000d: ldarg.0 + IL_000e: call int32 [mscorlib]System.Environment::get_CurrentManagedThreadId() + IL_0013: stfld int32 Extensions/'d__1'::'<>l__initialThreadId' + IL_0018: ret + } // end of method 'd__1'::.ctor + .method private final hidebysig newslot virtual + instance void System.IDisposable.Dispose () cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance void [mscorlib]System.IDisposable::Dispose() + // Method begins at RVA 0x209d + // Code size 9 (0x9) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.s -2 + IL_0003: stfld int32 Extensions/'d__1'::'<>1__state' + IL_0008: ret + } // end of method 'd__1'::System.IDisposable.Dispose + .method private final hidebysig newslot virtual + instance bool MoveNext () cil managed + { + .override method instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() + // Method begins at RVA 0x20a8 + // Code size 76 (0x4c) + .maxstack 3 + .locals init ( + [0] int32 + ) + IL_0000: ldarg.0 + IL_0001: ldfld int32 Extensions/'d__1'::'<>1__state' + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_0010 + IL_000a: ldloc.0 + IL_000b: ldc.i4.1 + IL_000c: beq.s IL_0043 + IL_000e: ldc.i4.0 + IL_000f: ret + IL_0010: ldarg.0 + IL_0011: ldc.i4.m1 + IL_0012: stfld int32 Extensions/'d__1'::'<>1__state' + IL_0017: ldarg.0 + IL_0018: ldarg.0 + IL_0019: ldfld object Extensions/'d__1'::o + IL_001e: dup + IL_001f: brtrue.s IL_0025 + IL_0021: pop + IL_0022: ldnull + IL_0023: br.s IL_002a + IL_0025: callvirt instance string [mscorlib]System.Object::ToString() + IL_002a: ldarg.0 + IL_002b: ldfld string Extensions/'d__1'::s + IL_0030: call string [mscorlib]System.String::Concat(string, string) + IL_0035: stfld string Extensions/'d__1'::'<>2__current' + IL_003a: ldarg.0 + IL_003b: ldc.i4.1 + IL_003c: stfld int32 Extensions/'d__1'::'<>1__state' + IL_0041: ldc.i4.1 + IL_0042: ret + IL_0043: ldarg.0 + IL_0044: ldc.i4.m1 + IL_0045: stfld int32 Extensions/'d__1'::'<>1__state' + IL_004a: ldc.i4.0 + IL_004b: ret + } // end of method 'd__1'::MoveNext + .method private final hidebysig specialname newslot virtual + instance string 'System.Collections.Generic.IEnumerator.get_Current' () cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1::get_Current() + // Method begins at RVA 0x2100 + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld string Extensions/'d__1'::'<>2__current' + IL_0006: ret + } // end of method 'd__1'::'System.Collections.Generic.IEnumerator.get_Current' + .method private final hidebysig newslot virtual + instance void System.Collections.IEnumerator.Reset () cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance void [mscorlib]System.Collections.IEnumerator::Reset() + // Method begins at RVA 0x2108 + // Code size 6 (0x6) + .maxstack 8 + IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() + IL_0005: throw + } // end of method 'd__1'::System.Collections.IEnumerator.Reset + .method private final hidebysig specialname newslot virtual + instance object System.Collections.IEnumerator.get_Current () cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance object [mscorlib]System.Collections.IEnumerator::get_Current() + // Method begins at RVA 0x2100 + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld string Extensions/'d__1'::'<>2__current' + IL_0006: ret + } // end of method 'd__1'::System.Collections.IEnumerator.get_Current + .method private final hidebysig newslot virtual + instance class [mscorlib]System.Collections.Generic.IEnumerator`1 'System.Collections.Generic.IEnumerable.GetEnumerator' () cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance class [mscorlib]System.Collections.Generic.IEnumerator`1 class [mscorlib]System.Collections.Generic.IEnumerable`1::GetEnumerator() + // Method begins at RVA 0x2110 + // Code size 67 (0x43) + .maxstack 2 + .locals init ( + [0] class Extensions/'d__1' + ) + IL_0000: ldarg.0 + IL_0001: ldfld int32 Extensions/'d__1'::'<>1__state' + IL_0006: ldc.i4.s -2 + IL_0008: bne.un.s IL_0022 + IL_000a: ldarg.0 + IL_000b: ldfld int32 Extensions/'d__1'::'<>l__initialThreadId' + IL_0010: call int32 [mscorlib]System.Environment::get_CurrentManagedThreadId() + IL_0015: bne.un.s IL_0022 + IL_0017: ldarg.0 + IL_0018: ldc.i4.0 + IL_0019: stfld int32 Extensions/'d__1'::'<>1__state' + IL_001e: ldarg.0 + IL_001f: stloc.0 + IL_0020: br.s IL_0029 + IL_0022: ldc.i4.0 + IL_0023: newobj instance void Extensions/'d__1'::.ctor(int32) + IL_0028: stloc.0 + IL_0029: ldloc.0 + IL_002a: ldarg.0 + IL_002b: ldfld object Extensions/'d__1'::'<>3__o' + IL_0030: stfld object Extensions/'d__1'::o + IL_0035: ldloc.0 + IL_0036: ldarg.0 + IL_0037: ldfld string Extensions/'d__1'::'<>3__s' + IL_003c: stfld string Extensions/'d__1'::s + IL_0041: ldloc.0 + IL_0042: ret + } // end of method 'd__1'::'System.Collections.Generic.IEnumerable.GetEnumerator' + .method private final hidebysig newslot virtual + instance class [mscorlib]System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.IEnumerable::GetEnumerator() + // Method begins at RVA 0x215f + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance class [mscorlib]System.Collections.Generic.IEnumerator`1 Extensions/'d__1'::'System.Collections.Generic.IEnumerable.GetEnumerator'() + IL_0006: ret + } // end of method 'd__1'::System.Collections.IEnumerable.GetEnumerator + // Properties + .property instance string 'System.Collections.Generic.IEnumerator.Current'() + { + .get instance string Extensions/'d__1'::'System.Collections.Generic.IEnumerator.get_Current'() + } + .property instance object System.Collections.IEnumerator.Current() + { + .get instance object Extensions/'d__1'::System.Collections.IEnumerator.get_Current() + } + } // end of class d__1 + // Methods + .method public hidebysig specialname static + class [mscorlib]System.Collections.Generic.IEnumerable`1 M ( + object o, + string s + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.IteratorStateMachineAttribute::.ctor(class [mscorlib]System.Type) = ( + 01 00 12 45 78 74 65 6e 73 69 6f 6e 73 2b 3c 4d + 3e 64 5f 5f 31 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 22 (0x16) + .maxstack 8 + IL_0000: ldc.i4.s -2 + IL_0002: newobj instance void Extensions/'d__1'::.ctor(int32) + IL_0007: dup + IL_0008: ldarg.0 + IL_0009: stfld object Extensions/'d__1'::'<>3__o' + IL_000e: dup + IL_000f: ldarg.1 + IL_0010: stfld string Extensions/'d__1'::'<>3__s' + IL_0015: ret + } // end of method Extensions::M +} // end of class Extensions +""").Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); + + var src2 = """ +public static class Extensions +{ + extension(object _) + { + static System.Collections.Generic.IEnumerable M(object o, string s) + { + yield return o + s; + } + } + + extension(object) + { + static System.Collections.Generic.IEnumerable M(object o, string s, int x) + { + yield return o + s; + } + } +} +"""; + var comp2 = CreateCompilation(src2); + CompileAndVerify(comp2).VerifyDiagnostics(); + + var src3 = """ +class Program +{ + static void Main() + { + foreach (var s in Test("1")) + System.Console.Write(s); + foreach (var s in object.M2("3", "4")) + System.Console.Write(s); + } + + static System.Collections.Generic.IEnumerable Test(object o) + { + return object.M(o, "2"); + } +} + +static class Extensions +{ + extension(object _) + { + public static System.Collections.Generic.IEnumerable M2(object o, string s) => object.M(o, s); + } +} +"""; + + var comp3 = CreateCompilation(src3, references: [comp1.ToMetadataReference()], options: TestOptions.DebugExe); + CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); + + comp3 = CreateCompilation(src3, references: [comp1.EmitToImageReference()], options: TestOptions.DebugExe); + CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); + } + + [Fact] + public void Implementation_StaticMethod_05_Async() + { + var src1 = """ +public static class Extensions +{ + extension(object _) + { + public static async System.Threading.Tasks.Task M(object o, string s) + { + await System.Threading.Tasks.Task.Yield(); + return o + s; + } + } +} +"""; + var comp1 = CreateCompilation(src1); + var verifier1 = CompileAndVerify(comp1, symbolValidator: (m) => + { + MethodSymbol implementation = m.ContainingAssembly.GetTypeByMetadataName("Extensions").GetMembers().OfType().Single(); + AssertEx.Equal("System.Runtime.CompilerServices.AsyncStateMachineAttribute(typeof(Extensions.d__1))", implementation.GetAttributes().Single().ToString()); + }).VerifyDiagnostics(); + + verifier1.VerifyTypeIL("Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0' + extends [mscorlib]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + object _ + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x20b3 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0'::'$' + .method public hidebysig static + class [mscorlib]System.Threading.Tasks.Task`1 M ( + object o, + string s + ) cil managed + { + // Method begins at RVA 0x20b5 + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0'::M + } // end of class <>E__0 + .class nested private auto ansi sealed beforefieldinit 'd__1' + extends [mscorlib]System.ValueType + implements [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field public int32 '<>1__state' + .field public valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 '<>t__builder' + .field public object o + .field public string s + .field private valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter '<>u__1' + // Methods + .method private final hidebysig newslot virtual + instance void MoveNext () cil managed + { + .override method instance void [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine::MoveNext() + // Method begins at RVA 0x20b8 + // Code size 178 (0xb2) + .maxstack 3 + .locals init ( + [0] int32, + [1] string, + [2] valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter, + [3] valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable, + [4] class [mscorlib]System.Exception + ) + IL_0000: ldarg.0 + IL_0001: ldfld int32 Extensions/'d__1'::'<>1__state' + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_0041 + IL_000a: call valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable [mscorlib]System.Threading.Tasks.Task::Yield() + IL_000f: stloc.3 + IL_0010: ldloca.s 3 + IL_0012: call instance valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter [mscorlib]System.Runtime.CompilerServices.YieldAwaitable::GetAwaiter() + IL_0017: stloc.2 + IL_0018: ldloca.s 2 + IL_001a: call instance bool [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter::get_IsCompleted() + IL_001f: brtrue.s IL_005d + IL_0021: ldarg.0 + IL_0022: ldc.i4.0 + IL_0023: dup + IL_0024: stloc.0 + IL_0025: stfld int32 Extensions/'d__1'::'<>1__state' + IL_002a: ldarg.0 + IL_002b: ldloc.2 + IL_002c: stfld valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter Extensions/'d__1'::'<>u__1' + IL_0031: ldarg.0 + IL_0032: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 Extensions/'d__1'::'<>t__builder' + IL_0037: ldloca.s 2 + IL_0039: ldarg.0 + IL_003a: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::AwaitUnsafeOnCompletedd__1'>(!!0&, !!1&) + IL_003f: leave.s IL_00b1 + IL_0041: ldarg.0 + IL_0042: ldfld valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter Extensions/'d__1'::'<>u__1' + IL_0047: stloc.2 + IL_0048: ldarg.0 + IL_0049: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter Extensions/'d__1'::'<>u__1' + IL_004e: initobj [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter + IL_0054: ldarg.0 + IL_0055: ldc.i4.m1 + IL_0056: dup + IL_0057: stloc.0 + IL_0058: stfld int32 Extensions/'d__1'::'<>1__state' + IL_005d: ldloca.s 2 + IL_005f: call instance void [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter::GetResult() + IL_0064: ldarg.0 + IL_0065: ldfld object Extensions/'d__1'::o + IL_006a: dup + IL_006b: brtrue.s IL_0071 + IL_006d: pop + IL_006e: ldnull + IL_006f: br.s IL_0076 + IL_0071: callvirt instance string [mscorlib]System.Object::ToString() + IL_0076: ldarg.0 + IL_0077: ldfld string Extensions/'d__1'::s + IL_007c: call string [mscorlib]System.String::Concat(string, string) + IL_0081: stloc.1 + IL_0082: leave.s IL_009d + } // end .try + catch [mscorlib]System.Exception + { + IL_0084: stloc.s 4 + IL_0086: ldarg.0 + IL_0087: ldc.i4.s -2 + IL_0089: stfld int32 Extensions/'d__1'::'<>1__state' + IL_008e: ldarg.0 + IL_008f: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 Extensions/'d__1'::'<>t__builder' + IL_0094: ldloc.s 4 + IL_0096: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetException(class [mscorlib]System.Exception) + IL_009b: leave.s IL_00b1 + } // end handler + IL_009d: ldarg.0 + IL_009e: ldc.i4.s -2 + IL_00a0: stfld int32 Extensions/'d__1'::'<>1__state' + IL_00a5: ldarg.0 + IL_00a6: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 Extensions/'d__1'::'<>t__builder' + IL_00ab: ldloc.1 + IL_00ac: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetResult(!0) + IL_00b1: ret + } // end of method 'd__1'::MoveNext + .method private final hidebysig newslot virtual + instance void SetStateMachine ( + class [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine stateMachine + ) cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance void [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine::SetStateMachine(class [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine) + // Method begins at RVA 0x2188 + // Code size 13 (0xd) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 Extensions/'d__1'::'<>t__builder' + IL_0006: ldarg.1 + IL_0007: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetStateMachine(class [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine) + IL_000c: ret + } // end of method 'd__1'::SetStateMachine + } // end of class d__1 + // Methods + .method public hidebysig specialname static + class [mscorlib]System.Threading.Tasks.Task`1 M ( + object o, + string s + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.AsyncStateMachineAttribute::.ctor(class [mscorlib]System.Type) = ( + 01 00 12 45 78 74 65 6e 73 69 6f 6e 73 2b 3c 4d + 3e 64 5f 5f 31 00 00 + ) + // Method begins at RVA 0x2068 + // Code size 63 (0x3f) + .maxstack 2 + .locals init ( + [0] valuetype Extensions/'d__1' + ) + IL_0000: ldloca.s 0 + IL_0002: call valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::Create() + IL_0007: stfld valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 Extensions/'d__1'::'<>t__builder' + IL_000c: ldloca.s 0 + IL_000e: ldarg.0 + IL_000f: stfld object Extensions/'d__1'::o + IL_0014: ldloca.s 0 + IL_0016: ldarg.1 + IL_0017: stfld string Extensions/'d__1'::s + IL_001c: ldloca.s 0 + IL_001e: ldc.i4.m1 + IL_001f: stfld int32 Extensions/'d__1'::'<>1__state' + IL_0024: ldloca.s 0 + IL_0026: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 Extensions/'d__1'::'<>t__builder' + IL_002b: ldloca.s 0 + IL_002d: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::Startd__1'>(!!0&) + IL_0032: ldloca.s 0 + IL_0034: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 Extensions/'d__1'::'<>t__builder' + IL_0039: call instance class [mscorlib]System.Threading.Tasks.Task`1 valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::get_Task() + IL_003e: ret + } // end of method Extensions::M +} // end of class Extensions +""".Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); + + var src2 = """ +public static class Extensions +{ + extension(object _) + { + static async System.Threading.Tasks.Task M(object o, string s) + { + await System.Threading.Tasks.Task.Yield(); + return o + s; + } + } + + extension(object) + { + static async System.Threading.Tasks.Task M(object o, string s, int x) + { + await System.Threading.Tasks.Task.Yield(); + return o + s; + } + } +} +"""; + var comp2 = CreateCompilation(src2); + CompileAndVerify(comp2).VerifyDiagnostics(); + + var src3 = """ +class Program +{ + static void Main() + { + System.Console.Write(Test("1").Result); + System.Console.Write(object.M2("3", "4").Result); + } + + async static System.Threading.Tasks.Task Test(object o) + { + await System.Threading.Tasks.Task.Yield(); + return await object.M(o, "2"); + } +} + +static class Extensions +{ + extension(object _) + { + async public static System.Threading.Tasks.Task M2(object o, string s) + { + await System.Threading.Tasks.Task.Yield(); + return await object.M(o, s); + } + } +} +"""; + + var comp3 = CreateCompilation(src3, references: [comp1.ToMetadataReference()], options: TestOptions.DebugExe); + CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); + + comp3 = CreateCompilation(src3, references: [comp1.EmitToImageReference()], options: TestOptions.DebugExe); + CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); + } + + [Fact] + public void Implementation_InstanceProperty_01() + { + var src1 = """ +public static class Extensions +{ + extension(object o) + { + public string P => o.ToString(); + } +} +"""; + var comp1 = CreateCompilation(src1); + + MethodSymbol implementation = comp1.GetTypeByMetadataName("Extensions").GetMembers().OfType().Single(); + Assert.True(implementation.IsStatic); + Assert.Equal(MethodKind.Ordinary, implementation.MethodKind); + Assert.Equal(1, implementation.ParameterCount); + AssertEx.Equal("System.String Extensions.get_P(System.Object o)", implementation.ToTestDisplayString()); + Assert.True(implementation.IsImplicitlyDeclared); + Assert.False(implementation.IsExtensionMethod); + Assert.True(implementation.HasSpecialName); + Assert.False(implementation.HasRuntimeSpecialName); + + var verifier1 = CompileAndVerify(comp1).VerifyDiagnostics(); + + var expectedTypeIL = """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0' + extends [mscorlib]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + object o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x206f + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0'::'$' + .method public hidebysig specialname + instance string get_P () cil managed + { + // Method begins at RVA 0x2071 + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0'::get_P + // Properties + .property instance string P() + { + .get instance string Extensions/'<>E__0'::get_P() + } + } // end of class <>E__0 + // Methods + .method public hidebysig specialname static + string get_P ( + object o + ) cil managed + { + // Method begins at RVA 0x2067 + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: callvirt instance string [mscorlib]System.Object::ToString() + IL_0006: ret + } // end of method Extensions::get_P +} // end of class Extensions +"""; + + verifier1.VerifyTypeIL("Extensions", expectedTypeIL.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); + + var src3 = """ +class Program +{ + static void Main() + { + System.Console.Write(Test("1")); + System.Console.Write("2".P2); + } + + static string Test(object o) + { + return o.P; + } +} + +static class Extensions +{ + extension(object o) + { + public string P2 => o.P; + } +} +"""; + + var comp1MetadataReference = comp1.ToMetadataReference(); + var comp3 = CreateCompilation(src3, references: [comp1MetadataReference], options: TestOptions.DebugExe); + var verifier3 = CompileAndVerify(comp3, expectedOutput: "12").VerifyDiagnostics(); + + var testIL = +@" +{ + // Code size 12 (0xc) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: call ""string Extensions.get_P(object)"" + IL_0007: stloc.0 + IL_0008: br.s IL_000a + IL_000a: ldloc.0 + IL_000b: ret +} +"; + verifier3.VerifyIL("Program.Test", testIL); + + var m2IL = +@" +{ + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: call ""string Extensions.get_P(object)"" + IL_0006: ret +} +"; + verifier3.VerifyIL("Extensions.get_P2(object)", m2IL); + + var comp1ImageReference = comp1.EmitToImageReference(); + comp3 = CreateCompilation(src3, references: [comp1ImageReference], options: TestOptions.DebugExe); + verifier3 = CompileAndVerify(comp3, expectedOutput: "12").VerifyDiagnostics(); + + verifier3.VerifyIL("Program.Test", testIL); + verifier3.VerifyIL("Extensions.get_P2(object)", m2IL); + + comp3 = CreateCompilationWithIL(src3, expectedTypeIL, options: TestOptions.DebugExe); + CompileAndVerify(comp3, expectedOutput: "12").VerifyDiagnostics(); + + var remove = """ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) +"""; + + comp3 = CreateCompilationWithIL(src3, expectedTypeIL.Remove(expectedTypeIL.IndexOf(remove), remove.Length)); + comp3.VerifyDiagnostics( + // (11,18): error CS1061: 'object' does not contain a definition for 'P' and no accessible extension method 'P' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) + // return o.P; + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "P").WithArguments("object", "P").WithLocation(11, 18), + // (19,31): error CS1061: 'object' does not contain a definition for 'P' and no accessible extension method 'P' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) + // public string P2 => o.P; + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "P").WithArguments("object", "P").WithLocation(19, 31) + ); + + src3 = """ +class Program +{ + static void Main() + { + System.Console.Write(Test("1")); + System.Console.Write("2".P2); + } + + static string Test(object o) + { + return o.get_P(); + } +} + +static class Extensions +{ + extension(object o) + { + public string P2 => o.get_P(); + } +} +"""; + + comp3 = CreateCompilation(src3, references: [comp1MetadataReference], options: TestOptions.DebugExe); + comp3.VerifyDiagnostics( + // (11,18): error CS1061: 'object' does not contain a definition for 'get_P' and no accessible extension method 'get_P' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) + // return o.get_P(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "get_P").WithArguments("object", "get_P").WithLocation(11, 18), + // (19,31): error CS1061: 'object' does not contain a definition for 'get_P' and no accessible extension method 'get_P' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) + // public string P2 => o.get_P(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "get_P").WithArguments("object", "get_P").WithLocation(19, 31) + ); + + comp3 = CreateCompilation(src3, references: [comp1ImageReference], options: TestOptions.DebugExe); + comp3.VerifyDiagnostics( + // (11,18): error CS1061: 'object' does not contain a definition for 'get_P' and no accessible extension method 'get_P' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) + // return o.get_P(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "get_P").WithArguments("object", "get_P").WithLocation(11, 18), + // (19,31): error CS1061: 'object' does not contain a definition for 'get_P' and no accessible extension method 'get_P' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) + // public string P2 => o.get_P(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "get_P").WithArguments("object", "get_P").WithLocation(19, 31) + ); + + src3 = """ +class Program +{ + static void Main() + { + System.Console.Write(Test("1")); + System.Console.Write("2".P2); + } + + static string Test(object o) + { + return Extensions.get_P(o); + } +} + +static class Extensions_ +{ + extension(object o) + { + public string P2 => Extensions.get_P(o); + } +} +"""; + + comp3 = CreateCompilation(src3, references: [comp1MetadataReference], options: TestOptions.DebugExe); + verifier3 = CompileAndVerify(comp3, expectedOutput: "12").VerifyDiagnostics(); + + verifier3.VerifyIL("Program.Test", testIL); + verifier3.VerifyIL("Extensions_.get_P2(object)", m2IL); + + comp3 = CreateCompilation(src3, references: [comp1ImageReference], options: TestOptions.DebugExe); + verifier3 = CompileAndVerify(comp3, expectedOutput: "12").VerifyDiagnostics(); + + verifier3.VerifyIL("Program.Test", testIL); + verifier3.VerifyIL("Extensions_.get_P2(object)", m2IL); + + var vbComp = CreateVisualBasicCompilation(""" +Class Program + Shared Sub Main() + System.Console.Write(Test2("3")) + End Sub + + Shared Function Test2(o As String) As String + return Extensions.get_P(o) + End Function +End Class +""", + referencedAssemblies: comp3.References, compilationOptions: new VisualBasicCompilationOptions(OutputKind.ConsoleApplication)); + + CompileAndVerify(vbComp, expectedOutput: "3").VerifyDiagnostics(); + + vbComp = CreateVisualBasicCompilation(""" +Class Program + Shared Sub Main() + System.Console.Write(Test1("1")) + End Sub + + Shared Function Test1(o As String) As String + return o.get_P() + End Function +End Class +""", + referencedAssemblies: comp3.References, compilationOptions: new VisualBasicCompilationOptions(OutputKind.ConsoleApplication)); + + vbComp.VerifyDiagnostics( + // error BC30456: 'get_P' is not a member of 'String'. + Diagnostic(30456 /*ERRID.ERR_NameNotMember2*/, "o.get_P").WithArguments("get_P", "String").WithLocation(7, 16) + ); + + var comp5 = CreateCompilation(src1); + comp5.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_ExtensionAttribute__ctor); + comp5.VerifyEmitDiagnostics( + // (3,5): error CS1110: Cannot define a new extension because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? + // extension(object o) + Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "extension").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(3, 5) + ); + } + + [Fact] + public void Implementation_StaticProperty_01() + { + var src1 = """ +public static class Extensions +{ + extension(object) + { + public static string P => "P"; + } +} +"""; + var comp1 = CreateCompilation(src1); + + MethodSymbol implementation = comp1.GetTypeByMetadataName("Extensions").GetMembers().OfType().Single(); + Assert.True(implementation.IsStatic); + Assert.Equal(MethodKind.Ordinary, implementation.MethodKind); + Assert.Equal(0, implementation.ParameterCount); + AssertEx.Equal("System.String Extensions.get_P()", implementation.ToTestDisplayString()); + Assert.True(implementation.IsImplicitlyDeclared); + Assert.False(implementation.IsExtensionMethod); + Assert.True(implementation.HasSpecialName); + Assert.False(implementation.HasRuntimeSpecialName); + + var verifier1 = CompileAndVerify(comp1).VerifyDiagnostics(); + + var expectedTypeIL = """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0' + extends [mscorlib]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + object '' + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x206e + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0'::'$' + .method public hidebysig specialname static + string get_P () cil managed + { + // Method begins at RVA 0x2070 + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0'::get_P + // Properties + .property string P() + { + .get string Extensions/'<>E__0'::get_P() + } + } // end of class <>E__0 + // Methods + .method public hidebysig specialname static + string get_P () cil managed + { + // Method begins at RVA 0x2067 + // Code size 6 (0x6) + .maxstack 8 + IL_0000: ldstr "P" + IL_0005: ret + } // end of method Extensions::get_P +} // end of class Extensions +"""; + + verifier1.VerifyTypeIL("Extensions", expectedTypeIL.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); + + var src3 = """ +class Program +{ + static void Main() + { + System.Console.Write(Test()); + System.Console.Write(object.P2); + } + + static string Test() + { + return object.P; + } +} + +static class Extensions +{ + extension(object o) + { + public static string P2 => object.P; + } +} +"""; + + var comp1MetadataReference = comp1.ToMetadataReference(); + var comp3 = CreateCompilation(src3, references: [comp1MetadataReference], options: TestOptions.DebugExe); + var verifier3 = CompileAndVerify(comp3, expectedOutput: "PP").VerifyDiagnostics(); + + var testIL = +@" +{ + // Code size 11 (0xb) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: call ""string Extensions.get_P()"" + IL_0006: stloc.0 + IL_0007: br.s IL_0009 + IL_0009: ldloc.0 + IL_000a: ret +} +"; + verifier3.VerifyIL("Program.Test", testIL); + + var m2IL = +@" +{ + // Code size 6 (0x6) + .maxstack 1 + IL_0000: call ""string Extensions.get_P()"" + IL_0005: ret +} +"; + verifier3.VerifyIL("Extensions.get_P2()", m2IL); + + var comp1ImageReference = comp1.EmitToImageReference(); + comp3 = CreateCompilation(src3, references: [comp1ImageReference], options: TestOptions.DebugExe); + verifier3 = CompileAndVerify(comp3, expectedOutput: "PP").VerifyDiagnostics(); + + verifier3.VerifyIL("Program.Test", testIL); + verifier3.VerifyIL("Extensions.get_P2()", m2IL); + + comp3 = CreateCompilationWithIL(src3, expectedTypeIL, options: TestOptions.DebugExe); + CompileAndVerify(comp3, expectedOutput: "PP").VerifyDiagnostics(); + + var remove = """ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) +"""; + + comp3 = CreateCompilationWithIL(src3, expectedTypeIL.Remove(expectedTypeIL.IndexOf(remove), remove.Length)); + comp3.VerifyDiagnostics( + // (11,23): error CS0117: 'object' does not contain a definition for 'P' + // return object.P; + Diagnostic(ErrorCode.ERR_NoSuchMember, "P").WithArguments("object", "P").WithLocation(11, 23), + // (19,43): error CS0117: 'object' does not contain a definition for 'P' + // public static string P2 => object.P; + Diagnostic(ErrorCode.ERR_NoSuchMember, "P").WithArguments("object", "P").WithLocation(19, 43) + ); + + src3 = """ +class Program +{ + static void Main() + { + System.Console.Write(Test()); + System.Console.Write(object.P2); + } + + static string Test() + { + return Extensions.get_P(); + } +} + +static class Extensions_ +{ + extension(object o) + { + public static string P2 => Extensions.get_P(); + } +} +"""; + + comp3 = CreateCompilation(src3, references: [comp1MetadataReference], options: TestOptions.DebugExe); + verifier3 = CompileAndVerify(comp3, expectedOutput: "PP").VerifyDiagnostics(); + + verifier3.VerifyIL("Program.Test", testIL); + verifier3.VerifyIL("Extensions_.get_P2()", m2IL); + + comp3 = CreateCompilation(src3, references: [comp1ImageReference], options: TestOptions.DebugExe); + verifier3 = CompileAndVerify(comp3, expectedOutput: "PP").VerifyDiagnostics(); + + verifier3.VerifyIL("Program.Test", testIL); + verifier3.VerifyIL("Extensions_.get_P2()", m2IL); + + var vbComp = CreateVisualBasicCompilation(""" +Class Program + Shared Sub Main() + System.Console.Write(Test2()) + End Sub + + Shared Function Test2() As String + return Extensions.get_P() + End Function +End Class +""", + referencedAssemblies: comp3.References, compilationOptions: new VisualBasicCompilationOptions(OutputKind.ConsoleApplication)); + + CompileAndVerify(vbComp, expectedOutput: "P").VerifyDiagnostics(); + + var comp5 = CreateCompilation(src1); + comp5.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_ExtensionAttribute__ctor); + comp5.VerifyEmitDiagnostics( + // (3,5): error CS1110: Cannot define a new extension because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? + // extension(object) + Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "extension").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(3, 5) + ); + } + + [Fact] + public void Implementation_InstanceProperty_02() + { + var src1 = """ +public static class Extensions +{ + extension(object o) + { + public string P { get { return o.ToString(); } } + } +} +"""; + var comp1 = CreateCompilation(src1); + var verifier1 = CompileAndVerify(comp1).VerifyDiagnostics(); + + verifier1.VerifyTypeIL("Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0' + extends [mscorlib]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + object o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x206f + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0'::'$' + .method public hidebysig specialname + instance string get_P () cil managed + { + // Method begins at RVA 0x2071 + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0'::get_P + // Properties + .property instance string P() + { + .get instance string Extensions/'<>E__0'::get_P() + } + } // end of class <>E__0 + // Methods + .method public hidebysig specialname static + string get_P ( + object o + ) cil managed + { + // Method begins at RVA 0x2067 + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: callvirt instance string [mscorlib]System.Object::ToString() + IL_0006: ret + } // end of method Extensions::get_P +} // end of class Extensions +""".Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); + + var src3 = """ +class Program +{ + static void Main() + { + System.Console.Write(Test("1")); + System.Console.Write("2".P2); + } + + static string Test(object o) + { + return o.P; + } +} + +static class Extensions +{ + extension(object o) + { + public string P2 => o.P; + } +} +"""; + + var comp3 = CreateCompilation(src3, references: [comp1.ToMetadataReference()], options: TestOptions.DebugExe); + var verifier3 = CompileAndVerify(comp3, expectedOutput: "12").VerifyDiagnostics(); + + var testIL = +@" +{ + // Code size 12 (0xc) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: call ""string Extensions.get_P(object)"" + IL_0007: stloc.0 + IL_0008: br.s IL_000a + IL_000a: ldloc.0 + IL_000b: ret +} +"; + verifier3.VerifyIL("Program.Test", testIL); + + var m2IL = +@" +{ + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: call ""string Extensions.get_P(object)"" + IL_0006: ret +} +"; + verifier3.VerifyIL("Extensions.get_P2(object)", m2IL); + + comp3 = CreateCompilation(src3, references: [comp1.EmitToImageReference()], options: TestOptions.DebugExe); + verifier3 = CompileAndVerify(comp3, expectedOutput: "12").VerifyDiagnostics(); + + verifier3.VerifyIL("Program.Test", testIL); + verifier3.VerifyIL("Extensions.get_P2(object)", m2IL); + } + + [Fact] + public void Implementation_DelegateCaching_01() + { + var src = """ +public static class Extensions +{ + extension(T o) + { + void M2() + { + #pragma warning disable CS8321 // The local function 'local' is declared but never used + System.Func local() + { + return C1.M1; + } + } + } +} + +class C1 +{ + static public V M1() => default; +} +"""; + var comp = CreateCompilation(src); + var verifier = CompileAndVerify(comp).VerifyDiagnostics(); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Consider executing and verifying behavior + + verifier.VerifyTypeIL("Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0`1' + extends [mscorlib]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + !T o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0`1'::'$' + .method private hidebysig + instance void M2 () cil managed + { + // Method begins at RVA 0x20a6 + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0`1'::M2 + } // end of class <>E__0`1 + .class nested private auto ansi abstract sealed beforefieldinit 'O__1_0`3' + extends [mscorlib]System.Object + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field public static class [mscorlib]System.Func`1 '<0>__M1' + } // end of class O__1_0`3 + // Methods + .method private hidebysig specialname static + void M2 ( + !!T o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method Extensions::M2 + .method assembly hidebysig static + class [mscorlib]System.Func`1 'b__1_0' () cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2069 + // Code size 28 (0x1c) + .maxstack 8 + IL_0000: ldsfld class [mscorlib]System.Func`1 class Extensions/'O__1_0`3'::'<0>__M1' + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn !!2 C1::M1() + IL_0010: newobj instance void class [mscorlib]System.Func`1::.ctor(object, native int) + IL_0015: dup + IL_0016: stsfld class [mscorlib]System.Func`1 class Extensions/'O__1_0`3'::'<0>__M1' + IL_001b: ret + } // end of method Extensions::'b__1_0' +} // end of class Extensions +""".Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); + + var src2 = """ +public static class Extensions +{ + extension(T o) + { + void M2() + { + #pragma warning disable CS8321 // The local function 'local' is declared but never used + System.Func local() + { + return C1.M1; + } + } + } + + extension(T o) + { + void M2(int x) + { + System.Func local() + { + return C1.M1; + } + } + } +} + +class C1 +{ + static public V M1() => default; +} +"""; + var comp2 = CreateCompilation(src2); + CompileAndVerify(comp2).VerifyDiagnostics(); + } + + [Fact] + public void Implementation_DelegateCaching_02() + { + var src = """ +public static class Extensions +{ + extension(T o) + { + void M2() + { + #pragma warning disable CS8321 // The local function 'local' is declared but never used + System.Action local() + { + return C1.M1; + } + } + } +} + +class C1 +{ + static public void M1() {} +} +"""; + var comp = CreateCompilation(src); + var verifier = CompileAndVerify(comp).VerifyDiagnostics(); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Consider executing and verifying behavior + + verifier.VerifyTypeIL("Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0`1' + extends [mscorlib]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + !T o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0`1'::'$' + .method private hidebysig + instance void M2 () cil managed + { + // Method begins at RVA 0x208e + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0`1'::M2 + } // end of class <>E__0`1 + .class nested private auto ansi abstract sealed beforefieldinit '<>O__1_0`1' + extends [mscorlib]System.Object + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field public static class [mscorlib]System.Action '<0>__M1' + } // end of class <>O__1_0`1 + // Methods + .method private hidebysig specialname static + void M2 ( + !!T o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method Extensions::M2 + .method assembly hidebysig static + class [mscorlib]System.Action 'b__1_0' () cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2069 + // Code size 28 (0x1c) + .maxstack 8 + IL_0000: ldsfld class [mscorlib]System.Action class Extensions/'<>O__1_0`1'::'<0>__M1' + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn void C1::M1() + IL_0010: newobj instance void [mscorlib]System.Action::.ctor(object, native int) + IL_0015: dup + IL_0016: stsfld class [mscorlib]System.Action class Extensions/'<>O__1_0`1'::'<0>__M1' + IL_001b: ret + } // end of method Extensions::'b__1_0' +} // end of class Extensions +""".Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); + + var src2 = """ +public static class Extensions +{ + extension(T o) + { + void M2() + { + #pragma warning disable CS8321 // The local function 'local' is declared but never used + System.Action local() + { + return C1.M1; + } + } + } + + extension(T o) + { + void M2(int x) + { + #pragma warning disable CS8321 // The local function 'local' is declared but never used + System.Action local() + { + return C1.M1; + } + } + } +} + +class C1 +{ + static public void M1() {} +} +"""; + var comp2 = CreateCompilation(src2); + CompileAndVerify(comp2).VerifyDiagnostics(); + } + + [Fact] + public void Implementation_DelegateCaching_03() + { + var src = """ +public static class Extensions +{ + extension(object o) + { + void M2() + { + #pragma warning disable CS8321 // The local function 'local' is declared but never used + System.Action local() + { + return C1.M1; + } + } + } +} + +class C1 +{ + static public void M1() {} +} +"""; + var comp = CreateCompilation(src); + var verifier = CompileAndVerify(comp).VerifyDiagnostics(); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Consider executing and verifying behavior + + verifier.VerifyTypeIL("Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0' + extends [mscorlib]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + object o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0'::'$' + .method private hidebysig + instance void M2 () cil managed + { + // Method begins at RVA 0x208e + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0'::M2 + } // end of class <>E__0 + .class nested private auto ansi abstract sealed beforefieldinit '<>O' + extends [mscorlib]System.Object + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field public static class [mscorlib]System.Action '<0>__M1' + } // end of class <>O + // Methods + .method private hidebysig specialname static + void M2 ( + object o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method Extensions::M2 + .method assembly hidebysig static + class [mscorlib]System.Action 'b__1_0' () cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2069 + // Code size 28 (0x1c) + .maxstack 8 + IL_0000: ldsfld class [mscorlib]System.Action Extensions/'<>O'::'<0>__M1' + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn void C1::M1() + IL_0010: newobj instance void [mscorlib]System.Action::.ctor(object, native int) + IL_0015: dup + IL_0016: stsfld class [mscorlib]System.Action Extensions/'<>O'::'<0>__M1' + IL_001b: ret + } // end of method Extensions::'b__1_0' +} // end of class Extensions +""".Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); + + var src2 = """ +public static class Extensions +{ + extension(object o) + { + void M2() + { + #pragma warning disable CS8321 // The local function 'local' is declared but never used + System.Action local() + { + return C1.M1; + } + } + } + + extension(object o) + { + void M2(int x) + { + System.Action local() + { + return C1.M1; + } + } + } +} + +class C1 +{ + static public void M1() {} +} +"""; + var comp2 = CreateCompilation(src2); + CompileAndVerify(comp2).VerifyDiagnostics(); + } + + [Fact] + public void Implementation_DelegateCaching_04() + { + var src = """ +public static class Extensions +{ + extension(T o) + { + System.Action M2() + { + return local; + + static void local() + { + typeof(T).ToString(); + } + } + } +} +"""; + var comp = CreateCompilation(src); + var verifier = CompileAndVerify(comp).VerifyDiagnostics(); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Consider executing and verifying behavior + + verifier.VerifyTypeIL("Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0`1' + extends [mscorlib]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + !T o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2096 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0`1'::'$' + .method private hidebysig + instance class [mscorlib]System.Action M2 () cil managed + { + // Method begins at RVA 0x2098 + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0`1'::M2 + } // end of class <>E__0`1 + .class nested private auto ansi abstract sealed beforefieldinit '<>O__1_0`1' + extends [mscorlib]System.Object + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field public static class [mscorlib]System.Action '<0>__local' + } // end of class <>O__1_0`1 + // Methods + .method private hidebysig specialname static + class [mscorlib]System.Action M2 ( + !!T o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 28 (0x1c) + .maxstack 8 + IL_0000: ldsfld class [mscorlib]System.Action class Extensions/'<>O__1_0`1'::'<0>__local' + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn void Extensions::'b__1_0'() + IL_0010: newobj instance void [mscorlib]System.Action::.ctor(object, native int) + IL_0015: dup + IL_0016: stsfld class [mscorlib]System.Action class Extensions/'<>O__1_0`1'::'<0>__local' + IL_001b: ret + } // end of method Extensions::M2 + .method assembly hidebysig static + void 'b__1_0' () cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2084 + // Code size 17 (0x11) + .maxstack 8 + IL_0000: ldtoken !!T + IL_0005: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) + IL_000a: callvirt instance string [mscorlib]System.Object::ToString() + IL_000f: pop + IL_0010: ret + } // end of method Extensions::'b__1_0' +} // end of class Extensions +""".Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); + + var src2 = """ +public static class Extensions +{ + extension(T o) + { + System.Action M2() + { + return local; + + static void local() + { + typeof(T).ToString(); + } + } + } + + extension(T o) + { + System.Action M2(int x) + { + return local; + + static void local() + { + typeof(T).ToString(); + } + } + } +} +"""; + var comp2 = CreateCompilation(src2); + CompileAndVerify(comp2).VerifyDiagnostics(); + } + + [Fact] + public void Implementation_DelegateCaching_05() + { + var src = """ +public static class Extensions +{ + extension(object o) + { + System.Action M2() + { + return local; + + static void local() + { + typeof(object).ToString(); + } + } + } +} +"""; + var comp = CreateCompilation(src); + var verifier = CompileAndVerify(comp).VerifyDiagnostics(); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Consider executing and verifying behavior + + verifier.VerifyTypeIL("Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0' + extends [mscorlib]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + object o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2096 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0'::'$' + .method private hidebysig + instance class [mscorlib]System.Action M2 () cil managed + { + // Method begins at RVA 0x2098 + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0'::M2 + } // end of class <>E__0 + .class nested private auto ansi abstract sealed beforefieldinit '<>O' + extends [mscorlib]System.Object + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field public static class [mscorlib]System.Action '<0>__local' + } // end of class <>O + // Methods + .method private hidebysig specialname static + class [mscorlib]System.Action M2 ( + object o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 28 (0x1c) + .maxstack 8 + IL_0000: ldsfld class [mscorlib]System.Action Extensions/'<>O'::'<0>__local' + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn void Extensions::'b__1_0'() + IL_0010: newobj instance void [mscorlib]System.Action::.ctor(object, native int) + IL_0015: dup + IL_0016: stsfld class [mscorlib]System.Action Extensions/'<>O'::'<0>__local' + IL_001b: ret + } // end of method Extensions::M2 + .method assembly hidebysig static + void 'b__1_0' () cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2084 + // Code size 17 (0x11) + .maxstack 8 + IL_0000: ldtoken [mscorlib]System.Object + IL_0005: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) + IL_000a: callvirt instance string [mscorlib]System.Object::ToString() + IL_000f: pop + IL_0010: ret + } // end of method Extensions::'b__1_0' +} // end of class Extensions +""".Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); + + var src2 = """ +public static class Extensions +{ + extension(object o) + { + System.Action M2() + { + return local; + + static void local() + { + typeof(object).ToString(); + } + } + } + + extension(object o) + { + System.Action M2(int x) + { + return local; + + static void local() + { + typeof(object).ToString(); + } + } + } +} +"""; + var comp2 = CreateCompilation(src2); + CompileAndVerify(comp2).VerifyDiagnostics(); + } + + [Fact] + public void Implementation_DynamicCallSite_01() + { + var src = """ +public static class Extensions +{ + extension(T o) + { + void M2() + { + #pragma warning disable CS8321 // The local function 'local' is declared but never used + void local(dynamic d, T t, U u, V v) + { + d.M1(t, u, v); + } + } + } +} +"""; + var comp = CreateCompilation(src, targetFramework: TargetFramework.StandardAndCSharp); + var verifier = CompileAndVerify(comp).VerifyDiagnostics(); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Consider executing and verifying behavior + + verifier.VerifyTypeIL("Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0`1' + extends [mscorlib]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + !T o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0`1'::'$' + .method private hidebysig + instance void M2 () cil managed + { + // Method begins at RVA 0x20ea + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0`1'::M2 + } // end of class <>E__0`1 + .class nested private auto ansi abstract sealed beforefieldinit '<>o__0|1`3' + extends [mscorlib]System.Object + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field public static class [System.Core]System.Runtime.CompilerServices.CallSite`1> '<>p__0' + } // end of class <>o__0|1`3 + // Methods + .method private hidebysig specialname static + void M2 ( + !!T o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method Extensions::M2 + .method assembly hidebysig static + void 'b__1_0' ( + object d, + !!T t, + !!U u, + !!V v + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + .param [1] + .custom instance void [System.Core]System.Runtime.CompilerServices.DynamicAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x206c + // Code size 114 (0x72) + .maxstack 9 + IL_0000: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1> class Extensions/'<>o__0|1`3'::'<>p__0' + IL_0005: brtrue.s IL_0059 + IL_0007: ldc.i4 256 + IL_000c: ldstr "M1" + IL_0011: ldnull + IL_0012: ldtoken Extensions + IL_0017: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) + IL_001c: ldc.i4.4 + IL_001d: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo + IL_0022: dup + IL_0023: ldc.i4.0 + IL_0024: ldc.i4.0 + IL_0025: ldnull + IL_0026: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string) + IL_002b: stelem.ref + IL_002c: dup + IL_002d: ldc.i4.1 + IL_002e: ldc.i4.1 + IL_002f: ldnull + IL_0030: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string) + IL_0035: stelem.ref + IL_0036: dup + IL_0037: ldc.i4.2 + IL_0038: ldc.i4.1 + IL_0039: ldnull + IL_003a: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string) + IL_003f: stelem.ref + IL_0040: dup + IL_0041: ldc.i4.3 + IL_0042: ldc.i4.1 + IL_0043: ldnull + IL_0044: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string) + IL_0049: stelem.ref + IL_004a: call class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::InvokeMember(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, class [mscorlib]System.Collections.Generic.IEnumerable`1, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1) + IL_004f: call class [System.Core]System.Runtime.CompilerServices.CallSite`1 class [System.Core]System.Runtime.CompilerServices.CallSite`1>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder) + IL_0054: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1> class Extensions/'<>o__0|1`3'::'<>p__0' + IL_0059: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1> class Extensions/'<>o__0|1`3'::'<>p__0' + IL_005e: ldfld !0 class [System.Core]System.Runtime.CompilerServices.CallSite`1>::Target + IL_0063: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1> class Extensions/'<>o__0|1`3'::'<>p__0' + IL_0068: ldarg.0 + IL_0069: ldarg.1 + IL_006a: ldarg.2 + IL_006b: ldarg.3 + IL_006c: callvirt instance void class [mscorlib]System.Action`5::Invoke(!0, !1, !2, !3, !4) + IL_0071: ret + } // end of method Extensions::'b__1_0' +} // end of class Extensions +""".Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]"). + Replace("[System.Core]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[System.Core]")); + + var src2 = """ +public static class Extensions +{ + extension(T o) + { + void M2() + { + #pragma warning disable CS8321 // The local function 'local' is declared but never used + void local(dynamic d, T t, U u, V v) + { + d.M1(t, u, v); + } + } + } + + extension(T o) + { + void M2(int x) + { + void local(dynamic d, T t, U u, V v) + { + d.M1(t, u, v); + } + } + } +} +"""; + var comp2 = CreateCompilation(src2, targetFramework: TargetFramework.StandardAndCSharp); + CompileAndVerify(comp2).VerifyDiagnostics(); + } + + [Fact] + public void Implementation_DynamicCallSite_02() + { + var src = """ +public static class Extensions +{ + extension(T o) + { + void M2() + { + #pragma warning disable CS8321 // The local function 'local' is declared but never used + void local(dynamic d, T t) + { + d.M1(t); + } + } + } +} +"""; + var comp = CreateCompilation(src, targetFramework: TargetFramework.StandardAndCSharp); + var verifier = CompileAndVerify(comp).VerifyDiagnostics(); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Consider executing and verifying behavior + + verifier.VerifyTypeIL("Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0`1' + extends [mscorlib]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + !T o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0`1'::'$' + .method private hidebysig + instance void M2 () cil managed + { + // Method begins at RVA 0x20d4 + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0`1'::M2 + } // end of class <>E__0`1 + .class nested private auto ansi abstract sealed beforefieldinit '<>o__1`1' + extends [mscorlib]System.Object + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field public static class [System.Core]System.Runtime.CompilerServices.CallSite`1> '<>p__0' + } // end of class <>o__1`1 + // Methods + .method private hidebysig specialname static + void M2 ( + !!T o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method Extensions::M2 + .method assembly hidebysig static + void 'b__1_0' ( + object d, + !!T t + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + .param [1] + .custom instance void [System.Core]System.Runtime.CompilerServices.DynamicAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x206c + // Code size 92 (0x5c) + .maxstack 9 + IL_0000: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1> class Extensions/'<>o__1`1'::'<>p__0' + IL_0005: brtrue.s IL_0045 + IL_0007: ldc.i4 256 + IL_000c: ldstr "M1" + IL_0011: ldnull + IL_0012: ldtoken Extensions + IL_0017: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) + IL_001c: ldc.i4.2 + IL_001d: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo + IL_0022: dup + IL_0023: ldc.i4.0 + IL_0024: ldc.i4.0 + IL_0025: ldnull + IL_0026: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string) + IL_002b: stelem.ref + IL_002c: dup + IL_002d: ldc.i4.1 + IL_002e: ldc.i4.1 + IL_002f: ldnull + IL_0030: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string) + IL_0035: stelem.ref + IL_0036: call class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::InvokeMember(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, class [mscorlib]System.Collections.Generic.IEnumerable`1, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1) + IL_003b: call class [System.Core]System.Runtime.CompilerServices.CallSite`1 class [System.Core]System.Runtime.CompilerServices.CallSite`1>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder) + IL_0040: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1> class Extensions/'<>o__1`1'::'<>p__0' + IL_0045: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1> class Extensions/'<>o__1`1'::'<>p__0' + IL_004a: ldfld !0 class [System.Core]System.Runtime.CompilerServices.CallSite`1>::Target + IL_004f: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1> class Extensions/'<>o__1`1'::'<>p__0' + IL_0054: ldarg.0 + IL_0055: ldarg.1 + IL_0056: callvirt instance void class [mscorlib]System.Action`3::Invoke(!0, !1, !2) + IL_005b: ret + } // end of method Extensions::'b__1_0' +} // end of class Extensions +""".Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]"). + Replace("[System.Core]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[System.Core]")); + + var src2 = """ +public static class Extensions +{ + extension(T o) + { + void M2() + { + #pragma warning disable CS8321 // The local function 'local' is declared but never used + void local(dynamic d, T t) + { + d.M1(t); + } + } + } + + extension(T o) + { + void M2(int x) + { + void local(dynamic d, T t) + { + d.M1(t); + } + } + } +} +"""; + var comp2 = CreateCompilation(src2, targetFramework: TargetFramework.StandardAndCSharp); + CompileAndVerify(comp2).VerifyDiagnostics(); + } + + [Fact] + public void Implementation_DynamicCallSite_03() + { + var src = """ +public static class Extensions +{ + extension(object o) + { + void M2() + { + #pragma warning disable CS8321 // The local function 'local' is declared but never used + void local(dynamic d) + { + d.M1(); + } + } + } +} +"""; + var comp = CreateCompilation(src, targetFramework: TargetFramework.StandardAndCSharp); + var verifier = CompileAndVerify(comp).VerifyDiagnostics(); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Consider executing and verifying behavior + + verifier.VerifyTypeIL("Extensions", """ +.class public auto ansi abstract sealed beforefieldinit Extensions + extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed beforefieldinit '<>E__0' + extends [mscorlib]System.Object + { + // Methods + .method private hidebysig specialname static + void '$' ( + object o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>E__0'::'$' + .method private hidebysig + instance void M2 () cil managed + { + // Method begins at RVA 0x20c9 + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } // end of method '<>E__0'::M2 + } // end of class <>E__0 + .class nested private auto ansi abstract sealed beforefieldinit '<>o__1' + extends [mscorlib]System.Object + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field public static class [System.Core]System.Runtime.CompilerServices.CallSite`1> '<>p__0' + } // end of class <>o__1 + // Methods + .method private hidebysig specialname static + void M2 ( + object o + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method Extensions::M2 + .method assembly hidebysig static + void 'b__1_0' ( + object d + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + .param [1] + .custom instance void [System.Core]System.Runtime.CompilerServices.DynamicAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x206c + // Code size 81 (0x51) + .maxstack 9 + IL_0000: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1> Extensions/'<>o__1'::'<>p__0' + IL_0005: brtrue.s IL_003b + IL_0007: ldc.i4 256 + IL_000c: ldstr "M1" + IL_0011: ldnull + IL_0012: ldtoken Extensions + IL_0017: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) + IL_001c: ldc.i4.1 + IL_001d: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo + IL_0022: dup + IL_0023: ldc.i4.0 + IL_0024: ldc.i4.0 + IL_0025: ldnull + IL_0026: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string) + IL_002b: stelem.ref + IL_002c: call class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::InvokeMember(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, class [mscorlib]System.Collections.Generic.IEnumerable`1, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1) + IL_0031: call class [System.Core]System.Runtime.CompilerServices.CallSite`1 class [System.Core]System.Runtime.CompilerServices.CallSite`1>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder) + IL_0036: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1> Extensions/'<>o__1'::'<>p__0' + IL_003b: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1> Extensions/'<>o__1'::'<>p__0' + IL_0040: ldfld !0 class [System.Core]System.Runtime.CompilerServices.CallSite`1>::Target + IL_0045: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1> Extensions/'<>o__1'::'<>p__0' + IL_004a: ldarg.0 + IL_004b: callvirt instance void class [mscorlib]System.Action`2::Invoke(!0, !1) + IL_0050: ret + } // end of method Extensions::'b__1_0' +} // end of class Extensions +""".Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]"). + Replace("[System.Core]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[System.Core]")); + + var src2 = """ +public static class Extensions +{ + extension(object o) + { + void M2() + { + #pragma warning disable CS8321 // The local function 'local' is declared but never used + void local(dynamic d) + { + d.M1(); + } + } + } + + extension(object o) + { + void M2(int x) + { + #pragma warning disable CS8321 // The local function 'local' is declared but never used + void local(dynamic d) + { + d.M1(); + } + } + } +} +"""; + var comp2 = CreateCompilation(src2, targetFramework: TargetFramework.StandardAndCSharp); + CompileAndVerify(comp2).VerifyDiagnostics(); + } + + [Fact] + public void InstanceMethodInvocation_Simple() + { + var src = """ +new object().M(); + +public static class Extensions +{ + extension(object o) + { + public void M() { System.Console.Write("ran"); } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var invocation = GetSyntax(tree, "new object().M()"); + Assert.Equal("void Extensions.<>E__0.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); + } + + [Fact] + public void InstanceMethodInvocation_Inaccessible() + { + var src = """ +new object().M(); + +public static class Extensions +{ + extension(object o) + { + void M() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,14): error CS1061: 'object' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) + // new object().M(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("object", "M").WithLocation(1, 14)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var invocation = GetSyntax(tree, "new object().M()"); + Assert.Null(model.GetSymbolInfo(invocation).Symbol); + Assert.Equal([], model.GetSymbolInfo(invocation).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal([], model.GetMemberGroup(invocation).ToTestDisplayStrings()); + + var memberAccess = GetSyntax(tree, "new object().M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["void Extensions.<>E__0.M()"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(["void Extensions.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + + src = """ +new object().M(); + +public static class Extensions +{ + private static void M(this object o) { } +} +"""; + comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,14): error CS1061: 'object' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) + // new object().M(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("object", "M").WithLocation(1, 14)); + + tree = comp.SyntaxTrees[0]; + model = comp.GetSemanticModel(tree); + invocation = GetSyntax(tree, "new object().M()"); + Assert.Null(model.GetSymbolInfo(invocation).Symbol); + Assert.Equal([], model.GetSymbolInfo(invocation).CandidateSymbols.ToTestDisplayStrings()); + + memberAccess = GetSyntax(tree, "new object().M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["void System.Object.M()"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(["void System.Object.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_Inaccessible_02() + { + var src = """ +new object().M(); + +public static class E1 +{ + extension(object o) + { + void M() { } + } +} +public static class E2 +{ + extension(object o) + { + public void M() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var invocation = GetSyntax(tree, "new object().M()"); + Assert.Equal("void E2.<>E__0.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetMemberGroup(invocation).ToTestDisplayStrings()); + + var memberAccess = GetSyntax(tree, "new object().M"); + Assert.Equal("void E2.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void E2.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + + src = """ +new object().M(); + +public static class E1 +{ + private static void M(this object o) { } +} +public static class E2 +{ + public static void M(this object o) { } +} +"""; + comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + tree = comp.SyntaxTrees[0]; + model = comp.GetSemanticModel(tree); + invocation = GetSyntax(tree, "new object().M()"); + Assert.Equal("void System.Object.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetMemberGroup(invocation).ToTestDisplayStrings()); + + memberAccess = GetSyntax(tree, "new object().M"); + Assert.Equal("void System.Object.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void System.Object.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_GenericReceiverParameter() + { + var src = """ +new object().M(); + +public static class Extensions +{ + extension(T t) + { + public void M() { System.Console.Write("ran"); } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var invocation = GetSyntax(tree, "new object().M()"); + Assert.Equal("void Extensions.<>E__0.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); + + var memberAccess = GetSyntax(tree, "new object().M"); + Assert.Equal(["void Extensions.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void StaticMethodInvocation_GenericReceiverParameter_Constrained() + { + var src = """ +object.M(); +int.M(); +new object().M2(); + +public static class Extensions +{ + extension(T) where T : struct + { + public static void M() { } + } + public static void M2(this T t) where T : struct { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,8): error CS0453: The type 'object' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'Extensions.extension(T)' + // object.M(); + Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "M").WithArguments("Extensions.extension(T)", "T", "object").WithLocation(1, 8), + // (3,14): error CS0453: The type 'object' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'Extensions.M2(T)' + // new object().M2(); + Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "M2").WithArguments("Extensions.M2(T)", "T", "object").WithLocation(3, 14)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var invocation = GetSyntax(tree, "object.M()"); + Assert.Null(model.GetSymbolInfo(invocation).Symbol); + + invocation = GetSyntax(tree, "int.M()"); + Assert.Equal("void Extensions.<>E__0.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); + + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + + memberAccess = GetSyntax(tree, "int.M"); + Assert.Equal(["void Extensions.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void PropertyAccess_GenericReceiverParameter_Constrained() + { + var src = """ +_ = object.P; +_ = int.P; + +public static class E +{ + extension(T) where T : struct + { + public static int P => 0; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,5): error CS9286: 'object' does not contain a definition for 'P' and no accessible extension member 'P' for receiver of type 'object' could be found (are you missing a using directive or an assembly reference?) + // _ = object.P; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "object.P").WithArguments("object", "P").WithLocation(1, 5)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.P"); + Assert.Equal("System.Int32 E.<>E__0.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : handle GetMemberGroup on a property access + + memberAccess = GetSyntax(tree, "int.P"); + Assert.Equal("System.Int32 E.<>E__0.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : handle GetMemberGroup on a property access + } + + [Fact] + public void ReceiverParameter_TypeWithUseSiteError() + { + var lib1_cs = "public class MissingBase { }"; + var comp1 = CreateCompilation(lib1_cs, assemblyName: "missing"); + comp1.VerifyDiagnostics(); + + var lib2_cs = "public class UseSiteError : MissingBase { }"; + var comp2 = CreateCompilation(lib2_cs, [comp1.EmitToImageReference()]); + comp2.VerifyDiagnostics(); + + var src = """ +class C { } +static class Extensions +{ + extension(UseSiteError) { } + extension(C) { } +} + +class C1 +{ + void M(UseSiteError x) { } + void M(C x) { } +} +"""; + var comp = CreateCompilation(src, [comp2.EmitToImageReference()]); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void ReceiverParameter_SuppressConstraintChecksInitially() + { + var text = @" +public class C1 where T : struct { } + +public static class Extensions +{ + extension(C1) { } +} +"; + var comp = CreateCompilation(text); + comp.VerifyEmitDiagnostics( + // (6,18): error CS0453: The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'C1' + // extension(C1) { } + Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "C1").WithArguments("C1", "T", "T").WithLocation(6, 18)); + } + + [Fact] + public void ReceiverParameter_SuppressConstraintChecksInitially_PointerAsTypeArgument() + { + var text = @" +public class C { } + +unsafe static class Extensions +{ + extension(C) { } +} +"; + var comp = CreateCompilation(text, options: TestOptions.UnsafeDebugDll); + comp.VerifyEmitDiagnostics( + // (6,15): error CS0306: The type 'int*' may not be used as a type argument + // extension(C) { } + Diagnostic(ErrorCode.ERR_BadTypeArgument, "C").WithArguments("int*").WithLocation(6, 15)); + } + + [Fact] + public void InstanceMethodInvocation_VariousScopes_Errors() + { + var cSrc = """ +class C +{ + public static void Main() + { + new object().Method(); + _ = new object().Property; + } +} +"""; + + var eSrc = """ +static class Extensions +{ + extension(object o) + { + public void Method() => throw null; + public int Property => throw null; + } +} +"""; + + var src1 = $$""" +namespace N +{ + {{cSrc}} + namespace N2 + { + {{eSrc}} + } +} +"""; + + verify(src1, + // (7,22): error CS1061: 'object' does not contain a definition for 'Method' and no accessible extension method 'Method' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) + // new object().Method(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Method").WithArguments("object", "Method").WithLocation(7, 22), + // (8,26): error CS1061: 'object' does not contain a definition for 'Property' and no accessible extension method 'Property' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) + // _ = new object().Property; + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Property").WithArguments("object", "Property").WithLocation(8, 26)); + + var src2 = $$""" +file {{eSrc}} +"""; + + verify(new[] { cSrc, src2 }, + // 0.cs(5,22): error CS1061: 'object' does not contain a definition for 'Method' and no accessible extension method 'Method' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) + // new object().Method(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Method").WithArguments("object", "Method").WithLocation(5, 22), + // 0.cs(6,26): error CS1061: 'object' does not contain a definition for 'Property' and no accessible extension method 'Property' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) + // _ = new object().Property; + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Property").WithArguments("object", "Property").WithLocation(6, 26)); + + static void verify(CSharpTestSource src, params DiagnosticDescription[] expected) + { + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + comp.VerifyEmitDiagnostics(expected); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var method = GetSyntax(tree, "new object().Method"); + Assert.Null(model.GetSymbolInfo(method).Symbol); + Assert.Empty(model.GetMemberGroup(method)); + + var property = GetSyntax(tree, "new object().Property"); + Assert.Null(model.GetSymbolInfo(property).Symbol); + Assert.Empty(model.GetMemberGroup(property)); + } + } + + [Fact] + public void InstanceMethodInvocation_FromUsingNamespace() + { + var cSrc = """ +class C +{ + public static void Main() + { + new object().Method(); + } +} +"""; + + var eSrc = """ +namespace N2 +{ + static class E + { + extension(object o) + { + public void Method() => throw null; + } + } +} +"""; + + var src1 = $$""" +using N2; +{{cSrc}} + +{{eSrc}} +"""; + verify(src1, "N2.E.<>E__0"); + + var src2 = $$""" +using N2; +using N2; // 1, 2 +{{cSrc}} + +{{eSrc}} +"""; + + var comp = CreateCompilation(src2, options: TestOptions.DebugExe); + comp.VerifyEmitDiagnostics( + // (2,1): hidden CS8019: Unnecessary using directive. + // using N2; // 1, 2 + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using N2;").WithLocation(2, 1), + // (2,7): warning CS0105: The using directive for 'N2' appeared previously in this namespace + // using N2; // 1, 2 + Diagnostic(ErrorCode.WRN_DuplicateUsing, "N2").WithArguments("N2").WithLocation(2, 7) + ); + + var src3 = $$""" +namespace N3 +{ + using N2; + + namespace N4 + { + {{cSrc}} + } + + {{eSrc}} +} +"""; + verify(src3, "N3.N2.E.<>E__0"); + + void verify(string src, string extensionName) + { + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + comp.VerifyEmitDiagnostics(); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : metadata is undone + //CompileAndVerify(comp, expectedOutput: "").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var invocation = GetSyntax(tree, "new object().Method"); + Assert.Equal($$"""void {{extensionName}}.Method()""", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); + Assert.Equal([$$"""void {{extensionName}}.Method()"""], model.GetMemberGroup(invocation).ToTestDisplayStrings()); + } + } + + [Fact] + public void InstanceMethodInvocation_UsingNamespaceNecessity() + { + var src = """ +using N; + +class C +{ + public static void Main() + { + new object().Method(); + } +} + +"""; + var eSrc = """ +namespace N +{ + public static class E + { + extension(object o) + { + public void Method() { System.Console.Write("method"); } + } + } +} +"""; + + var comp = CreateCompilation([src, eSrc], options: TestOptions.DebugExe); + comp.VerifyEmitDiagnostics(); + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : metadata is undone + //CompileAndVerify(comp, expectedOutput: "method"); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var invocation = GetSyntax(tree, "new object().Method"); + Assert.Equal("void N.E.<>E__0.Method()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); + Assert.Equal(["void N.E.<>E__0.Method()"], model.GetMemberGroup(invocation).ToTestDisplayStrings()); + + src = """ +using N; + +class C +{ + public static void Main() { } +} + +namespace N +{ + public static class Extensions + { + extension(object o) + { + public void Method() { } + } + } +} +"""; + + comp = CreateCompilation([src, eSrc]); + comp.VerifyEmitDiagnostics( + // (1,1): hidden CS8019: Unnecessary using directive. + // using N; + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using N;").WithLocation(1, 1)); + } + + [Theory, CombinatorialData] + public void InstanceMethodInvocation_Ambiguity(bool e1BeforeE2) + { + var e1 = """ +static class E1 +{ + extension(object o) + { + public void Method() => throw null; + } +} +"""; + + var e2 = """ +static class E2 +{ + extension(object o) + { + public void Method() => throw null; + } +} +"""; + + var src = $$""" +new object().Method(); + +{{(e1BeforeE2 ? e1 : e2)}} +{{(e1BeforeE2 ? e2 : e1)}} +"""; + var comp = CreateCompilation(src); + if (!e1BeforeE2) + { + comp.VerifyEmitDiagnostics( + // (1,14): error CS0121: The call is ambiguous between the following methods or properties: 'E2.extension(object).Method()' and 'E1.extension(object).Method()' + // new object().Method(); + Diagnostic(ErrorCode.ERR_AmbigCall, "Method").WithArguments("E2.extension(object).Method()", "E1.extension(object).Method()").WithLocation(1, 14)); + } + else + { + comp.VerifyEmitDiagnostics( + // (1,14): error CS0121: The call is ambiguous between the following methods or properties: 'E1.extension(object).Method()' and 'E2.extension(object).Method()' + // new object().Method(); + Diagnostic(ErrorCode.ERR_AmbigCall, "Method").WithArguments("E1.extension(object).Method()", "E2.extension(object).Method()").WithLocation(1, 14)); + } + } + + [Fact] + public void InstanceMethodInvocation_Overloads() + { + var src = """ +new object().Method(42); +new object().Method("hello"); + +static class E1 +{ + extension(object o) + { + public void Method(int i) { System.Console.Write($"E1.Method({i}) "); } + } +} + +static class E2 +{ + extension(object o) + { + public void Method(string s) { System.Console.Write($"E2.Method({s}) "); } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : metadata is undone + //CompileAndVerify(comp, expectedOutput: "E1.Method(42) E2.Method(hello)").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var invocation1 = GetSyntax(tree, "new object().Method(42)"); + Assert.Equal("void E1.<>E__0.Method(System.Int32 i)", model.GetSymbolInfo(invocation1).Symbol.ToTestDisplayString()); + Assert.Empty(model.GetMemberGroup(invocation1)); + + var invocation2 = GetSyntax(tree, """new object().Method("hello")"""); + Assert.Equal("void E2.<>E__0.Method(System.String s)", model.GetSymbolInfo(invocation2).Symbol.ToTestDisplayString()); + Assert.Empty(model.GetMemberGroup(invocation2)); + + var memberAccess1 = GetSyntaxes(tree, "new object().Method").First(); + Assert.Equal(["void E1.<>E__0.Method(System.Int32 i)", "void E2.<>E__0.Method(System.String s)"], model.GetMemberGroup(memberAccess1).ToTestDisplayStrings()); + + var memberAccess2 = GetSyntaxes(tree, "new object().Method").Last(); + Assert.Equal(["void E1.<>E__0.Method(System.Int32 i)", "void E2.<>E__0.Method(System.String s)"], model.GetMemberGroup(memberAccess2).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_Overloads_DifferentScopes_NestedNamespace() + { + var src = """ +namespace N1 +{ + static class E1 + { + extension(object o) + { + public void Method(int i) { System.Console.Write($"E1.Method({i}) "); } + } + } + + namespace N2 + { + static class E2 + { + extension(object o) + { + public void Method(string s) { System.Console.Write($"E2.Method({s}) "); } + } + } + + class C + { + public static void Main() + { + new object().Method(42); + new object().Method("hello"); + } + } + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + comp.VerifyEmitDiagnostics(); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : metadata is undone + //CompileAndVerify(comp, expectedOutput: "E1.Method(42) E2.Method(hello)").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var invocation1 = GetSyntax(tree, "new object().Method(42)"); + Assert.Equal("void N1.E1.<>E__0.Method(System.Int32 i)", model.GetSymbolInfo(invocation1).Symbol.ToTestDisplayString()); + Assert.Empty(model.GetMemberGroup(invocation1)); + + var invocation2 = GetSyntax(tree, """new object().Method("hello")"""); + Assert.Equal("void N1.N2.E2.<>E__0.Method(System.String s)", model.GetSymbolInfo(invocation2).Symbol.ToTestDisplayString()); + Assert.Empty(model.GetMemberGroup(invocation2)); + + var memberAccess1 = GetSyntaxes(tree, "new object().Method").First(); + Assert.Equal(["void N1.N2.E2.<>E__0.Method(System.String s)", "void N1.E1.<>E__0.Method(System.Int32 i)"], model.GetMemberGroup(memberAccess1).ToTestDisplayStrings()); + + var memberAccess2 = GetSyntaxes(tree, "new object().Method").Last(); + Assert.Equal(["void N1.N2.E2.<>E__0.Method(System.String s)", "void N1.E1.<>E__0.Method(System.Int32 i)"], model.GetMemberGroup(memberAccess2).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_NamespaceVsUsing_FromNamespace() + { + var src = """ +using N2; + +new object().Method(42); +new object().Method("hello"); +new object().Method(default); + +static class E1 +{ + extension(object o) + { + public void Method(int i) { System.Console.Write("E1.Method "); } + } +} + +namespace N2 +{ + static class E2 + { + extension(object o) + { + public void Method(string s) { System.Console.Write("E2.Method "); } + } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : metadata is undone + //CompileAndVerify(comp, expectedOutput: "E1.Method E2.Method E1.Method").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var invocation1 = GetSyntax(tree, "new object().Method(42)"); + Assert.Equal("void E1.<>E__0.Method(System.Int32 i)", model.GetSymbolInfo(invocation1).Symbol.ToTestDisplayString()); + Assert.Empty(model.GetMemberGroup(invocation1)); + Assert.Equal(["void E1.<>E__0.Method(System.Int32 i)", "void N2.E2.<>E__0.Method(System.String s)"], model.GetMemberGroup(invocation1.Expression).ToTestDisplayStrings()); + + var invocation2 = GetSyntax(tree, """new object().Method("hello")"""); + Assert.Equal("void N2.E2.<>E__0.Method(System.String s)", model.GetSymbolInfo(invocation2).Symbol.ToTestDisplayString()); + Assert.Empty(model.GetMemberGroup(invocation2)); + Assert.Equal(["void E1.<>E__0.Method(System.Int32 i)", "void N2.E2.<>E__0.Method(System.String s)"], model.GetMemberGroup(invocation2.Expression).ToTestDisplayStrings()); + + var invocation3 = GetSyntax(tree, "new object().Method(default)"); + Assert.Equal("void E1.<>E__0.Method(System.Int32 i)", model.GetSymbolInfo(invocation3).Symbol.ToTestDisplayString()); + Assert.Empty(model.GetMemberGroup(invocation3)); + Assert.Equal(["void E1.<>E__0.Method(System.Int32 i)", "void N2.E2.<>E__0.Method(System.String s)"], model.GetMemberGroup(invocation3.Expression).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_MatchingExtendedType_DerivedDerivedType() + { + var src = """ +new Derived().M(); + +class Base { } +class Derived : Base { } + +static class E +{ + extension(object o) + { + public void M() { System.Console.Write("ran"); } + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var invocation = GetSyntax(tree, "new Derived().M()"); + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); + Assert.Empty(model.GetMemberGroup(invocation)); + + var memberAccess = GetSyntax(tree, "new Derived().M"); + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_MatchingExtendedType_ImplementedInterface() + { + var src = """ +new C().M(); + +interface I { } +class C : I { } + +static class E +{ + extension(I i) + { + public void M() { System.Console.Write("ran"); } + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var invocation = GetSyntax(tree, "new C().M()"); + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); + Assert.Empty(model.GetMemberGroup(invocation)); + + var memberAccess = GetSyntax(tree, "new C().M"); + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_MatchingExtendedType_IndirectlyImplementedInterface() + { + var src = """ +new C().M(); + +interface I { } +interface Indirect : I { } +class C : Indirect { } + +static class E +{ + extension(I i) + { + public void M() { System.Console.Write("ran"); } + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var invocation = GetSyntax(tree, "new C().M()"); + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); + Assert.Empty(model.GetMemberGroup(invocation)); + + var memberAccess = GetSyntax(tree, "new C().M"); + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_MatchingExtendedType_TypeParameterImplementedInterface() + { + var src = """ +class C +{ + void M(T t) where T : I + { + t.M(); + } +} + +interface I { } + +static class E +{ + extension(I i) + { + public void M() { System.Console.Write("ran"); } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var invocation = GetSyntax(tree, "t.M()"); + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); + + var memberAccess = GetSyntax(tree, "t.M"); + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void StaticMethodInvocation_MatchingExtendedType_TypeParameterImplementedInterface() + { + var src = """ +class C +{ + void M() where T : I + { + T.M(); + } +} + +interface I { } + +static class E +{ + extension(I) + { + public static void M() => throw null; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (5,9): error CS0704: Cannot do non-virtual member lookup in 'T' because it is a type parameter + // T.M(); + Diagnostic(ErrorCode.ERR_LookupInTypeVariable, "T").WithArguments("T").WithLocation(5, 9)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "T.M"); + Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_MatchingExtendedType_TypeParameterWithBaseClass() + { + var src = $$""" +class C { } + +class D +{ + void M(T t) where T : C + { + t.M2(); + } +} + +static class E +{ + extension(C c) + { + public void M2() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : metadata is undone + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var invocation = GetSyntax(tree, "t.M2()"); + Assert.Equal("void E.<>E__0.M2()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); + + var memberAccess = GetSyntax(tree, "t.M2"); + Assert.Equal(["void E.<>E__0.M2()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_MatchingExtendedType_ConstrainedTypeParameter() + { + var src = $$""" +D.M(""); + +class D +{ + public static void M(T t) where T : class + { + t.M2(); + } +} + +static class E1 +{ + extension(T t) where T : struct + { + public void M2() { } + } +} + +static class E2 +{ + extension(T t) where T : class + { + public void M2() { System.Console.Write("ran"); } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var invocation = GetSyntax(tree, "t.M2()"); + Assert.Equal("void E2.<>E__0.M2()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); + + var memberAccess = GetSyntax(tree, "t.M2"); + Assert.Equal(["void E2.<>E__0.M2()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_MatchingExtendedType_BaseType() + { + var src = """ +new object().M(); +new object().M2(); + +static class E +{ + extension(string s) + { + public void M() => throw null; + } + public static void M2(this string s) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,1): error CS1929: 'object' does not contain a definition for 'M' and the best extension method overload 'E.extension(string).M()' requires a receiver of type 'string' + // new object().M(); + Diagnostic(ErrorCode.ERR_BadInstanceArgType, "new object()").WithArguments("object", "M", "E.extension(string).M()", "string").WithLocation(1, 1), + // (2,1): error CS1929: 'object' does not contain a definition for 'M2' and the best extension method overload 'E.M2(string)' requires a receiver of type 'string' + // new object().M2(); + Diagnostic(ErrorCode.ERR_BadInstanceArgType, "new object()").WithArguments("object", "M2", "E.M2(string)", "string").WithLocation(2, 1) + ); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new object().M"); + Assert.Empty(model.GetMemberGroup(memberAccess)); + } + + [Fact] + public void InstanceMethodInvocation_MatchingExtendedType_GenericType() + { + var src = """ +new C().M(); + +class C { } + +static class E +{ + extension(C c) + { + public void M() { System.Console.Write("ran"); } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var invocation = GetSyntax(tree, "new C().M()"); + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); + + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(invocation.Expression).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_MatchingExtendedType_GenericType_GenericMember_01() + { + var src = """ +new C().M(); + +class C { } + +static class E +{ + extension(C c) + { + public void M() { System.Console.Write("ran"); } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,14): error CS1061: 'C' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?) + // new C().M(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("C", "M").WithLocation(1, 14)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var invocation = GetSyntax(tree, "new C().M()"); + Assert.Null(model.GetSymbolInfo(invocation).Symbol); + Assert.Equal([], model.GetMemberGroup(invocation).ToTestDisplayStrings()); + + var memberAccess = GetSyntax(tree, "new C().M"); + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_MatchingExtendedType_GenericType_GenericMember_02() + { + var src = """ +new C().M(); + +class C { } + +static class E +{ + extension(C c) + { + public void M() { System.Console.Write("ran"); } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var invocation = GetSyntax(tree, "new C().M()"); + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetMemberGroup(invocation).ToTestDisplayStrings()); + + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(invocation.Expression).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_MatchingExtendedType_GenericType_GenericMember_OmittedTypeArgument_01() + { + var src = """ +new C().M<,>(); + +class C { } + +static class E +{ + extension(C c) + { + public void M() => throw null; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,1): error CS8389: Omitting the type argument is not allowed in the current context + // new C().M<,>(); + Diagnostic(ErrorCode.ERR_OmittedTypeArgument, "new C().M<,>").WithLocation(1, 1), + // (1,14): error CS1061: 'C' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?) + // new C().M<,>(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M<,>").WithArguments("C", "M").WithLocation(1, 14)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var invocation = GetSyntax(tree, "new C().M<,>()"); + Assert.Null(model.GetSymbolInfo(invocation).Symbol); + Assert.Equal([], model.GetMemberGroup(invocation).ToTestDisplayStrings()); + + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(invocation.Expression).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_MatchingExtendedType_GenericType_GenericMember_OmittedTypeArgument_02() + { + var src = """ +new C().M<,,>(); + +class C { } + +static class E +{ + extension(C c) + { + public void M() => throw null; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,1): error CS8389: Omitting the type argument is not allowed in the current context + // new C().M<,,>(); + Diagnostic(ErrorCode.ERR_OmittedTypeArgument, "new C().M<,,>").WithLocation(1, 1), + // (1,1): error CS1929: 'C' does not contain a definition for 'M' and the best extension method overload 'E.extension(C).M()' requires a receiver of type 'C' + // new C().M<,,>(); + Diagnostic(ErrorCode.ERR_BadInstanceArgType, "new C()").WithArguments("C", "M", "E.extension(C).M()", "C").WithLocation(1, 1)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var invocation = GetSyntax(tree, "new C().M<,,>()"); + Assert.Null(model.GetSymbolInfo(invocation).Symbol); + Assert.Equal([], model.GetMemberGroup(invocation).ToTestDisplayStrings()); + + Assert.Equal([], model.GetMemberGroup(invocation.Expression).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_MatchingExtendedType_GenericType_GenericMember_BrokenConstraint() + { + var src = """ +new C().M(); + +class C { } + +static class E +{ + extension(C c) + { + public void M() where U : struct => throw null; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,14): error CS0453: The type 'string' must be a non-nullable value type in order to use it as parameter 'U' in the generic type or method 'E.extension(C).M()' + // new C().M(); + Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "M").WithArguments("E.extension(C).M()", "U", "string").WithLocation(1, 14)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var invocation = GetSyntax(tree, "new C().M()"); + Assert.Null(model.GetSymbolInfo(invocation).Symbol); + Assert.Equal([], model.GetMemberGroup(invocation).ToTestDisplayStrings()); + Assert.Equal([], model.GetMemberGroup(invocation.Expression).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_MatchingExtendedType_BrokenConstraint() + { + var source = """ +new object().Method(); +new object().Method2(); + +static class E +{ + extension(T t) where T : struct + { + public void Method() { } + } + public static void Method2(this T t) where T : struct { } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (1,14): error CS0453: The type 'object' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'E.extension(T)' + // new object().Method(); + Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "Method").WithArguments("E.extension(T)", "T", "object").WithLocation(1, 14), + // (2,14): error CS0453: The type 'object' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'E.Method2(T)' + // new object().Method2(); + Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "Method2").WithArguments("E.Method2(T)", "T", "object").WithLocation(2, 14) + ); + } + + [Fact] + public void InstanceMethodInvocation_MatchingExtendedType_BrokenConstraint_Nullability() + { + var source = """ +#nullable enable +bool b = true; +var o = b ? null : new object(); +o.Method(); + +static class E +{ + extension(T t) where T : notnull + { + public void Method() { System.Console.Write(t is null); } + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (4,1): warning CS8602: Dereference of a possibly null reference. + // o.Method(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o").WithLocation(4, 1)); + CompileAndVerify(comp, expectedOutput: "True"); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "o.Method"); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Nullability is undone + Assert.Equal("void E.extension(System.Object!).Method()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString(includeNonNullable: true)); + } + + [Fact] + public void ReceiverParameter_AliasType() + { + var source = """ +using Alias = C; + +new Alias().M(); + +class C { } + +static class E +{ + extension(Alias a) + { + public void M() { System.Console.Write("ran"); } + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new Alias().M"); + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void InstanceMethodInvocation_DynamicArgument() + { + // No extension members in dynamic invocation + var src = """ +dynamic d = null; +new object().M(d); +new object().M2(d); + +static class E +{ + extension(object o) + { + public void M(object o1) => throw null; + } + public static void M2(this object o, object o2) => throw null; +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (2,1): error CS1973: 'object' has no applicable method named 'M' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax. + // new object().M(d); + Diagnostic(ErrorCode.ERR_BadArgTypeDynamicExtension, "new object().M(d)").WithArguments("object", "M").WithLocation(2, 1), + // (3,1): error CS1973: 'object' has no applicable method named 'M2' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax. + // new object().M2(d); + Diagnostic(ErrorCode.ERR_BadArgTypeDynamicExtension, "new object().M2(d)").WithArguments("object", "M2").WithLocation(3, 1)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new object().M"); + Assert.Equal(["void E.<>E__0.M(System.Object o1)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_MatchingExtendedType_DynamicDifference_Nested() + { + var src = """ +new C().M(); + +class C { } + +static class E +{ + extension(C c) + { + public void M() + { + System.Console.Write("M"); + } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "M").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new C().M"); + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_MatchingExtendedType_DynamicDifference_InBase() + { + var src = """ +new D().M(); + +class C { } +class D : C { } + +static class E +{ + extension(C c) + { + public void M() + { + System.Console.Write("M"); + } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "M").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new D().M"); + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_MatchingExtendedType_DynamicDifference_InInterface() + { + var src = """ +new D().M(); + +interface I { } +class D : I { } + +static class E +{ + extension(I i) + { + public void M() { System.Console.Write("M"); } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (4,11): error CS1966: 'D': cannot implement a dynamic interface 'I' + // class D : I { } + Diagnostic(ErrorCode.ERR_DeriveFromConstructedDynamic, "I").WithArguments("D", "I").WithLocation(4, 11)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new D().M"); + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_MatchingExtendedType_TupleNamesDifference() + { + var src = """ +new C<(int a, int b)>().M(); +new C<(int, int)>().M(); +new C<(int other, int)>().M(); + +class C { } + +static class E +{ + extension(C<(int a, int b)> c) + { + public void M() { System.Console.Write("M"); } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "MMM").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new C<(int a, int b)>().M"); + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + + memberAccess = GetSyntax(tree, "new C<(int, int)>().M"); + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + + memberAccess = GetSyntax(tree, "new C<(int other, int)>().M"); + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + + src = """ +new C<(int a, int b)>().M(); +new C<(int, int)>().M(); +new C<(int other, int)>().M(); + +class C { } + +static class E +{ + public static void M(this C<(int a, int b)> c) { System.Console.Write("M"); } +} +"""; + comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void InstanceMethodInvocation_MatchingExtendedType_TupleNamesDifference_InBase() + { + var src = """ +new D1().M(); +new D2().M(); +new D3().M(); + +class C { } +class D1 : C<(int a, int b)> { } +class D2 : C<(int, int)> { } +class D3 : C<(int other, int)> { } + +static class E +{ + extension(C<(int a, int b)> c) + { + public void M() { System.Console.Write("M"); } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "MMM").VerifyDiagnostics(); + } + + [Fact] + public void InstanceMethodInvocation_MatchingExtendedType_TupleNamesDifference_InInterface() + { + var src = """ +new D1().M(); +new D2().M(); +new D3().M(); + +class I { } +class D1 : I<(int a, int b)> { } +class D2 : I<(int, int)> { } +class D3 : I<(int other, int)> { } + +static class E +{ + extension(I<(int a, int b)> i) + { + public void M() { System.Console.Write("M"); } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "MMM").VerifyDiagnostics(); + } + + [Fact] + public void InstanceMethodInvocation_Nameof() + { + var src = """ +object o = null; +System.Console.Write($"{nameof(o.M)} "); + +static class E +{ + extension(object) + { + public void M() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (2,32): error CS8093: Extension method groups are not allowed as an argument to 'nameof'. + // System.Console.Write($"{nameof(o.M)} "); + Diagnostic(ErrorCode.ERR_NameofExtensionMethod, "o.M").WithLocation(2, 32)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "o.M"); + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_Nameof_ViaType() + { + var src = """ +System.Console.Write($"{nameof(E.M)} "); + +static class E +{ + extension(object) + { + public void M() { } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "M").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "E.M"); + Assert.Equal(["void E.M(this System.Object)", "void E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_Nameof_Overloads() + { + var src = """ +object o = null; +System.Console.Write($"{nameof(o.M)} "); + +static class E +{ + extension(object o) + { + public void M() { } + public void M(int i) { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (2,32): error CS8093: Extension method groups are not allowed as an argument to 'nameof'. + // System.Console.Write($"{nameof(o.M)} "); + Diagnostic(ErrorCode.ERR_NameofExtensionMethod, "o.M").WithLocation(2, 32)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "o.M"); + Assert.Equal(["void E.<>E__0.M()", "void E.<>E__0.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_Nameof_SimpleName() + { + var src = """ +class C +{ + void M() + { + _ = nameof(Method); + } +} + +static class E +{ + extension(object o) + { + public void Method() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (5,20): error CS0103: The name 'Method' does not exist in the current context + // _ = nameof(Method); + Diagnostic(ErrorCode.ERR_NameNotInContext, "Method").WithArguments("Method").WithLocation(5, 20)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var identifier = GetSyntax(tree, "Method"); + Assert.Equal([], model.GetMemberGroup(identifier).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_Null_Method() + { + var src = """ +#nullable enable + +object? o = null; +o.Method(); + +static class E +{ + extension(object o) + { + public void Method() { System.Console.Write("Method"); } + } +} +"""; + var comp = CreateCompilation(src); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : nullability is undone + comp.VerifyEmitDiagnostics( + // (4,1): warning CS8602: Dereference of a possibly null reference. + // o.Method(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o").WithLocation(4, 1)); + + CompileAndVerify(comp, expectedOutput: "Method"); + } + + [Fact] + public void InstanceMethodInvocation_ColorColor_Method() + { + var src = """ +C.M(new C()); + +class C +{ + public static void M(C C) + { + C.Method(); + } +} + +static class E +{ + extension(C c) + { + public void Method() { System.Console.Write("Method "); } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "Method").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "C.Method"); + Assert.Equal("void E.<>E__0.Method()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.Method()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_ColorColor_Static_Method() + { + var src = """ +C.M(null); + +class C +{ + public static void M(C C) + { + C.Method(); + } +} + +static class E +{ + extension(C c) + { + public void Method() { System.Console.Write("Method"); } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + CompileAndVerify(comp, expectedOutput: "Method").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "C.Method"); + Assert.Equal("void E.<>E__0.Method()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.Method()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_PatternBased_ForEach_NoMethod() + { + var src = """ +foreach (var x in new C()) +{ + System.Console.Write(x); + break; +} + +class C { } +class D { } + +static class E +{ + extension(C c) + { + public D GetEnumerator() => new D(); + } + + extension(D d) + { + public bool MoveNext() => true; + public int Current => 42; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,19): error CS0117: 'D' does not contain a definition for 'Current' + // foreach (var x in new C()) + Diagnostic(ErrorCode.ERR_NoSuchMember, "new C()").WithArguments("D", "Current").WithLocation(1, 19), + // (1,19): error CS0202: foreach requires that the return type 'D' of 'E.extension(C).GetEnumerator()' must have a suitable public 'MoveNext' method and public 'Current' property + // foreach (var x in new C()) + Diagnostic(ErrorCode.ERR_BadGetEnumerator, "new C()").WithArguments("D", "E.extension(C).GetEnumerator()").WithLocation(1, 19) + ); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var loop = tree.GetRoot().DescendantNodes().OfType().Single(); + Assert.Null(model.GetForEachStatementInfo(loop).GetEnumeratorMethod); + Assert.Null(model.GetForEachStatementInfo(loop).MoveNextMethod); + Assert.Null(model.GetForEachStatementInfo(loop).CurrentProperty); + } + + [Fact] + public void InstanceMethodInvocation_NameOf_SingleParameter() + { + var src = """ +class C +{ + public static void Main() + { + string x = ""; + System.Console.Write(nameof(x)); + } +} + + +static class E +{ + extension(C c) + { + public string nameof(string s) => throw null; + } +} +"""; + + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: "x").VerifyDiagnostics(); + } + + [Fact] + public void InstanceMethodInvocation_Simple_ExpressionTree() + { + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : decide whether to allow expression tree scenarios. Verify shape of the tree if we decide to allow + var source = """ +using System.Linq.Expressions; +Expression x = () => new C().M(42); + +class C +{ + public void M() => throw null; +} + +static class E +{ + extension(C c) + { + public void M(int i) { System.Console.Write("E.M"); } + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : metadata is undone + //CompileAndVerify(comp, expectedOutput: "").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new C().M"); + Assert.Equal("void E.<>E__0.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void C.M()", "void E.<>E__0.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_NextScope() + { + // If overload resolution on extension type methods yields no applicable candidates, + // we look in the next scope. + var source = """ +using N; + +new C().M(42); + +class C +{ + public void M() => throw null; +} + +static class E1 +{ + extension(C c) + { + public void M(string s) => throw null; + } +} + +namespace N +{ + static class E2 + { + extension(C c) + { + public void M(int i) { System.Console.Write($"E2.M({i})"); } + } + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "E2.M(42)"); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new C().M"); + Assert.Equal("void N.E2.<>E__0.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void C.M()", "void E1.<>E__0.M(System.String s)", "void N.E2.<>E__0.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_NewExtensionPriority() + { + var source = """ +new C().M(42); + +class C +{ + public void M() => throw null; +} + +static class E1 +{ + extension(C c) + { + public void M(int i) => throw null; + } +} + +static class E2 +{ + public static void M(this C c, int i) => throw null; +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (1,9): error CS0121: The call is ambiguous between the following methods or properties: 'E1.extension(C).M(int)' and 'E2.M(C, int)' + // new C().M(42); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("E1.extension(C).M(int)", "E2.M(C, int)").WithLocation(1, 9)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new C().M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["void C.M()", "void E1.<>E__0.M(System.Int32 i)", "void C.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_NewExtensionPriority_02() + { + var source = """ +new C().M(42); + +class C +{ + public void M() => throw null; +} + +static class E +{ + extension(C c) + { + public void M(int i) => throw null; + } + public static void M(this C c, int i) => throw null; +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (1,9): error CS0121: The call is ambiguous between the following methods or properties: 'E.extension(C).M(int)' and 'E.M(C, int)' + // new C().M(42); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("E.extension(C).M(int)", "E.M(C, int)").WithLocation(1, 9), + // (12,21): error CS0111: Type 'E' already defines a member called 'M' with the same parameter types + // public void M(int i) => throw null; + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M").WithArguments("M", "E").WithLocation(12, 21) + ); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new C().M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["void C.M()", "void E.<>E__0.M(System.Int32 i)", "void C.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_FallbackToExtensionMethod() + { + // The extension method is picked up if extension declaration candidates were not applicable + var source = """ +new C().M(42); + +class C +{ + public static void M() => throw null; +} + +static class E1 +{ + extension(C c) + { + public void M(string s) => throw null; + public void M(char c1) => throw null; + } +} + +static class E2 +{ + public static void M(this C c, int i) { System.Console.Write($"E2.M({i})"); } +} +"""; + var comp = CreateCompilation(source); + + CompileAndVerify(comp, expectedOutput: "E2.M(42)"); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new C().M"); + Assert.Equal("void C.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void C.M()", "void E1.<>E__0.M(System.String s)", "void E1.<>E__0.M(System.Char c1)", "void C.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_SimpleName() + { + // Extension invocation comes into play on an invocation on a member access but not an invocation on a simple name + var source = """ +class C +{ + public void M() => throw null; + + void M2() + { + M(42); // 1 + } +} + +static class E +{ + extension(C c) + { + public void M(int i) => throw null; + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // 0.cs(7,9): error CS1501: No overload for method 'M' takes 1 arguments + // M(42); // 1 + Diagnostic(ErrorCode.ERR_BadArgCount, "M").WithArguments("M", "1").WithLocation(7, 9) + ); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var invocation = GetSyntax(tree, "M(42)"); + Assert.Null(model.GetSymbolInfo(invocation).Symbol); + Assert.Empty(model.GetMemberGroup(invocation)); + Assert.Equal(["void C.M()"], model.GetMemberGroup(invocation.Expression).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_ArgumentName() + { + // Instance method with incompatible parameter name is skipped in favor of extension declaration method + var source = """ +new C().M(b: 42); + +class C +{ + public void M(int a) => throw null; +} + +static class E1 +{ + extension(C c) + { + public void M(int b) { System.Console.Write($"E1.M({b})"); } + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + CompileAndVerify(comp, expectedOutput: "E1.M(42)"); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new C().M"); + Assert.Equal("void E1.<>E__0.M(System.Int32 b)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void C.M(System.Int32 a)", "void E1.<>E__0.M(System.Int32 b)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_ArgumentName_02() + { + // Extension declaration method with incompatible parameter name is skipped in favor of extension method + var source = """ +new C().M(c: 42); + +public class C +{ + public static void M(int a) => throw null; +} + +static class E1 +{ + extension(C c) + { + public void M(int b) => throw null; + } +} + +public static class E2 +{ + public static void M(this C self, int c) + { + System.Console.Write($"E2.M({c})"); + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "E2.M(42)").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new C().M"); + Assert.Equal("void C.M(System.Int32 c)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + + Assert.Equal(["void C.M(System.Int32 a)", "void E1.<>E__0.M(System.Int32 b)", "void C.M(System.Int32 c)"], + model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_ArgumentName_03() + { + var source = """ +new object().M(c: 43, b: 42); + +static class E +{ + extension(object o) + { + public void M(int b, int c) { System.Console.Write($"E.M({b}, {c})"); } + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "E.M(42, 43)").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new object().M"); + Assert.Equal("void E.<>E__0.M(System.Int32 b, System.Int32 c)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void InstanceMethodInvocation_ArgumentName_04() + { + var source = """ +new object().M(o: new object()); + +static class E +{ + extension(object o) + { + public void M(object o2) => throw null; + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (1,16): error CS1744: Named argument 'o' specifies a parameter for which a positional argument has already been given + // new object().M(o: new object()); + Diagnostic(ErrorCode.ERR_NamedArgumentUsedInPositional, "o").WithArguments("o").WithLocation(1, 16)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new object().M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + } + + [Fact] + public void InstanceMethodInvocation_RefKind() + { + var source = """ +int i = 42; +int j; + +new object().M(ref i, out j); + +static class E +{ + extension(object o) + { + public void M(ref int b, out int c) { c = 43; System.Console.Write($"E.M({b}, {c})"); } + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "E.M(42, 43)").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new object().M"); + Assert.Equal("void E.<>E__0.M(ref System.Int32 b, out System.Int32 c)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void InstanceMethodInvocation_AmbiguityWithExtensionOnBaseType_PreferMoreSpecific() + { + var source = """ +System.Console.Write(new C().M(42)); + +class Base { } + +class C : Base { } + +static class E1 +{ + extension(Base b) + { + public int M(int i) => throw null; + } +} + +static class E2 +{ + extension(C c) + { + public int M(int i) => i; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new C().M"); + Assert.Equal("System.Int32 E2.<>E__0.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["System.Int32 E1.<>E__0.M(System.Int32 i)", "System.Int32 E2.<>E__0.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + + source = """ +System.Console.Write(new C().M(42)); + +public class Base { } + +public class C : Base { } + +public static class E1 +{ + public static int M(this Base b, int i) => throw null; +} + +public static class E2 +{ + public static int M(this C c, int i) => i; +} +"""; + comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + } + + [Fact] + public void InstanceMethodInvocation_TypeArguments() + { + var source = """ +new C().M(42); + +class C { } + +static class E +{ + extension(C c) + { + public void M(int i) => throw null; + public void M(int i) + { + System.Console.Write("ran"); + } + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new C().M"); + Assert.Equal("void E.<>E__0.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_TypeArguments_WrongNumber() + { + var source = """ +new C().M(42); + +class C { } + +static class E +{ + extension(C c) + { + public void M(int i) => throw null; + public void M(int i) => throw null; + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // 0.cs(1,9): error CS1061: 'C' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?) + // new C().M(42); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("C", "M").WithLocation(1, 9) + ); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new C().M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["void E.<>E__0.M(System.Int32 i)", "void E.<>E__0.M(System.Int32 i)"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(["void E.<>E__0.M(System.Int32 i)", "void E.<>E__0.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_TypeArguments_Omitted() + { + var source = """ +new C().M<>(42); + +class C { } + +static class E +{ + extension(C c) + { + public void M(int i) => throw null; + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (1,1): error CS8389: Omitting the type argument is not allowed in the current context + // new C().M<>(42); + Diagnostic(ErrorCode.ERR_OmittedTypeArgument, "new C().M<>").WithLocation(1, 1) + ); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new C().M<>"); + Assert.Equal("void E.<>E__0.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_TypeArguments_Inferred() + { + // No type arguments passed, but the extension declaration method is found and the type parameter inferred + var source = """ +new C().M(42); + +class C { } + +static class E +{ + extension(C c) + { + public void M(T t) + { + System.Console.Write($"M({t})"); + } + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "M(42)").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new C().M"); + Assert.Equal("void E.<>E__0.M(System.Int32 t)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M(T t)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void StaticMethodInvocation_InstanceExtensionMethod() + { + // The extension method is not static, but the receiver is a type + var source = """ +C.M(); + +class C { } + +static class E +{ + extension(C c) + { + public void M() => throw null; + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (1,1): error CS0120: An object reference is required for the non-static field, method, or property 'E.extension(C).M()' + // C.M(); + Diagnostic(ErrorCode.ERR_ObjectRequired, "C.M").WithArguments("E.extension(C).M()").WithLocation(1, 1)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "C.M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + + source = """ +C.Method(); + +public class C { } + +public static class E +{ + public static void Method(this C c) { } +} +"""; + comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // 0.cs(1,1): error CS0120: An object reference is required for the non-static field, method, or property 'E.Method(C)' + // C.Method(); + Diagnostic(ErrorCode.ERR_ObjectRequired, "C.Method").WithArguments("E.Method(C)").WithLocation(1, 1)); + } + + [Fact] + public void InstanceMethodInvocation_StaticExtensionMethod() + { + // The extension method is static but the receiver is a value + var source = """ +new C().M(); + +class C { } + +static class E +{ + extension(C c) + { + public static void M() => throw null; + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (1,1): error CS0176: Member 'E.extension(C).M()' cannot be accessed with an instance reference; qualify it with a type name instead + // new C().M(); + Diagnostic(ErrorCode.ERR_ObjectProhibited, "new C().M").WithArguments("E.extension(C).M()").WithLocation(1, 1)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new C().M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_GenericType() + { + var src = """ +new C().StaticType(); + +class C { } + +static class E +{ + extension(C c) + { + public static class StaticType { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,14): error CS1061: 'C' does not contain a definition for 'StaticType' and no accessible extension method 'StaticType' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?) + // new C().StaticType(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "StaticType").WithArguments("C", "StaticType").WithLocation(1, 14), + // (9,29): error CS9282: Extension declarations can include only methods or properties + // public static class StaticType { } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "StaticType").WithLocation(9, 29)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new C().StaticType"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(CandidateReason.None, model.GetSymbolInfo(memberAccess).CandidateReason); + Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_RefOmittedComCall() + { + // For COM import type, omitting the ref is allowed + string source = @" +using System; +using System.Runtime.InteropServices; + +[ComImport, Guid(""1234C65D-1234-447A-B786-64682CBEF136"")] +class C { } + +static class E +{ + extension(C c) + { + public void M(ref short p) { } + public void M(sbyte p) { } + public void I(ref int p) { } + } +} + +class X +{ + public static void Goo() + { + short x = 123; + C c = new C(); + c.M(x); + c.I(123); + } +} +"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + } + + [Fact] + public void ParameterCapturing_023_ColorColor_MemberAccess_InstanceAndStatic_ExtensionDeclarationMethods() + { + // See ParameterCapturing_023_ColorColor_MemberAccess_InstanceAndStatic_Method + var source = """ +struct S1(Color Color) +{ + public void Test() + { + Color.M1(this); + } +} + +class Color { } + +static class E +{ + extension(Color c) + { + public void M1(S1 x, int y = 0) { System.Console.WriteLine("instance"); } + + public static void M1(T x) where T : unmanaged { System.Console.WriteLine("static"); } + } +} +"""; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : missing ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver + var comp = CreateCompilation(source, options: TestOptions.ReleaseDll); + comp.VerifyEmitDiagnostics( + //// (5,9): error CS9106: Identifier 'Color' is ambiguous between type 'Color' and parameter 'Color Color' in this context. + //// Color.M1(this); + //Diagnostic(ErrorCode.ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver, "Color").WithArguments("Color", "Color", "Color Color").WithLocation(5, 9) + ); + + Assert.NotEmpty(comp.GetTypeByMetadataName("S1").InstanceConstructors.OfType().Single().GetCapturedParameters()); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "Color.M1"); + Assert.Equal("void E.<>E__0.M1(S1 x, [System.Int32 y = 0])", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ParameterCapturing_023_ColorColor_MemberAccess_InstanceAndStatic_ExtensionDeclarationMembersVsExtensionMethod() + { + var source = """ +public struct S1(Color Color) +{ + public void Test() + { + Color.M1(this); + } +} + +public class Color { } + +public static class E1 +{ + public static void M1(this Color c, S1 x, int y = 0) { System.Console.WriteLine("instance"); } +} + +static class E2 +{ + extension(Color c) + { + public static void M1(T x) where T : unmanaged { System.Console.WriteLine("static"); } + } +} +"""; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : missing ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver + var comp = CreateCompilation(source, options: TestOptions.ReleaseDll); + comp.VerifyEmitDiagnostics( + //// (5,9): error CS9106: Identifier 'Color' is ambiguous between type 'Color' and parameter 'Color Color' in this context. + //// Color.M1(this); + //Diagnostic(ErrorCode.ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver, "Color").WithArguments("Color", "Color", "Color Color").WithLocation(5, 9) + ); + + Assert.NotEmpty(comp.GetTypeByMetadataName("S1").InstanceConstructors.OfType().Single().GetCapturedParameters()); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "Color.M1"); + Assert.Equal("void Color.M1(S1 x, [System.Int32 y = 0])", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void InstanceMethodInvocation_NotOnBase() + { + // Unlike `this`, `base` is not an expression in itself. + // "Extension invocation" and "extension member lookup" do not apply to `base_access` syntax. + var src = """ +class Base { } + +class Derived : Base +{ + void Main() + { + M(); // 1 + base.M(); // 2 + } +} + +static class E +{ + extension(Base b) + { + public void M() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (7,9): error CS0103: The name 'M' does not exist in the current context + // M(); // 1 + Diagnostic(ErrorCode.ERR_NameNotInContext, "M").WithArguments("M").WithLocation(7, 9), + // (8,14): error CS0117: 'Base' does not contain a definition for 'M' + // base.M(); // 2 + Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("Base", "M").WithLocation(8, 14)); + } + + [Fact] + public void LookupKind_Invocation() + { + // Non-invocable extension member in inner scope is skipped in favor of invocable one from outer scope + var src = """ +using N; + +new object().Member(); + +static class E +{ + extension(object o) + { + public int Member => 0; + } +} + +namespace N +{ + static class E2 + { + extension(object o) + { + public void Member() { System.Console.Write("ran "); } + } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new object().Member"); + Assert.Equal("void N.E2.<>E__0.Member()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void InstanceMethodInvocation_Generic_NotUnique() + { + var src = """ +new C().M(); +new C().M(); + +new C().M2(); +new C().M2(); + +class C { } + +static class E +{ + extension(C c) + { + public string M() => "hi"; + } + public static string M2(this C c) => "hi"; +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,26): error CS1061: 'C' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?) + // new C().M(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("C", "M").WithLocation(1, 26), + // (2,26): error CS1061: 'C' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?) + // new C().M(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("C", "M").WithLocation(2, 26), + // (4,26): error CS1061: 'C' does not contain a definition for 'M2' and no accessible extension method 'M2' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?) + // new C().M2(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M2").WithArguments("C", "M2").WithLocation(4, 26), + // (5,26): error CS1061: 'C' does not contain a definition for 'M2' and no accessible extension method 'M2' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?) + // new C().M2(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M2").WithArguments("C", "M2").WithLocation(5, 26)); + } + + [Fact] + public void InstanceMethodInvocation_Generic_NestedTuples() + { + var src = """ +var s = new C<(string, string)>.Nested<(int, int)>().M(); +System.Console.Write(s); + +class C +{ + internal class Nested { } +} + +static class E +{ + extension(C<(T1, T1)>.Nested<(T2, T2)> cn) + { + public string M() => "hi"; + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "hi").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var memberAccess = GetSyntax(tree, "new C<(string, string)>.Nested<(int, int)>().M"); + Assert.Equal("System.String E.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void InstanceMethodInvocation_Generic_PointerArray() + { + var src = """ +unsafe +{ + string s = new C.Nested().M(); + System.Console.Write(s); +} + +unsafe class C +{ + internal class Nested { } +} + +unsafe static class E +{ + extension(C.Nested cn) + where T1 : unmanaged + where T2 : unmanaged + { + public string M() => "hi"; + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.UnsafeDebugExe); + CompileAndVerify(comp, expectedOutput: "hi").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new C.Nested().M"); + Assert.Equal("System.String E.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void InstanceMethodInvocation_Generic_Pointer() + { + var src = """ +unsafe +{ + new C.Nested().M(); + new C.Nested().M2(); +} + +unsafe class C +{ + internal class Nested { } +} + +static class E +{ + extension(C.Nested cn) + { + public string M() => null; + } + public static string M2(this C.Nested cn) => null; +} +"""; + var comp = CreateCompilation(src, options: TestOptions.UnsafeDebugExe); + comp.VerifyEmitDiagnostics( + // (3,37): error CS0306: The type 'long*' may not be used as a type argument + // new C.Nested().M(); + Diagnostic(ErrorCode.ERR_BadTypeArgument, "M").WithArguments("long*").WithLocation(3, 37), + // (3,37): error CS0306: The type 'int*' may not be used as a type argument + // new C.Nested().M(); + Diagnostic(ErrorCode.ERR_BadTypeArgument, "M").WithArguments("int*").WithLocation(3, 37), + // (4,37): error CS0306: The type 'long*' may not be used as a type argument + // new C.Nested().M2(); + Diagnostic(ErrorCode.ERR_BadTypeArgument, "M2").WithArguments("long*").WithLocation(4, 37), + // (4,37): error CS0306: The type 'int*' may not be used as a type argument + // new C.Nested().M2(); + Diagnostic(ErrorCode.ERR_BadTypeArgument, "M2").WithArguments("int*").WithLocation(4, 37) + ); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new C.Nested().M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + } + + [Fact] + public void InstanceMethodInvocation_Generic_FunctionPointer() + { + var src = """ +unsafe +{ + string s = new C[]>.Nested[]>().M(); + System.Console.Write(s); +} + +unsafe class C +{ + internal class Nested { } +} + +unsafe static class E +{ + extension(C[]>.Nested[]> cn) + { + public string M() => "hi"; + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.UnsafeDebugExe); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new C[]>.Nested[]>().M"); + Assert.Equal("System.String E.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void InstanceMethodInvocation_Generic_ForInterface() + { + var src = """ +string s = new C().M(); +System.Console.Write(s); + +class C : I { } +interface I { } + +static class E +{ + extension(I i) + { + public string M() => "hi"; + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "hi").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new C().M"); + Assert.Equal("System.String E.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void InstanceMethodInvocation_Generic_ForBaseInterface() + { + var src = """ +string s = new C().M(); +System.Console.Write(s); + +class C : I { } +interface I : I2 { } +interface I2 { } + +static class E +{ + extension(I2 i) + { + public string M() => "hi"; + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "hi").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new C().M"); + Assert.Equal("System.String E.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void InstanceMethodInvocation_Generic_ForBase() + { + var src = """ +string s = new C().M(); +System.Console.Write(s); + +class Base { } +class C : Base { } + +static class E +{ + extension(Base b) + { + public string M() => "hi"; + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "hi").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new C().M"); + Assert.Equal("System.String E.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void InstanceMethodInvocation_Obsolete() + { + var src = """ +new object().Method(); + +static class E +{ + extension(object o) + { + [System.Obsolete("Method is obsolete", true)] + public void Method() => throw null; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,1): error CS0619: 'E.extension(object).Method()' is obsolete: 'Method is obsolete' + // new object().Method(); + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "new object().Method()").WithArguments("E.extension(object).Method()", "Method is obsolete").WithLocation(1, 1)); + } + + [Fact] + public void InstanceMethodInvocation_BrokenConstraintMethodOuterExtension() + { + var src = """ +static class E2 +{ + extension(object o) + { + public void M() => throw null; + } +} + +namespace Inner +{ + class C + { + public static void Main() + { + new C().M(); + } + } + + static class E1 + { + extension(C c) + { + public string M() where T : struct => throw null; + } + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new C().M"); + Assert.Equal("void E2.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void E2.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethodInvocation_MultipleSubstitutions() + { + var src = """ +new C().M(); + +interface I { } +class C : I, I { } + +static class E +{ + extension(I i) + { + public void M() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,9): error CS1061: 'C' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?) + // new C().M(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("C", "M").WithLocation(1, 9)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new C().M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + Assert.Empty(model.GetMemberGroup(memberAccess)); + } + + [Theory, CombinatorialData] + public void InstanceMethodInvocation_MultipleExtensions(bool e1BeforeE2) + { + var e1 = """ +static class E1 +{ + extension(object o) + { + public string M() => throw null; + } +} +"""; + + var e2 = """ +static class E2 +{ + extension(object o) + { + public string M() => throw null; + } +} +"""; + + var src = $$""" +new object().M(); +{{(e1BeforeE2 ? e1 : e2)}} +{{(e1BeforeE2 ? e2 : e1)}} +"""; + var comp = CreateCompilation(src); + if (!e1BeforeE2) + { + comp.VerifyEmitDiagnostics( + // (1,14): error CS0121: The call is ambiguous between the following methods or properties: 'E2.extension(object).M()' and 'E1.extension(object).M()' + // new object().M(); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("E2.extension(object).M()", "E1.extension(object).M()").WithLocation(1, 14)); + } + else + { + comp.VerifyEmitDiagnostics( + // (1,14): error CS0121: The call is ambiguous between the following methods or properties: 'E1.extension(object).M()' and 'E2.extension(object).M()' + // new object().M(); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("E1.extension(object).M()", "E2.extension(object).M()").WithLocation(1, 14)); + } + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new object().M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + if (e1BeforeE2) + { + Assert.Equal(["System.String E1.<>E__0.M()", "System.String E2.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + else + { + Assert.Equal(["System.String E2.<>E__0.M()", "System.String E1.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + } + + public class ThreePermutationGenerator : IEnumerable + { + private readonly List _data = [ + [0, 1, 2], + [0, 2, 1], + [1, 0, 2], + [1, 2, 0], + [2, 0, 1], + [2, 1, 0]]; + + public IEnumerator GetEnumerator() => _data.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + } + + [Theory, ClassData(typeof(ThreePermutationGenerator))] + public void InstanceMethodInvocation_InterfaceAppearsTwice(int first, int second, int third) + { + string[] segments = [ + """ + static class E1 + { + extension(I1 i) + { + public string M() => null; + } + } + """, + """ + static class E2 + { + extension(I2 i) { } + } + """, + """ + static class E3 + { + extension(C c) { } + } + """]; + + var src = $$""" +System.Console.Write(new C().M()); + +interface I1 { } +interface I2 : I1 { } + +class C : I1, I2 { } + +{{segments[first]}} + +{{segments[second]}} + +{{segments[third]}} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,30): error CS1061: 'C' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?) + // System.Console.Write(new C().M()); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("C", "M").WithLocation(1, 30)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new C().M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + Assert.Empty(model.GetMemberGroup(memberAccess)); + } + + [Fact] + public void InstanceMethodInvocation_SingleStageInference() + { + var src = """ +public class C +{ + public void M(I i, out object o) + { + i.M(out o); + i.M2(out o); + } +} + +public static class E +{ + public static void M(this I i, out T t) { t = default; } +} + +static class E2 +{ + extension(I i) + { + public void M2(out T t) { t = default; } + } +} + +public interface I { } +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var memberAccess1 = GetSyntax(tree, "i.M"); + Assert.Equal("void I.M(out System.Object t)", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetSymbolInfo(memberAccess1).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(["void I.M(out System.String t)"], model.GetMemberGroup(memberAccess1).ToTestDisplayStrings()); + + var memberAccess2 = GetSyntax(tree, "i.M2"); + Assert.Equal("void E2.<>E__0.M2(out System.Object t)", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetSymbolInfo(memberAccess2).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(["void E2.<>E__0.M2(out System.String t)"], model.GetMemberGroup(memberAccess2).ToTestDisplayStrings()); + } + + [Fact] + public void GetCompatibleExtension_Conversion_01() + { + var src = """ +using System.Collections.Generic; + +IEnumerable i = null; +i.M(); +_ = i.P; + +static class E +{ + extension(IEnumerable o) + { + public void M() { System.Console.Write(o is null); } + public int P { get { System.Console.Write(o is null); return 0; } } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "TrueTrue").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var memberAccess = GetSyntax(tree, "i.M"); + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + + memberAccess = GetSyntax(tree, "i.P"); + Assert.Equal("System.Int32 E.<>E__0.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + + src = """ +using System.Collections.Generic; + +IEnumerable i = null; +i.M(); +_ = i.P; + +static class E +{ + extension(IEnumerable o) + { + public static void M() { } + public static int P => throw null; + } +} +"""; + comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics( + // (4,1): error CS1929: 'IEnumerable' does not contain a definition for 'M' and the best extension method overload 'E.extension(IEnumerable).M()' requires a receiver of type 'System.Collections.Generic.IEnumerable' + // i.M(); + Diagnostic(ErrorCode.ERR_BadInstanceArgType, "i").WithArguments("System.Collections.Generic.IEnumerable", "M", "E.extension(System.Collections.Generic.IEnumerable).M()", "System.Collections.Generic.IEnumerable").WithLocation(4, 1), + // (5,5): error CS9286: 'IEnumerable' does not contain a definition for 'P' and no accessible extension member 'P' for receiver of type 'IEnumerable' could be found (are you missing a using directive or an assembly reference?) + // _ = i.P; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "i.P").WithArguments("System.Collections.Generic.IEnumerable", "P").WithLocation(5, 5) + ); + } + + [Fact] + public void GetCompatibleExtension_Conversion_02() + { + var src = """ +string.M(); +_ = string.P; + +static class E +{ + extension(object) + { + public static void M() { System.Console.Write("ran "); } + public static int P { get { System.Console.Write("ran2"); return 0; } } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "ran ran2").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var memberAccess = GetSyntax(tree, "string.M"); + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void GetCompatibleExtension_Conversion_03() + { + var src = """ +int.M(); +_ = int.P; + +static class E +{ + extension(object) + { + public static void M() { System.Console.Write("ran "); } + public static int P { get { System.Console.Write("ran2"); return 0; } } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "ran ran2").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var memberAccess = GetSyntax(tree, "int.M"); + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void GetCompatibleExtension_Conversion_04() + { + var src = """ +int.M(); +42.M2(); + +_ = int.P; +_ = 42.P2; + +static class E +{ + extension(int? i) + { + public static void M() { } + public static int P => 0; + public int P2 => 0; + } + public static void M2(this int? i) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,1): error CS1929: 'int' does not contain a definition for 'M' and the best extension method overload 'E.extension(int?).M()' requires a receiver of type 'int?' + // int.M(); + Diagnostic(ErrorCode.ERR_BadInstanceArgType, "int").WithArguments("int", "M", "E.extension(int?).M()", "int?").WithLocation(1, 1), + // (2,1): error CS1929: 'int' does not contain a definition for 'M2' and the best extension method overload 'E.M2(int?)' requires a receiver of type 'int?' + // 42.M2(); + Diagnostic(ErrorCode.ERR_BadInstanceArgType, "42").WithArguments("int", "M2", "E.M2(int?)", "int?").WithLocation(2, 1), + // (4,5): error CS9286: 'int' does not contain a definition for 'P' and no accessible extension member 'P' for receiver of type 'int' could be found (are you missing a using directive or an assembly reference?) + // _ = int.P; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "int.P").WithArguments("int", "P").WithLocation(4, 5), + // (5,5): error CS9286: 'int' does not contain a definition for 'P2' and no accessible extension member 'P2' for receiver of type 'int' could be found (are you missing a using directive or an assembly reference?) + // _ = 42.P2; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "42.P2").WithArguments("int", "P2").WithLocation(5, 5)); + } + + [Fact] + public void GetCompatibleExtension_Conversion_05() + { + var src = """ +MyEnum.Zero.M(); + +enum MyEnum { Zero } + +static class E +{ + extension(System.Enum e) + { + public void M() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void GetCompatibleExtension_Conversion_06() + { + var src = """ +dynamic d = new C(); +d.M(); +d.M2(); + +static class E +{ + extension(object o) + { + public void M() => throw null; + } + + public static void M2(this object o) => throw null; +} + +class C +{ + public void M() { System.Console.Write("ran "); } + public void M2() { System.Console.Write("ran2"); } +} +"""; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("ran ran2"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); + } + + [Fact] + public void GetCompatibleExtension_Conversion_07() + { + var src = """ +object o = null; +o.M(); +o.M2(); + +static class E +{ + extension(dynamic d) + { + public void M() { } + } + + public static void M2(this dynamic d) { } +} +"""; + var comp = CreateCompilation(src); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : validate extension parameter + comp.VerifyEmitDiagnostics( + // (12,32): error CS1103: The first parameter of an extension method cannot be of type 'dynamic' + // public static void M2(this dynamic d) { } + Diagnostic(ErrorCode.ERR_BadTypeforThis, "dynamic").WithArguments("dynamic").WithLocation(12, 32)); + } + + [Fact] + public void GetCompatibleExtension_Conversion_08() + { + var src = """ +(int a, int b) t = default; +t.M(); +t.M2(); + +static class E +{ + extension((int c, int d) t) + { + public void M() { } + } + + public static void M2(this (int c, int d) t) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void GetCompatibleExtension_Conversion_09() + { + var src = """ +int[] i = default; +i.M(); +i.M2(); + +static class E +{ + extension(System.ReadOnlySpan ros) + { + public void M() { } + } + + public static void M2(this System.ReadOnlySpan ros) { } +} +"""; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void GetCompatibleExtension_Conversion_10() + { + var missingSrc = """ +public class Missing { } +"""; + var missingRef = CreateCompilation(missingSrc, assemblyName: "missing").EmitToImageReference(); + + var derivedSrc = """ +public class Derived : Missing { } +"""; + var derivedRef = CreateCompilation(derivedSrc, references: [missingRef]).EmitToImageReference(); + + var src = """ +new Derived().M(); +new Derived().M2(); + +class Other { } + +static class E +{ + extension(Other o) + { + public void M() { } + } + + public static void M2(this Other o) { } +} +"""; + var comp = CreateCompilation(src, references: [derivedRef]); + comp.VerifyEmitDiagnostics( + // (1,1): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // new Derived().M(); + Diagnostic(ErrorCode.ERR_NoTypeDef, "new Derived().M").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(1, 1), + // (1,15): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // new Derived().M(); + Diagnostic(ErrorCode.ERR_NoTypeDef, "M").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(1, 15), + // (2,1): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // new Derived().M2(); + Diagnostic(ErrorCode.ERR_NoTypeDef, "new Derived().M2").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(2, 1), + // (2,15): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // new Derived().M2(); + Diagnostic(ErrorCode.ERR_NoTypeDef, "M2").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(2, 15)); + } + + [Fact] + public void GetCompatibleExtension_Conversion_11() + { + var missingSrc = """ +public class Missing { } +"""; + var missingRef = CreateCompilation(missingSrc, assemblyName: "missing").EmitToImageReference(); + + var derivedSrc = """ +public class Derived : Missing { } +"""; + var derivedRef = CreateCompilation(derivedSrc, references: [missingRef]).EmitToImageReference(); + + var src = """ +new Derived().M(); +new Derived().M2(); + +static class E +{ + extension(Derived d) + { + public void M() { } + } + + public static void M2(this Derived d) { } +} +"""; + var comp = CreateCompilation(src, references: [derivedRef]); + comp.VerifyEmitDiagnostics( + // (1,15): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // new Derived().M(); + Diagnostic(ErrorCode.ERR_NoTypeDef, "M").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(1, 15), + // (2,15): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // new Derived().M2(); + Diagnostic(ErrorCode.ERR_NoTypeDef, "M2").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(2, 15)); + } + + [Fact] + public void GetCompatibleExtension_Conversion_12() + { + var missingSrc = """ +public class Missing { } +"""; + var missingRef = CreateCompilation(missingSrc, assemblyName: "missing").EmitToImageReference(); + + var derivedSrc = """ +public class I { } +public class Derived : I { } +"""; + var derivedRef = CreateCompilation(derivedSrc, references: [missingRef]).EmitToImageReference(); + + var src = """ +new Derived().M(); +new Derived().M2(); + +static class E +{ + extension(I i) + { + public void M() { } + } + + public static void M2(this I i) { } +} +"""; + var comp = CreateCompilation(src, references: [derivedRef]); + comp.VerifyEmitDiagnostics( + // (1,1): error CS1929: 'Derived' does not contain a definition for 'M' and the best extension method overload 'E.extension(I).M()' requires a receiver of type 'I' + // new Derived().M(); + Diagnostic(ErrorCode.ERR_BadInstanceArgType, "new Derived()").WithArguments("Derived", "M", "E.extension(I).M()", "I").WithLocation(1, 1), + // (2,1): error CS1929: 'Derived' does not contain a definition for 'M2' and the best extension method overload 'E.M2(I)' requires a receiver of type 'I' + // new Derived().M2(); + Diagnostic(ErrorCode.ERR_BadInstanceArgType, "new Derived()").WithArguments("Derived", "M2", "E.M2(I)", "I").WithLocation(2, 1)); + } + + [Fact] + public void GetCompatibleExtension_TypeInference_01() + { + var src = """ +I.M(); + +interface I { } + +static class E +{ + extension(I) + { + public static void M() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var memberAccess = GetSyntax(tree, "I.M"); + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void GetCompatibleExtension_TypeInference_02() + { + var src = """ +I.M(); + +interface I { } + +static class E +{ + extension(I) + { + public static void M() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var memberAccess = GetSyntax(tree, "I.M"); + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void GetCompatibleExtension_TypeInference_03() + { + var src = """ +I.M(); + +interface I { } + +static class E +{ + extension(I) + { + public static void M() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,19): error CS1061: 'I' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'I' could be found (are you missing a using directive or an assembly reference?) + // I.M(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("I", "M").WithLocation(1, 19)); + } + + [Fact] + public void GetCompatibleExtension_Constraint_UseSiteInfo_01() + { + var missingSrc = """ +public struct Missing { public int i; } +"""; + var missingRef = CreateCompilation(missingSrc, assemblyName: "missing").EmitToImageReference(); + + var containerSrc = """ +public struct Container { public Missing field; } +"""; + var containerRef = CreateCompilation(containerSrc, references: [missingRef]).EmitToImageReference(); + + var src = """ +Container.M(); + +static class E +{ + extension(T t) where T : unmanaged + { + public static void M() { } + } +} +"""; + var comp = CreateCompilation(src, references: [containerRef]); + comp.VerifyEmitDiagnostics( + // (1,11): error CS8377: The type 'Container' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'E.extension(T)' + // Container.M(); + Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M").WithArguments("E.extension(T)", "T", "Container").WithLocation(1, 11), + // (1,11): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // Container.M(); + Diagnostic(ErrorCode.ERR_NoTypeDef, "M").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(1, 11)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "Container.M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + + src = """ +new Container().M(); + +static class E +{ + public static void M(this T t) where T : unmanaged { } +} +"""; + comp = CreateCompilation(src, references: [containerRef]); + comp.VerifyEmitDiagnostics( + // (1,17): error CS8377: The type 'Container' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'E.M(T)' + // new Container().M(); + Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M").WithArguments("E.M(T)", "T", "Container").WithLocation(1, 17), + // (1,17): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // new Container().M(); + Diagnostic(ErrorCode.ERR_NoTypeDef, "M").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(1, 17)); + + src = """ +new object().M(new Container()); + +static class E +{ + public static void M(this object o, T t) where T : unmanaged { } +} +"""; + comp = CreateCompilation(src, references: [containerRef]); + comp.VerifyEmitDiagnostics( + // (1,14): error CS8377: The type 'Container' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'E.M(object, T)' + // new object().M(new Container()); + Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M").WithArguments("E.M(object, T)", "T", "Container").WithLocation(1, 14), + // (1,14): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // new object().M(new Container()); + Diagnostic(ErrorCode.ERR_NoTypeDef, "M").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(1, 14)); + } + + [Fact] + public void GetCompatibleExtension_Constraint_UseSiteInfo_02() + { + var missingSrc = """ +public struct Missing { public int i; } +"""; + var missingRef = CreateCompilation(missingSrc, assemblyName: "missing").EmitToImageReference(); + + var containerSrc = """ +public struct Container { public Missing field; } +"""; + var containerRef = CreateCompilation(containerSrc, references: [missingRef]).EmitToImageReference(); + + var src = """ +using N; + +Container.M(); + +static class E +{ + extension(T t) where T : unmanaged + { + public static void M(int inapplicable) => throw null; + } +} + +namespace N +{ + static class E2 + { + extension(T t) + { + public static void M() { } + } + } +} +"""; + var comp = CreateCompilation(src, references: [containerRef]); + comp.VerifyEmitDiagnostics(); // The inapplicable candidate gets rejected before we get to check its constraints + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "Container.M"); + Assert.Equal("void N.E2.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + + src = """ +Container.M(); + +static class E +{ + extension(T t) where T : unmanaged + { + public static void M(int inapplicable) => throw null; + } +} +"""; + comp = CreateCompilation(src, references: [containerRef]); + comp.VerifyEmitDiagnostics( + // (1,11): error CS7036: There is no argument given that corresponds to the required parameter 'inapplicable' of 'E.extension(T).M(int)' + // Container.M(); + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "M").WithArguments("inapplicable", "E.extension(T).M(int)").WithLocation(1, 11)); + + src = """ +using N; + +Container.M(); + +static class E +{ + extension(T t) where T : unmanaged + { + public static void M() => throw null; // applicable to arguments + } +} + +namespace N +{ + static class E2 + { + extension(T t) + { + public static void M() => throw null; + } + } +} +"""; + comp = CreateCompilation(src, references: [containerRef]); + comp.VerifyEmitDiagnostics(); + + tree = comp.SyntaxTrees.Single(); + model = comp.GetSemanticModel(tree); + memberAccess = GetSyntax(tree, "Container.M"); + Assert.Equal("void N.E2.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + + src = """ +using N; + +new Container().M(); + +static class E +{ + public static void M(this T t) where T : unmanaged { } +} + +namespace N +{ + static class E2 + { + public static void M(this T t) { } + } +} +"""; + // Expecting an error to be reported since we're not able to check whether the constraint is violated + // Tracked by https://github.com/dotnet/roslyn/issues/77407 + comp = CreateCompilation(src, references: [containerRef]); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void GetCompatibleExtension_Constraint_UseSiteInfo_03() + { + var missingSrc = """ +public struct Missing { public int i; } +"""; + var missingRef = CreateCompilation(missingSrc, assemblyName: "missing").EmitToImageReference(); + + var containerSrc = """ +public struct Container { public Missing field; } +"""; + var containerRef = CreateCompilation(containerSrc, references: [missingRef]).EmitToImageReference(); + + var src = """ +int.M(new Container()); + +static class E +{ + extension(int) + { + public static void M(T t) where T : unmanaged { } + } +} +"""; + var comp = CreateCompilation(src, references: [containerRef]); + comp.VerifyEmitDiagnostics( + // (1,5): error CS8377: The type 'Container' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'E.extension(int).M(T)' + // int.M(new Container()); + Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M").WithArguments("E.extension(int).M(T)", "T", "Container").WithLocation(1, 5), + // (1,5): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // int.M(new Container()); + Diagnostic(ErrorCode.ERR_NoTypeDef, "M").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(1, 5)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "int.M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + } + + [Fact] + public void InstancePropertyAccess_Simple() + { + var src = """ +System.Console.Write(new object().P); + +public static class Extensions +{ + extension(object o) + { + public int P => 42; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new object().P"); + Assert.Equal("System.Int32 Extensions.<>E__0.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + } + + [Fact] + public void InstancePropertyAccess_StaticExtensionProperty() + { + var src = """ +System.Console.Write(new object().P); + +public static class Extensions +{ + extension(object o) + { + public static int P => 42; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,22): error CS9286: 'object' does not contain a definition for 'P' and no accessible extension member 'P' for receiver of type 'object' could be found (are you missing a using directive or an assembly reference?) + // System.Console.Write(new object().P); + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "new object().P").WithArguments("object", "P").WithLocation(1, 22)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new object().P"); + Assert.Equal("System.Int32 Extensions.<>E__0.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + } + + [Fact] + public void InstancePropertyAccess_Invoked() + { + var src = """ +new object().P(); + +public static class Extensions +{ + extension(object o) + { + public int P => 42; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,14): error CS1061: 'object' does not contain a definition for 'P' and no accessible extension method 'P' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) + // new object().P(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "P").WithArguments("object", "P").WithLocation(1, 14)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var invocation = GetSyntax(tree, "new object().P()"); + Assert.Null(model.GetSymbolInfo(invocation).Symbol); + Assert.Equal([], model.GetSymbolInfo(invocation).CandidateSymbols.ToTestDisplayStrings()); + + Assert.Equal(["System.Int32 Extensions.<>E__0.P { get; }"], model.GetMemberGroup(invocation.Expression).ToTestDisplayStrings()); + } + + [Fact] + public void InstancePropertyAccess_Invoked_Invocable() + { + var src = """ +new object().P(); + +public static class Extensions +{ + extension(object o) + { + public System.Action P { get { return () => { System.Console.Write("ran"); }; } } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new object().P"); + Assert.Equal("System.Action Extensions.<>E__0.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : handle GetMemberGroup on a property access + } + + [Fact] + public void StaticMethodInvocation_Simple() + { + var src = """ +object.M(); + +public static class Extensions +{ + extension(object) + { + public static int M() => 42; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var invocation = GetSyntax(tree, "object.M()"); + Assert.Equal("System.Int32 Extensions.<>E__0.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetSymbolInfo(invocation).CandidateSymbols.ToTestDisplayStrings()); + } + + [Fact] + public void StaticMethodInvocation_TypeArguments() + { + var source = """ +C.M(42); + +class C { } + +static class E +{ + extension(C) + { + public static void M(int i) => throw null; + public static void M(int i) { System.Console.Write("ran"); } + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran"); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "C.M"); + Assert.Equal("void E.<>E__0.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Theory, CombinatorialData] + public void StaticMethodInvocation_Ambiguity_Method(bool e1BeforeE2) + { + var e1 = """ +static class E1 +{ + extension(object) + { + public static void Method() => throw null; + } +} +"""; + + var e2 = """ +static class E2 +{ + extension(object) + { + public static void Method() => throw null; + } +} +"""; + + var src = $$""" +object.Method(); + +{{(e1BeforeE2 ? e1 : e2)}} +{{(e1BeforeE2 ? e2 : e1)}} +"""; + var comp = CreateCompilation(src); + if (!e1BeforeE2) + { + comp.VerifyEmitDiagnostics( + // (1,8): error CS0121: The call is ambiguous between the following methods or properties: 'E2.extension(object).Method()' and 'E1.extension(object).Method()' + // object.Method(); + Diagnostic(ErrorCode.ERR_AmbigCall, "Method").WithArguments("E2.extension(object).Method()", "E1.extension(object).Method()").WithLocation(1, 8)); + } + else + { + comp.VerifyEmitDiagnostics( + // (1,8): error CS0121: The call is ambiguous between the following methods or properties: 'E1.extension(object).Method()' and 'E2.extension(object).Method()' + // object.Method(); + Diagnostic(ErrorCode.ERR_AmbigCall, "Method").WithArguments("E1.extension(object).Method()", "E2.extension(object).Method()").WithLocation(1, 8)); + } + } + + [Fact] + public void StaticPropertyAccess_InstanceExtensionProperty() + { + var src = """ +System.Console.Write(new object().P); + +public static class Extensions +{ + extension(object o) + { + public static int P => 42; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,22): error CS9286: 'object' does not contain a definition for 'P' and no accessible extension member 'P' for receiver of type 'object' could be found (are you missing a using directive or an assembly reference?) + // System.Console.Write(new object().P); + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "new object().P").WithArguments("object", "P").WithLocation(1, 22)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new object().P"); + Assert.Equal("System.Int32 Extensions.<>E__0.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + } + + [Fact] + public void ResolveAll_ConditionalOperator_Static_ExtensionMethod() + { + var source = """ +bool b = true; +var x = b ? object.M : object.M; + +static class E +{ + extension(object o) + { + public static void M() { } + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (2,9): error CS0173: Type of conditional expression cannot be determined because there is no implicit conversion between 'method group' and 'method group' + // var x = b ? object.M : object.M; + Diagnostic(ErrorCode.ERR_InvalidQM, "b ? object.M : object.M").WithArguments("method group", "method group").WithLocation(2, 9)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntaxes(tree, "object.M").ToArray(); + Assert.Null(model.GetSymbolInfo(memberAccess[0]).Symbol); + Assert.Null(model.GetSymbolInfo(memberAccess[1]).Symbol); + + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(memberAccess[0]).ToTestDisplayStrings()); + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(memberAccess[1]).ToTestDisplayStrings()); + } + + [Fact] + public void ResolveAll_ConditionalOperator_Static_ExtensionProperty() + { + var source = """ +bool b = true; +var x = b ? object.StaticProperty : object.StaticProperty; +System.Console.Write(x); + +static class E +{ + extension(object o) + { + public static int StaticProperty => 42; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntaxes(tree, "object.StaticProperty").ToArray(); + Assert.Equal("System.Int32 E.<>E__0.StaticProperty { get; }", model.GetSymbolInfo(memberAccess[0]).Symbol.ToTestDisplayString()); + Assert.Equal("System.Int32 E.<>E__0.StaticProperty { get; }", model.GetSymbolInfo(memberAccess[1]).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_ConditionalOperator_Static_DifferentTypes() + { + var source = """ +bool b = true; +var x = b ? object.StaticProperty : object.StaticProperty2; +System.Console.Write(x.ToString()); + +static class E +{ + extension(object o) + { + public static int StaticProperty => 42; + public static long StaticProperty2 => 43; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.StaticProperty"); + Assert.Equal("System.Int32 E.<>E__0.StaticProperty { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + + Assert.Equal("System.Int32", model.GetTypeInfo(memberAccess).Type.ToTestDisplayString()); + Assert.Equal("System.Int64", model.GetTypeInfo(memberAccess).ConvertedType.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_ConditionalOperator_Static_WithTargetType() + { + var source = """ +bool b = true; +long x = b ? object.StaticProperty : object.StaticProperty; +System.Console.Write(x.ToString()); + +static class E +{ + extension(object o) + { + public static int StaticProperty => 42; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntaxes(tree, "object.StaticProperty").ToArray(); + Assert.Equal("System.Int32 E.<>E__0.StaticProperty { get; }", model.GetSymbolInfo(memberAccess[0]).Symbol.ToTestDisplayString()); + Assert.Equal("System.Int32 E.<>E__0.StaticProperty { get; }", model.GetSymbolInfo(memberAccess[1]).Symbol.ToTestDisplayString()); + + Assert.Equal("System.Int32", model.GetTypeInfo(memberAccess[0]).Type.ToTestDisplayString()); + Assert.Equal("System.Int32", model.GetTypeInfo(memberAccess[0]).ConvertedType.ToTestDisplayString()); + + Assert.Equal("System.Int32", model.GetTypeInfo(memberAccess[1]).Type.ToTestDisplayString()); + Assert.Equal("System.Int32", model.GetTypeInfo(memberAccess[1]).ConvertedType.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_ConditionalOperator_Static_TwoExtensions_WithTargetType() + { + var source = """ +bool b = true; +string x = b ? D.f : D.f; +System.Console.Write(x); + +class D { } + +static class E1 +{ + extension(D) + { + public static string f => "ran"; + } +} + +static class E2 +{ + extension(object o) + { + public static void f() { } + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (2,16): error CS9286: 'D' does not contain a definition for 'f' and no accessible extension member 'f' for receiver of type 'D' could be found (are you missing a using directive or an assembly reference?) + // string x = b ? D.f : D.f; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "D.f").WithArguments("D", "f").WithLocation(2, 16), + // (2,22): error CS9286: 'D' does not contain a definition for 'f' and no accessible extension member 'f' for receiver of type 'D' could be found (are you missing a using directive or an assembly reference?) + // string x = b ? D.f : D.f; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "D.f").WithArguments("D", "f").WithLocation(2, 22)); + } + + [Fact] + public void ResolveAll_ConditionalOperator_Static_TwoExtensions_WithTargetDelegateType() + { + var source = """ +bool b = true; +System.Action x = b ? D.f : D.f; +System.Console.Write(x); + +class D { } + +static class E +{ + extension(D) + { + public static string f => null; + } +} + +static class E2 +{ + extension(object o) + { + public static void f() { } + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (2,23): error CS9286: 'D' does not contain a definition for 'f' and no accessible extension member 'f' for receiver of type 'D' could be found (are you missing a using directive or an assembly reference?) + // System.Action x = b ? D.f : D.f; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "D.f").WithArguments("D", "f").WithLocation(2, 23), + // (2,29): error CS9286: 'D' does not contain a definition for 'f' and no accessible extension member 'f' for receiver of type 'D' could be found (are you missing a using directive or an assembly reference?) + // System.Action x = b ? D.f : D.f; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "D.f").WithArguments("D", "f").WithLocation(2, 29)); + } + + [Fact] + public void ResolveAll_Cast_Static_Operand() + { + var source = """ +var x = (long)object.StaticProperty; +System.Console.Write(x.ToString()); + +static class E +{ + extension(object o) + { + public static int StaticProperty => 42; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.StaticProperty"); + Assert.Equal("System.Int32 E.<>E__0.StaticProperty { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + + Assert.Equal("System.Int32", model.GetTypeInfo(memberAccess).Type.ToTestDisplayString()); + Assert.Equal("System.Int32", model.GetTypeInfo(memberAccess).ConvertedType.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_Cast_Static_Operand_TwoExtensions() + { + var source = """ +var x = (string)D.f; +System.Console.Write(x); + +class D { } + +static class E1 +{ + extension(D) + { + public static string f => "ran"; + } +} + +static class E2 +{ + extension(object) + { + public static void f() { } + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (1,17): error CS9286: 'D' does not contain a definition for 'f' and no accessible extension member 'f' for receiver of type 'D' could be found (are you missing a using directive or an assembly reference?) + // var x = (string)D.f; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "D.f").WithArguments("D", "f").WithLocation(1, 17)); + } + + [Fact] + public void ResolveAll_Cast_Static_Operand_TwoExtensions_DelegateType() + { + var source = """ +var x = (System.Action)D.f; +System.Action a = D.f; + +class D { } + +static class E1 +{ + extension(D) + { + public static string f => null; + } +} + +static class E2 +{ + extension(object) + { + public static void f() => throw null; + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (1,24): error CS9286: 'D' does not contain a definition for 'f' and no accessible extension member 'f' for receiver of type 'D' could be found (are you missing a using directive or an assembly reference?) + // var x = (System.Action)D.f; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "D.f").WithArguments("D", "f").WithLocation(1, 24), + // (2,19): error CS9286: 'D' does not contain a definition for 'f' and no accessible extension member 'f' for receiver of type 'D' could be found (are you missing a using directive or an assembly reference?) + // System.Action a = D.f; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "D.f").WithArguments("D", "f").WithLocation(2, 19)); + + // Note: a conversion to a delegate type does not provide invocation context for resolving the member access + source = """ +var x = (System.Action)D.f; +System.Action a = D.f; + +class C +{ + public static void f() { } +} + +class D : C +{ + public static new string f => null!; +} +"""; + comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (1,9): error CS0030: Cannot convert type 'string' to 'System.Action' + // var x = (System.Action)D.f; + Diagnostic(ErrorCode.ERR_NoExplicitConv, "(System.Action)D.f").WithArguments("string", "System.Action").WithLocation(1, 9), + // (2,19): error CS0029: Cannot implicitly convert type 'string' to 'System.Action' + // System.Action a = D.f; + Diagnostic(ErrorCode.ERR_NoImplicitConv, "D.f").WithArguments("string", "System.Action").WithLocation(2, 19)); + } + + [Fact] + public void ResolveAll_MethodTypeInference() + { + var source = """ +write(object.M); +void write(T t) { System.Console.Write(t.ToString()); } + +static class E +{ + extension(object) + { + public static int M => 42; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Equal("System.Int32 E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + + Assert.Equal("System.Int32", model.GetTypeInfo(memberAccess).Type.ToTestDisplayString()); + Assert.Equal("System.Int32", model.GetTypeInfo(memberAccess).ConvertedType.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_ArrayCreation_Initializer_Static() + { + var source = """ +var x = new[] { object.StaticProperty, object.StaticProperty }; +System.Console.Write((x[0], x[1])); + +static class E +{ + extension(object) + { + public static int StaticProperty => 42; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "(42, 42)").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntaxes(tree, "object.StaticProperty").ToArray(); + Assert.Equal("System.Int32 E.<>E__0.StaticProperty { get; }", model.GetSymbolInfo(memberAccess[0]).Symbol.ToTestDisplayString()); + Assert.Equal("System.Int32 E.<>E__0.StaticProperty { get; }", model.GetSymbolInfo(memberAccess[1]).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_ArrayCreation_Rank() + { + var source = """ +var x = new object[object.StaticProperty]; +System.Console.Write(x.Length.ToString()); + +static class E +{ + extension(object o) + { + public static int StaticProperty => 42; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.StaticProperty"); + Assert.Equal("System.Int32 E.<>E__0.StaticProperty { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_Deconstruction_Declaration() + { + var source = """ +var (x, y) = object.M; +System.Console.Write((x, y)); + +static class E +{ + extension(object) + { + public static (int, int) M => (42, 43); + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "(42, 43)").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Equal("(System.Int32, System.Int32) E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_Deconstruction_Assignment() + { + var source = """ +int x, y; +(x, y) = object.M; +System.Console.Write((x, y)); + +static class E +{ + extension(object o) + { + public static (int, int) M => (42, 43); + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "(42, 43)").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Equal("(System.Int32, System.Int32) E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_TupleExpression() + { + var source = """ +System.Console.Write((object.M, object.M)); + +static class E +{ + extension(object o) + { + public static int M => 42; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "(42, 42)").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntaxes(tree, "object.M").ToArray(); + Assert.Equal("System.Int32 E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess[0]).Symbol.ToTestDisplayString()); + Assert.Equal("System.Int32 E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess[1]).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_CollectionExpression() + { + var source = """ +int[] x = [object.M]; +System.Console.Write(x[0].ToString()); + +static class E +{ + extension(object o) + { + public static int M => 42; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Equal("System.Int32 E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_CollectionExpression_ExtensionAddMethod() + { + var source = """ +using System.Collections; +using System.Collections.Generic; + +MyCollection c = [42]; + +static class E +{ + extension(MyCollection c) + { + public void Add(int i) { System.Console.Write("ran"); } + } +} + +public class MyCollection : IEnumerable +{ + IEnumerator IEnumerable.GetEnumerator() => throw null; + IEnumerator IEnumerable.GetEnumerator() => throw null; +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + } + + [Fact] + public void ResolveAll_CollectionExpression_ExtensionAddMethod_RefReceiverParameter() + { + // The receiver argument gets an implicit `ref` when the parameter is `ref` + var source = """ +using System.Collections; +using System.Collections.Generic; + +MyCollection c = [42]; +System.Console.Write(c is null); + +static class E +{ + extension(ref MyCollection c) + { + public void Add(int i) { System.Console.Write("ran "); c = null; } + } +} + +public class MyCollection : IEnumerable +{ + IEnumerator IEnumerable.GetEnumerator() => throw null; + IEnumerator IEnumerable.GetEnumerator() => throw null; +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran True").VerifyDiagnostics(); + } + + [Fact] + public void ResolveAll_CollectionExpression_ExtensionAddMethod_InReceiverParameter() + { + var source = """ +using System.Collections; +using System.Collections.Generic; + +MyCollection c = [42]; + +static class E +{ + extension(in MyCollection c) + { + public void Add(int i) { System.Console.Write("ran"); } + } +} + +public class MyCollection : IEnumerable +{ + IEnumerator IEnumerable.GetEnumerator() => throw null; + IEnumerator IEnumerable.GetEnumerator() => throw null; +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + } + + [Fact] + public void ResolveAll_CollectionExpression_ExtensionAddMethod_RefParameter() + { + var source = """ +using System.Collections; +using System.Collections.Generic; + +MyCollection c = [42]; + +static class E +{ + extension(MyCollection c) + { + public void Add(ref int i) { System.Console.Write("ran"); } + } +} + +public class MyCollection : IEnumerable +{ + IEnumerator IEnumerable.GetEnumerator() => throw null; + IEnumerator IEnumerable.GetEnumerator() => throw null; +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (4,18): error CS1954: The best overloaded method match 'E.extension(MyCollection).Add(ref int)' for the collection initializer element cannot be used. Collection initializer 'Add' methods cannot have ref or out parameters. + // MyCollection c = [42]; + Diagnostic(ErrorCode.ERR_InitializerAddHasParamModifiers, "[42]").WithArguments("E.extension(MyCollection).Add(ref int)").WithLocation(4, 18)); + } + + [Fact] + public void ResolveAll_CollectionExpression_ExtensionAddDelegateTypeProperty() + { + var source = """ +using System.Collections; +using System.Collections.Generic; + +MyCollection c = [42]; + +static class E +{ + extension(MyCollection c) + { + public System.Action Add => (int i) => { }; + } +} + +public class MyCollection : IEnumerable +{ + IEnumerator IEnumerable.GetEnumerator() => throw null; + IEnumerator IEnumerable.GetEnumerator() => throw null; +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (4,18): error CS1061: 'MyCollection' does not contain a definition for 'Add' and no accessible extension method 'Add' accepting a first argument of type 'MyCollection' could be found (are you missing a using directive or an assembly reference?) + // MyCollection c = [42]; + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "[42]").WithArguments("MyCollection", "Add").WithLocation(4, 18) + ); + } + + [Fact] + public void ResolveAll_Initializer_Property() + { + var source = """ +var x = new System.Collections.Generic.List() { object.M }; +System.Console.Write(x[0]); + +static class E +{ + extension(object o) + { + public static int M => 42; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Equal("System.Int32 E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_Initializer_Method() + { + var source = """ +var x = new System.Collections.Generic.List() { object.M }; + +static class E +{ + extension(object o) + { + public static void M() => throw null; + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (1,54): error CS1950: The best overloaded Add method 'List.Add(int)' for the collection initializer has some invalid arguments + // var x = new System.Collections.Generic.List() { object.M }; + Diagnostic(ErrorCode.ERR_BadArgTypesForCollectionAdd, "object.M").WithArguments("System.Collections.Generic.List.Add(int)").WithLocation(1, 54), + // (1,54): error CS1503: Argument 1: cannot convert from 'method group' to 'int' + // var x = new System.Collections.Generic.List() { object.M }; + Diagnostic(ErrorCode.ERR_BadArgType, "object.M").WithArguments("1", "method group", "int").WithLocation(1, 54)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["void E.<>E__0.M()"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(CandidateReason.OverloadResolutionFailure, model.GetSymbolInfo(memberAccess).CandidateReason); + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void ResolveAll_Initializer_ObjectInitializer() + { + var source = """ +var x = new C() { f = object.M }; +System.Console.Write(x.f.ToString()); + +class C +{ + public int f; +} + +static class E +{ + extension(object o) + { + public static int M => 42; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Equal("System.Int32 E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_ConditionalAccess_Receiver() + { + var source = """ +System.Console.Write(object.M?.ToString()); + +static class E +{ + extension(object o) + { + public static string M => "ran"; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Equal("System.String E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_ConditionalAccess_WhenNotNull_Property() + { + var source = """ +var x = new object()?.M; +System.Console.Write(x.ToString()); + +static class E +{ + extension(object o) + { + public string M => "ran"; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberBinding = GetSyntax(tree, ".M"); + Assert.Equal("System.String E.<>E__0.M { get; }", model.GetSymbolInfo(memberBinding).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_ConditionalAccess_WhenNotNull_Invocation() + { + var source = """ +var x = new object()?.M(); +System.Console.Write(x.ToString()); + +static class E +{ + extension(object o) + { + public string M() => "ran"; + public string M(int i) => throw null; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberBinding = GetSyntax(tree, ".M"); + Assert.Equal("System.String E.<>E__0.M()", model.GetSymbolInfo(memberBinding).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_CompoundAssignment_Left() + { + var source = """ +object.M += 41; +System.Console.Write(E.M.ToString()); + +static class E +{ + extension(object o) + { + public static int M { get => 42; set { } } + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Equal("System.Int32 E.<>E__0.M { get; set; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_CompoundAssignment_Right() + { + var source = """ +int x = 1; +x += object.M; +System.Console.Write(x.ToString()); + +static class E +{ + extension(object o) + { + public static int M => 41; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Equal("System.Int32 E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_BinaryOperator_UserDefinedOperator() + { + var source = """ +var x = object.M + object.M; +System.Console.Write(x.ToString()); + +public class C +{ + public static int operator+(C c1, C c2) => 42; +} + +static class E +{ + extension(object o) + { + public static C M => new C(); + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntaxes(tree, "object.M").ToArray(); + Assert.Equal("C E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess[0]).Symbol.ToTestDisplayString()); + Assert.Equal("C E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess[1]).Symbol.ToTestDisplayString()); + + var binaryOp = GetSyntax(tree, "object.M + object.M"); + Assert.Equal("System.Int32 C.op_Addition(C c1, C c2)", model.GetSymbolInfo(binaryOp).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_BinaryOperator_NoUserDefinedOperator() + { + var source = """ +var x = object.M + object.M; +System.Console.Write(x.ToString()); + +public class C { } + +static class E +{ + extension(object o) + { + public static C M => new C(); + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (1,9): error CS0019: Operator '+' cannot be applied to operands of type 'C' and 'C' + // var x = object.M + object.M; + Diagnostic(ErrorCode.ERR_BadBinaryOps, "object.M + object.M").WithArguments("+", "C", "C").WithLocation(1, 9)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntaxes(tree, "object.M").ToArray(); + Assert.Equal("C E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess[0]).Symbol.ToTestDisplayString()); + Assert.Equal("C E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess[1]).Symbol.ToTestDisplayString()); + + var binaryOp = GetSyntax(tree, "object.M + object.M"); + Assert.Null(model.GetSymbolInfo(binaryOp).Symbol); + } + + [Fact] + public void ResolveAll_IncrementOperator() + { + var source = """ +object.M++; + +public class C { } + +static class E +{ + extension(object o) + { + public static int M { get { System.Console.Write("get "); return 41; } set { System.Console.Write($"set({value}) "); } } + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "get set(42)").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Equal("System.Int32 E.<>E__0.M { get; set; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + + var unaryOp = GetSyntax(tree, "object.M++"); + Assert.Equal("System.Int32 System.Int32.op_Increment(System.Int32 value)", model.GetSymbolInfo(unaryOp).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_UnaryOperator() + { + var source = """ +_ = !object.M; + +public class C { } + +static class E +{ + extension(object o) + { + public static bool M { get { System.Console.Write("ran"); return true; } } + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Equal("System.Boolean E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + + var unaryOp = GetSyntax(tree, "!object.M"); + Assert.Equal("System.Boolean System.Boolean.op_LogicalNot(System.Boolean value)", + model.GetSymbolInfo(unaryOp).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_NullCoalescingOperator() + { + var source = """ +var x = object.M ?? object.M2; +System.Console.Write(x); + +static class E +{ + extension(object o) + { + public static string M => null; + public static string M2 => "ran"; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess1 = GetSyntax(tree, "object.M"); + Assert.Equal("System.String E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); + + var memberAccess2 = GetSyntax(tree, "object.M2"); + Assert.Equal("System.String E.<>E__0.M2 { get; }", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_NullCoalescingAssignmentOperator() + { + var source = """ +object.M ??= object.M2; + +static class E +{ + extension(object o) + { + public static string M { get { System.Console.Write("get "); return null; } set { System.Console.Write($"set({value}) "); } } + public static string M2 => "ran"; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "get set(ran)").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess1 = GetSyntax(tree, "object.M"); + Assert.Equal("System.String E.<>E__0.M { get; set; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); + + var memberAccess2 = GetSyntax(tree, "object.M2"); + Assert.Equal("System.String E.<>E__0.M2 { get; }", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_Query_Select() + { + var source = """ +using System.Linq; + +int[] array = [1]; +var r = from int i in array select object.M; +foreach (var x in r) +{ + System.Console.Write(x.ToString()); +} + +static class E +{ + extension(object o) + { + public static string M => "ran"; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Equal("System.String E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact(Skip = "Tracked by https://github.com/dotnet/roslyn/issues/76130 : WasPropertyBackingFieldAccessChecked asserts that we're setting twice")] + public void ResolveAll_Query_Cast() + { + var source = """ +using System.Linq; + +var r = from string s in object.M from string s2 in object.M2 select s.ToString(); +foreach (var x in r) +{ + System.Console.Write(x.ToString()); +} + +static class E +{ + extension(object o) + { + public static object[] M => ["ran"]; + public static object[] M2 => [""]; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess1 = GetSyntax(tree, "object.M"); + Assert.Equal("System.Object[] E.M", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); + + var memberAccess2 = GetSyntax(tree, "object.M2"); + Assert.Equal("System.Object[] E.M2", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_Return_Lambda() + { + var source = """ +var x = () => + { + bool b = true; + if (b) + return object.M; + else + return object.M2; + }; +System.Console.Write(x().ToString()); + +static class E +{ + extension(object o) + { + public static int M => 42; + public static int M2 => 0; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess1 = GetSyntax(tree, "object.M"); + Assert.Equal("System.Int32 E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); + + var memberAccess2 = GetSyntax(tree, "object.M2"); + Assert.Equal("System.Int32 E.<>E__0.M2 { get; }", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_ExpressionBodiedLambda() + { + var source = """ +var x = () => object.M; +System.Console.Write(x().ToString()); + +static class E +{ + extension(object o) + { + public static int M => 42; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess1 = GetSyntax(tree, "object.M"); + Assert.Equal("System.Int32 E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_YieldReturn() + { + var source = """ +foreach (var y in local()) +{ + System.Console.Write(y.ToString()); +} + +System.Collections.Generic.IEnumerable local() +{ + bool b = true; + if (b) + yield return object.M; + else + yield return object.M2; +} + +static class E +{ + extension(object o) + { + public static int M => 42; + public static int M2 => 0; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess1 = GetSyntax(tree, "object.M"); + Assert.Equal("System.Int32 E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); + + var memberAccess2 = GetSyntax(tree, "object.M2"); + Assert.Equal("System.Int32 E.<>E__0.M2 { get; }", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_YieldReturn_Lambda() + { + var source = """ +var x = System.Collections.Generic.IEnumerable () => + { + bool b = true; + if (b) + yield return object.M; + else + yield return object.M2; + }; + +foreach (var y in x()) +{ + System.Console.Write(y.ToString()); +} + +static class E +{ + extension(object o) + { + public static int M => 42; + public static int M2 => 0; + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (1,56): error CS1643: Not all code paths return a value in lambda expression of type 'Func>' + // var x = System.Collections.Generic.IEnumerable () => + Diagnostic(ErrorCode.ERR_AnonymousReturnExpected, "=>").WithArguments("lambda expression", "System.Func>").WithLocation(1, 56), + // (5,13): error CS1621: The yield statement cannot be used inside an anonymous method or lambda expression + // yield return object.M; + Diagnostic(ErrorCode.ERR_YieldInAnonMeth, "yield").WithLocation(5, 13), + // (7,13): error CS1621: The yield statement cannot be used inside an anonymous method or lambda expression + // yield return object.M2; + Diagnostic(ErrorCode.ERR_YieldInAnonMeth, "yield").WithLocation(7, 13)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess1 = GetSyntax(tree, "object.M"); + Assert.Equal("System.Int32 E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); + + var memberAccess2 = GetSyntax(tree, "object.M2"); + Assert.Equal("System.Int32 E.<>E__0.M2 { get; }", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_Throw() + { + var source = """ +try +{ + throw object.M; +} +catch (System.Exception e) +{ + System.Console.Write(e.Message); +} + +static class E +{ + extension(object o) + { + public static System.Exception M => new System.Exception("ran"); + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess1 = GetSyntax(tree, "object.M"); + Assert.Equal("System.Exception E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_FieldInitializer() + { + var source = """ +System.Console.Write(C.field.ToString()); + +class C +{ + public static string field = object.M; +} + +static class E +{ + extension(object o) + { + public static string M => "ran"; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess1 = GetSyntax(tree, "object.M"); + Assert.Equal("System.String E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_Invocation_Static() + { + var src = """ +local(object.M); + +void local(string s) +{ + System.Console.Write(s); +} + +static class E +{ + extension(object o) + { + public static string M => "ran"; + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntaxes(tree, "object.M").First(); + Assert.Equal("System.String E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_Invocation_Static_DelegateTypeParameter() + { + var src = """ +local(object.M); + +void local(System.Func d) +{ + System.Console.Write(d()); +} + +static class E +{ + extension(object o) + { + public static string M() => "ran"; + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntaxes(tree, "object.M").First(); + Assert.Equal("System.String E.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_Invocation_Static_Inferred() + { + var src = """ +System.Console.Write(local(object.M)); + +T local(T t) +{ + return t; +} + +static class E +{ + extension(object o) + { + public static string M => "ran"; + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntaxes(tree, "object.M").First(); + Assert.Equal("System.String E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_Invocation_Static_DelegateTypeParameter_InapplicableInstanceMember() + { + var src = """ +local(object.ToString); + +void local(System.Func d) +{ + System.Console.Write(d(42)); +} + +static class E +{ + extension(object o) + { + public static string ToString(int i) => "ran"; + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntaxes(tree, "object.ToString").First(); + Assert.Equal("System.String E.<>E__0.ToString(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_Invocation_Static_DelegateTypeParameter_PropertyAndMethod() + { + var src = """ +var o = new object(); +C.M(o.Member); + +class C +{ + public static void M(System.Action a) { a(); } +} + +static class E1 +{ + extension(object o) + { + public string Member => throw null; + } +} + +public static class E2 +{ + public static void Member(this object o) => throw null; +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (2,5): error CS9286: 'object' does not contain a definition for 'Member' and no accessible extension member 'Member' for receiver of type 'object' could be found (are you missing a using directive or an assembly reference?) + // C.M(o.Member); + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "o.Member").WithArguments("object", "Member").WithLocation(2, 5)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "o.Member"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + Assert.Equal(["System.String E1.<>E__0.Member { get; }", "void E2.Member(this System.Object o)"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + } + + [Fact] + public void ResolveAll_ObjectCreation_Static() + { + var source = """ +new C(object.M); + +class C +{ + public C(string s) { System.Console.Write(s); } +} + +static class E +{ + extension(object o) + { + public static string M => "ran"; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess1 = GetSyntax(tree, "object.M"); + Assert.Equal("System.String E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_BinaryOperator_Static_TwoExtensions() + { + var src = """ +bool b = D.f + D.f; + +class C +{ + public static bool operator +(C c, System.Action a) => true; +} + +class D { } + +static class E1 +{ + extension(D d) + { + public static C f => null; + } +} + +static class E2 +{ + extension(object o) + { + public static void f() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,10): error CS9286: 'D' does not contain a definition for 'f' and no accessible extension member 'f' for receiver of type 'D' could be found (are you missing a using directive or an assembly reference?) + // bool b = D.f + D.f; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "D.f").WithArguments("D", "f").WithLocation(1, 10), + // (1,16): error CS9286: 'D' does not contain a definition for 'f' and no accessible extension member 'f' for receiver of type 'D' could be found (are you missing a using directive or an assembly reference?) + // bool b = D.f + D.f; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "D.f").WithArguments("D", "f").WithLocation(1, 16)); + } + + [Fact] + public void ResolveAll_Lambda_Static_TwoAsGoodExtensions_LambdaConverted() + { + var src = """ +System.Func l = () => object.f; + +static class E1 +{ + extension(object o) + { + public static string f => null; + } +} + +static class E2 +{ + extension(object o) + { + public static void f() { System.Console.Write("ran"); } + } +} +"""; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : the diagnostic should describe what went wrong + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,38): error CS9286: 'object' does not contain a definition for 'f' and no accessible extension member 'f' for receiver of type 'object' could be found (are you missing a using directive or an assembly reference?) + // System.Func l = () => object.f; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "object.f").WithArguments("object", "f").WithLocation(1, 38) + ); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntaxes(tree, "object.f").First(); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["System.String E1.<>E__0.f { get; }", "void E2.<>E__0.f()"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + } + + [Fact] + public void ResolveAll_Lambda_Instance_ExtensionMethodVsExtensionMember() + { + var src = """ +System.Func lambda = () => new object().Member; + +static class E +{ + extension(object o) + { + public string Member => throw null; + } + + public static void Member(this object o) => throw null; +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,43): error CS9286: 'object' does not contain a definition for 'Member' and no accessible extension member 'Member' for receiver of type 'object' could be found (are you missing a using directive or an assembly reference?) + // System.Func lambda = () => new object().Member; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "new object().Member").WithArguments("object", "Member").WithLocation(1, 43)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new object().Member"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + } + + [Fact] + public void ResolveAll_Lambda_Instance_MethodGroupWithMultipleOverloads() + { + var src = """ +System.Func lambda = () => new object().Member; +lambda()(); + +static class E +{ + extension(object o) + { + public void Member() { System.Console.Write("ran"); } + public void Member(int i) => throw null; + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new object().Member"); + Assert.Equal("void E.<>E__0.Member()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_Lambda_Static_TwoExtensions_ConversionToDelegateType_ExplicitReturnType() + { + var src = """ +var l = System.Action () => D.f; + +class D { } + +static class E1 +{ + extension(object o) + { + public static string f => null; + } +} +static class E2 +{ + extension(object o) + { + public static void f() { System.Console.Write("ran"); } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,29): error CS9286: 'D' does not contain a definition for 'f' and no accessible extension member 'f' for receiver of type 'D' could be found (are you missing a using directive or an assembly reference?) + // var l = System.Action () => D.f; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "D.f").WithArguments("D", "f").WithLocation(1, 29) + ); + } + + [Fact] + public void ResolveAll_Lambda_Static_TwoExtensions_ConversionToDelegateType() + { + var src = """ +System.Func l = () => D.f; + +class D { } + +static class E1 +{ + extension(D) + { + public static string f => null; + } +} + +static class E2 +{ + extension(object) + { + public static void f() { System.Console.Write("ran"); } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,38): error CS9286: 'D' does not contain a definition for 'f' and no accessible extension member 'f' for receiver of type 'D' could be found (are you missing a using directive or an assembly reference?) + // System.Func l = () => D.f; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "D.f").WithArguments("D", "f").WithLocation(1, 38) + ); + } + + [Fact] + public void ResolveAll_SwitchExpression_Static_Default() + { + var src = """ +bool b = true; +var s = b switch { true => object.f, false => default }; +System.Console.Write(s); + +static class E +{ + extension(object) + { + public static string f => "hi"; + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "hi").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntaxes(tree, "object.f").First(); + Assert.Equal("System.String E.<>E__0.f { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + + var defaultExpr = GetSyntax(tree, "default"); + Assert.Equal("System.String", model.GetTypeInfo(defaultExpr).Type.ToTestDisplayString()); + Assert.Equal("System.String", model.GetTypeInfo(defaultExpr).ConvertedType.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_RefTernary() + { + var src = """ +bool b = true; +string s1 = "ran"; +string s2 = null; + +var x = b ? ref s1.f : ref s2.f; +System.Console.Write(x); + +static class E +{ + extension(ref string s) + { + public ref string f => ref s; + } + + public static ref string M(this ref string s) => ref s; +} +"""; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : missing error on extension parameter + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (15,30): error CS8337: The first parameter of a 'ref' extension method 'M' must be a value type or a generic type constrained to struct. + // public static ref string M(this ref string s) => ref s; + Diagnostic(ErrorCode.ERR_RefExtensionMustBeValueTypeOrConstrainedToOne, "M").WithArguments("M").WithLocation(15, 30)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "s1.f"); + Assert.Equal("ref System.String E.<>E__0.f { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ResolveAll_Query_Static_InstanceMethodGroup() + { + var src = """ +string query = from x in object.ToString select x; + +static class E +{ + extension(object) + { + public static string ToString() => null; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,33): error CS0119: 'object.ToString()' is a method, which is not valid in the given context + // string query = from x in object.ToString select x; + Diagnostic(ErrorCode.ERR_BadSKunknown, "ToString").WithArguments("object.ToString()", "method").WithLocation(1, 33)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.ToString"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["System.String System.Object.ToString()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void ResolveAll_Query_Static_ExtensionMethodGroup() + { + var src = """ +string query = from x in object.M select x; + +static class E +{ + extension(object o) + { + public static string M() => null; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,33): error CS0119: 'E.extension(object).M()' is a method, which is not valid in the given context + // string query = from x in object.M select x; + Diagnostic(ErrorCode.ERR_BadSKunknown, "M").WithArguments("E.extension(object).M()", "method").WithLocation(1, 33)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Empty(model.GetMemberGroup(memberAccess)); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : consider handling BoundBadExpression better + } + + [Fact] + public void ResolveAll_Instance_Invocation_InnerInapplicableExtensionMethodVsOuterInvocableExtensionProperty() + { + var src = """ +namespace N +{ + public class C + { + public static void Main() + { + new object().M(); + } + } + + public static class Extension + { + public static void M(this object o, int i) { } // not applicable because of second parameter + } +} + +static class E +{ + extension(object o) + { + public System.Action M => () => { System.Console.Write("ran"); }; + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new object().M"); + Assert.Equal("System.Action E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : handle GetMemberGroup on a property access + } + + [Fact] + public void ResolveAll_Instance_Invocation_InnerIrrelevantExtensionMethodVsOuterInvocableExtensionProperty() + { + var src = """ +namespace N +{ + public class C + { + public static void Main() + { + new object().M(); + } + } + + public static class Extension + { + public static void M(this string o, int i) { } // not eligible because of `this` parameter + } +} + +static class E +{ + extension(object o) + { + public System.Action M => () => { System.Console.Write("ran"); }; + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new object().M"); + Assert.Equal("System.Action E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : handle GetMemberGroup on a property access + } + + [Fact] + public void ResolveAll_Instance_InferredVariable_InnerExtensionMethodVsOuterInvocableExtensionProperty() + { + var src = """ +namespace N +{ + public class C + { + public static void Main() + { + var x = new object().M; + x(42); + } + } + + public static class Extension + { + public static void M(this object o, int i) { System.Console.Write("ran"); } + } +} + +static class E +{ + extension(object o) + { + public System.Action M => () => throw null; + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new object().M"); + Assert.Equal("void System.Object.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void System.Object.M(System.Int32 i)", "System.Action E.<>E__0.M { get; }"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void ResolveAll_Instance_LocalDeclaration_InnerExtensionMethodVsOuterExtensionProperty() + { + var src = """ +namespace N +{ + public class C + { + public static void Main() + { + int x = new object().M; + } + } + + public static class Extension + { + public static void M(this object o, int i) { } + } +} + +static class E +{ + extension(object o) + { + public int M => 42; + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + comp.VerifyEmitDiagnostics( + // (7,34): error CS0428: Cannot convert method group 'M' to non-delegate type 'int'. Did you intend to invoke the method? + // int x = new object().M; + Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "M").WithArguments("M", "int").WithLocation(7, 34)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new object().M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["void System.Object.M(System.Int32 i)", "System.Int32 E.<>E__0.M { get; }"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void ResolveAll_Static_LocalDeclaration_InnerExtensionMethodVsOuterExtensionProperty() + { + var src = """ +namespace N +{ + public class C + { + public static void Main() + { + int x = object.M; + } + } + + public static class Extension + { + public static void M(this object o, int i) { } + } +} + +static class E +{ + extension(object o) + { + public static int M => 42; + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + comp.VerifyEmitDiagnostics( + // (7,28): error CS0428: Cannot convert method group 'M' to non-delegate type 'int'. Did you intend to invoke the method? + // int x = object.M; + Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "M").WithArguments("M", "int").WithLocation(7, 28)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["void System.Object.M(System.Int32 i)", "System.Int32 E.<>E__0.M { get; }"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void ResolveAll_Static_LocalDeclaration_InstanceInnerExtensionTypeMethodVsOuterExtensionProperty() + { + var src = """ +namespace N +{ + public class C + { + public static void Main() + { + int x = object.M; + } + } + + static class E1 + { + extension(object o) + { + public void M(int i) { } + } + } +} + +static class E2 +{ + extension(object) + { + public static int M => 42; + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + comp.VerifyEmitDiagnostics( + // (7,28): error CS0428: Cannot convert method group 'M' to non-delegate type 'int'. Did you intend to invoke the method? + // int x = object.M; + Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "M").WithArguments("M", "int").WithLocation(7, 28)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["void N.E1.<>E__0.M(System.Int32 i)", "System.Int32 E2.<>E__0.M { get; }"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void ResolveAll_Instance_LocalDeclaration_StaticInnerExtensionTypeMethodVsOuterExtensionProperty() + { + var src = """ +namespace N +{ + public class C + { + public static void Main() + { + int x = new object().M; + } + } + + static class E1 + { + extension(object) + { + public static void M(int i) => throw null; + } + } +} + +static class E2 +{ + extension(object o) + { + public int M => 42; + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + comp.VerifyEmitDiagnostics( + // (7,34): error CS0428: Cannot convert method group 'M' to non-delegate type 'int'. Did you intend to invoke the method? + // int x = new object().M; + Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "M").WithArguments("M", "int").WithLocation(7, 34)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new object().M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["void N.E1.<>E__0.M(System.Int32 i)", "System.Int32 E2.<>E__0.M { get; }"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void ResolveAll_Instance_LocalDeclaration_InnerIrrelevantExtensionMethodVsOuterExtensionProperty() + { + var src = """ +namespace N +{ + public class C + { + public static void Main() + { + int x = new object().M; + System.Console.Write(x); + } + } + + public static class Extension + { + public static void M(this string o, int i) { } // not eligible because of `this` parameter + } +} + +static class E +{ + extension(object o) + { + public int M => 42; + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new object().M"); + Assert.Equal("System.Int32 E.<>E__0.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : handle GetMemberGroup on a property access + } + + [Fact] + public void ResolveAll_Instance_LocalDeclaration_DelegateType_InnerInapplicableExtensionMethodVsOuterExtensionProperty() + { + var src = """ +namespace N +{ + public class C + { + public static void Main() + { + System.Action x = new object().M; + x(); + } + } + + public static class Extension + { + public static void M(this object o, int i) { } + } +} + +static class E +{ + extension(object o) + { + public void M() { System.Console.Write("ran"); } + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new object().M"); + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void System.Object.M(System.Int32 i)", "void E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void ResolveAll_Instance_LocalDeclaration_DelegateType_InnerIrrelevantExtensionMethodVsOuterExtensionProperty() + { + var src = """ +namespace N +{ + public class C + { + public static void Main() + { + System.Action x = new object().M; + x(); + } + } + + public static class Extension + { + public static void M(this string o, int i) { } // not eligible because of `this` parameter + } +} + +static class E +{ + extension(object o) + { + public void M() { System.Console.Write("ran"); } + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new object().M"); + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void ResolveAll_ConditionalOperator_Static_TwoAsGoodExtensions_Property() + { + var source = """ +bool b = true; +var x = b ? object.StaticProperty : object.StaticProperty; + +static class E1 +{ + extension(object) + { + public static int StaticProperty => 42; + } +} +static class E2 +{ + extension(object) + { + public static int StaticProperty => 42; + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (2,13): error CS9286: 'object' does not contain a definition for 'StaticProperty' and no accessible extension member 'StaticProperty' for receiver of type 'object' could be found (are you missing a using directive or an assembly reference?) + // var x = b ? object.StaticProperty : object.StaticProperty; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "object.StaticProperty").WithArguments("object", "StaticProperty").WithLocation(2, 13), + // (2,37): error CS9286: 'object' does not contain a definition for 'StaticProperty' and no accessible extension member 'StaticProperty' for receiver of type 'object' could be found (are you missing a using directive or an assembly reference?) + // var x = b ? object.StaticProperty : object.StaticProperty; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "object.StaticProperty").WithArguments("object", "StaticProperty").WithLocation(2, 37)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntaxes(tree, "object.StaticProperty").ToArray(); + Assert.Null(model.GetSymbolInfo(memberAccess[0]).Symbol); + Assert.Null(model.GetSymbolInfo(memberAccess[1]).Symbol); + } + + [Fact] + public void DelegateConversion_TypeReceiver() + { + var source = """ +D d = C.M; +d(42); + +delegate void D(int i); + +class C { } + +static class E +{ + extension(C) + { + public static void M(int i) { System.Console.Write($"E.M({i})"); } + } +} +"""; + var comp = CreateCompilation(source); + var verifier = CompileAndVerify(comp, expectedOutput: "E.M(42)").VerifyDiagnostics(); + verifier.VerifyIL("", """ +{ + // Code size 35 (0x23) + .maxstack 2 + IL_0000: ldsfld "D Program.<>O.<0>__M" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn "void E.M(int)" + IL_0010: newobj "D..ctor(object, System.IntPtr)" + IL_0015: dup + IL_0016: stsfld "D Program.<>O.<0>__M" + IL_001b: ldc.i4.s 42 + IL_001d: callvirt "void D.Invoke(int)" + IL_0022: ret +} +"""); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "C.M"); + Assert.Equal("void E.<>E__0.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Null(model.GetTypeInfo(memberAccess).Type); + Assert.Equal("D", model.GetTypeInfo(memberAccess).ConvertedType.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + Assert.Equal(ConversionKind.MethodGroup, model.GetConversion(memberAccess).Kind); + } + + [Fact] + public void DelegateConversion_TypeReceiver_Creation() + { + var source = """ +D d = new D(C.M); +d(42); + +delegate void D(int i); + +class C { } + +static class E +{ + extension(C) + { + public static void M(int i) { System.Console.Write($"E.M({i})"); } + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "E.M(42)").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "C.M"); + Assert.Equal("void E.<>E__0.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Null(model.GetTypeInfo(memberAccess).Type); + Assert.Equal("D", model.GetTypeInfo(memberAccess).ConvertedType.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + Assert.Equal(ConversionKind.MethodGroup, model.GetConversion(memberAccess).Kind); + } + + [Fact] + public void DelegateConversion_InstanceReceiver_Creation() + { + var source = """ +D d = new D(new C().M); +d(42); + +delegate void D(int i); + +class C { } + +static class E +{ + extension(C) + { + public void M(int i) { System.Console.Write($"E.M({i})"); } + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "E.M(42)").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new C().M"); + Assert.Equal("void E.<>E__0.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Null(model.GetTypeInfo(memberAccess).Type); + Assert.Equal("D", model.GetTypeInfo(memberAccess).ConvertedType.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + Assert.Equal(ConversionKind.MethodGroup, model.GetConversion(memberAccess).Kind); + } + + [Fact] + public void DelegateConversion_InstanceReceiver() + { + var source = """ +D d = new C(42).M; +d(43); + +delegate void D(int i); + +class C(int x) +{ + public int x = x; + public void M() => throw null; +} + +static class E +{ + extension(C c) + { + public void M(int i) { System.Console.Write($"{c.x}.M({i})"); } + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + var verifier = CompileAndVerify(comp, expectedOutput: "42.M(43)").VerifyDiagnostics(); + verifier.VerifyIL("", """ +{ + // Code size 26 (0x1a) + .maxstack 2 + IL_0000: ldc.i4.s 42 + IL_0002: newobj "C..ctor(int)" + IL_0007: ldftn "void E.M(C, int)" + IL_000d: newobj "D..ctor(object, System.IntPtr)" + IL_0012: ldc.i4.s 43 + IL_0014: callvirt "void D.Invoke(int)" + IL_0019: ret +} +"""); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new C(42).M"); + Assert.Equal("void E.<>E__0.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void C.M()", "void E.<>E__0.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + Assert.Equal(ConversionKind.MethodGroup, model.GetConversion(memberAccess).Kind); + } + + [Fact] + public void DelegateConversion_TypeReceiver_Overloads() + { + var source = """ +D d = C.M; +d(42); + +C.M(42); + +delegate void D(int i); + +class C { } + +static class E +{ + extension(C) + { + public static void M(int i) { System.Console.Write("ran "); } + + public static void M(string s) => throw null; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntaxes(tree, "C.M").First(); + Assert.Equal("void E.<>E__0.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M(System.Int32 i)", "void E.<>E__0.M(System.String s)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void DelegateConversion_ValueReceiver_Overloads() + { + var source = """ +D d = new C().M; +d(42); + +new C().M(42); + +delegate void D(int i); + +class C { } + +static class E +{ + extension(C c) + { + public void M(int i) { System.Console.Write("ran "); } + public void M(string s) => throw null; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntaxes(tree, "new C().M").First(); + Assert.Equal("void E.<>E__0.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M(System.Int32 i)", "void E.<>E__0.M(System.String s)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void DelegateConversion_TypeReceiver_Overloads_DifferentExtensions() + { + var source = """ +D d = C.M; +d(42); + +C.M(42); + +delegate void D(int i); + +class C { } + +static class E1 +{ + extension(C) + { + public static void M(int i) { System.Console.Write("ran "); } + } +} +static class E2 +{ + extension(C) + { + public static void M(string s) => throw null; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntaxes(tree, "C.M").First(); + Assert.Equal("void E1.<>E__0.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void E1.<>E__0.M(System.Int32 i)", "void E2.<>E__0.M(System.String s)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void DelegateConversion_WrongSignature() + { + var source = """ +D d = new C().M; +d(42); + +new C().M(42); + +delegate void D(int i); + +class C { } + +static class E +{ + extension(C c) + { + public void M(string s) => throw null; + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (1,15): error CS0123: No overload for 'M' matches delegate 'D' + // D d = new C().M; + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "M").WithArguments("M", "D").WithLocation(1, 15), + // (4,11): error CS1503: Argument 2: cannot convert from 'int' to 'string' + // new C().M(42); + Diagnostic(ErrorCode.ERR_BadArgType, "42").WithArguments("2", "int", "string").WithLocation(4, 11)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntaxes(tree, "new C().M").First(); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["void E.<>E__0.M(System.String s)"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(["void E.<>E__0.M(System.String s)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void DelegateConversion_TypeReceiver_ZeroArityMatchesAny() + { + var source = """ +D d = object.Method; +d(""); + +d = object.Method; +d(""); + +delegate void D(string s); + +static class E +{ + extension(object) + { + public static void Method(int i) => throw null; + public static void Method(T t) { System.Console.Write("Method "); } + public static void Method(T1 t1, T2 t2) => throw null; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "Method Method").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.Method"); + Assert.Equal("void E.<>E__0.Method(System.String t)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.Method(System.Int32 i)", "void E.<>E__0.Method(T t)", "void E.<>E__0.Method(T1 t1, T2 t2)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void DelegateConversion_ValueReceiver_Overloads_OuterScope_WithInapplicableInstanceMember() + { + var source = """ +using N; + +D d = new C().M; +d(42); + +new C().M(42); + +delegate void D(int i); + +class C +{ + public void M(char c) { } +} + +namespace N +{ + static class E1 + { + extension(C c) + { + public void M(int i) + { + System.Console.Write("ran "); + } + } + } +} + +static class E2 +{ + extension(C c) + { + public void M(string s) => throw null; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntaxes(tree, "new C().M").First(); + Assert.Equal("void N.E1.<>E__0.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void C.M(System.Char c)", "void E2.<>E__0.M(System.String s)", "void N.E1.<>E__0.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void DelegateConversion_TypeReceiver_Overloads_InnerScope() + { + var source = """ +using N; + +D d = C.M; +d(42); + +delegate void D(int i); + +class C { } + +static class E1 +{ + extension(C) + { + public static void M(int i) { System.Console.Write("ran"); } + } +} + +namespace N +{ + static class E2 + { + extension(C) + { + public static void M(int i) => throw null; + } + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // 0.cs(1,1): hidden CS8019: Unnecessary using directive. + // using N; + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using N;").WithLocation(1, 1)); + + CompileAndVerify(comp, expectedOutput: "ran"); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "C.M"); + Assert.Equal("void E1.<>E__0.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void E1.<>E__0.M(System.Int32 i)", "void N.E2.<>E__0.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void DelegateConversion_TypeReceiver_TypeArguments_01() + { + var source = """ +D d = object.M; +d(42); + +delegate void D(int i); + +static class E +{ + extension(object) + { + public static void M(int i) => throw null; + public static void M(int i) { System.Console.Write("ran"); } + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Equal("void E.<>E__0.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void DelegateConversion_TypeReceiver_TypeArguments_02() + { + var source = """ +D d = object.M; +d(42); + +delegate void D(int i); + +static class E +{ + extension(object) + { + public static void M(T t) { } + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (1,14): error CS0117: 'object' does not contain a definition for 'M' + // D d = object.M; + Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("object", "M").WithLocation(1, 14)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Empty(model.GetMemberGroup(memberAccess)); + } + + [Fact] + public void DelegateConversion_TypeReceiver_TypeArguments_03() + { + var source = """ +D d = object.M; +d(42); + +delegate void D(int i); + +static class E +{ + extension(T t) + { + public static void M(U u) { System.Console.Write("ran"); } + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Equal("void E.<>E__0.M(System.Int32 u)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M(System.Int32 u)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void DelegateConversion_TypeReceiver_TypeArguments_04() + { + var source = """ +D d = object.M; +d(42); + +delegate void D(int i); + +static class E +{ + extension(T) + { + public static void M(int i) { System.Console.Write("ran"); } + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Equal("void E.<>E__0.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void DelegateConversion_TypeReceiver_OptionalParameter() + { + var source = """ +System.Action a = object.M; +System.Action a2 = E.M2; + +static class E +{ + extension(object) + { + public static void M(int i = 0) => throw null; + } + + public static void M2(int i = 0) => throw null; +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (1,26): error CS0123: No overload for 'M' matches delegate 'Action' + // System.Action a = object.M; + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "M").WithArguments("M", "System.Action").WithLocation(1, 26), + // (2,22): error CS0123: No overload for 'M2' matches delegate 'Action' + // System.Action a2 = E.M2; + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "M2").WithArguments("M2", "System.Action").WithLocation(2, 22)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["void E.<>E__0.M([System.Int32 i = 0])"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + + source = """ +static class E +{ + static void Main() + { + System.Action a2 = E.M2; + } + + public static void M2(int i = 0) => throw null; +} +"""; + comp = CreateCompilation(source, parseOptions: TestOptions.Regular7); + comp.VerifyEmitDiagnostics( + // (5,30): error CS0123: No overload for 'M2' matches delegate 'Action' + // System.Action a2 = E.M2; + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "M2").WithArguments("M2", "System.Action").WithLocation(5, 30)); + } + + [Fact] + public void DelegateConversion_TypeReceiver_ReturnRefKindMismatch() + { + var source = """ +D d = object.M; + +delegate int D(); + +static class E +{ + extension(object) + { + public static ref int M() => throw null; + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (1,7): error CS8189: Ref mismatch between 'E.extension(object).M()' and delegate 'D' + // D d = object.M; + Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "object.M").WithArguments("E.extension(object).M()", "D").WithLocation(1, 7)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Equal(["ref System.Int32 E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void DelegateConversion_TypeReceiver_ReturnTypeMismatch() + { + var source = """ +D d = object.M; + +delegate int D(); + +static class E +{ + extension(object) + { + public static string M() => throw null; + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (1,7): error CS0407: 'string E.extension(object).M()' has the wrong return type + // D d = object.M; + Diagnostic(ErrorCode.ERR_BadRetType, "object.M").WithArguments("E.extension(object).M()", "string").WithLocation(1, 7)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Equal(["System.String E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void DelegateConversion_TypeReceiver_BadParameterConversion() + { + var source = """ +D d = object.M; +D2 d2 = object.M2; + +delegate void D(long l); +delegate void D2(int i); + +static class E +{ + extension(object) + { + public static void M(int i) => throw null; + public static void M2(long l) => throw null; + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (1,14): error CS0123: No overload for 'M' matches delegate 'D' + // D d = object.M; + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "M").WithArguments("M", "D").WithLocation(1, 14), + // (2,9): error CS0123: No overload for 'E.extension(object).M2(long)' matches delegate 'D2' + // D2 d2 = object.M2; + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "object.M2").WithArguments("E.extension(object).M2(long)", "D2").WithLocation(2, 9)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess1 = GetSyntax(tree, "object.M"); + Assert.Equal(["void E.<>E__0.M(System.Int32 i)"], model.GetMemberGroup(memberAccess1).ToTestDisplayStrings()); + + var memberAccess2 = GetSyntax(tree, "object.M2"); + Assert.Equal(["void E.<>E__0.M2(System.Int64 l)"], model.GetMemberGroup(memberAccess2).ToTestDisplayStrings()); + } + + [Fact] + public void DelegateConversion_TypeReceiver_Conditional() + { + var source = """ +System.Action a = object.M; + +static class E +{ + extension(object) + { + [System.Diagnostics.Conditional("DEBUG")] + public static void M() => throw null; + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (1,19): error CS1618: Cannot create delegate with 'E.extension(object).M()' because it or a method it overrides has a Conditional attribute + // System.Action a = object.M; + Diagnostic(ErrorCode.ERR_DelegateOnConditional, "object.M").WithArguments("E.extension(object).M()").WithLocation(1, 19)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void DelegateConversion_TypeReceiver_Partial() + { + var source = """ +System.Action a = object.M; + +static partial class E +{ + extension(object) + { + static partial void M(); + } +} +"""; + var comp = CreateCompilation(source); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : the error on the partial method seems misleading + comp.VerifyEmitDiagnostics( + // (1,26): error CS0117: 'object' does not contain a definition for 'M' + // System.Action a = object.M; + Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("object", "M").WithLocation(1, 26), + // (7,29): error CS0751: A partial member must be declared within a partial type + // static partial void M(); + Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "M").WithLocation(7, 29)); + } + + [Fact] + public void DelegateConversion_TypeReceiver_Pointer() + { + var source = """ +D d = object.M; + +unsafe delegate int* D(); + +unsafe static class E +{ + extension(object) + { + public static int* M() => throw null; + } +} +"""; + var comp = CreateCompilation(source, options: TestOptions.UnsafeDebugExe); + comp.VerifyEmitDiagnostics( + // (1,7): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // D d = object.M; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "object.M").WithLocation(1, 7)); + } + + [Fact] + public void DelegateConversion_TypeReceiver_RefReadonlyMismatch() + { + var source = """ +D d = object.M; +D2 d2 = object.M2; + +D d3 = E.M3; +D2 d4 = E.M4; + +delegate void D(ref int i); +delegate void D2(ref readonly int i); + +static class E +{ + extension(object) + { + public static void M(ref readonly int i) => throw null; + public static void M2(ref int i) => throw null; + } + + public static void M3(ref readonly int i) => throw null; + public static void M4(ref int i) => throw null; +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (1,7): warning CS9198: Reference kind modifier of parameter 'ref readonly int i' doesn't match the corresponding parameter 'ref int i' in target. + // D d = object.M; + Diagnostic(ErrorCode.WRN_TargetDifferentRefness, "object.M").WithArguments("ref readonly int i", "ref int i").WithLocation(1, 7), + // (2,16): error CS0123: No overload for 'M2' matches delegate 'D2' + // D2 d2 = object.M2; + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "M2").WithArguments("M2", "D2").WithLocation(2, 16), + // (4,8): warning CS9198: Reference kind modifier of parameter 'ref readonly int i' doesn't match the corresponding parameter 'ref int i' in target. + // D d3 = E.M3; + Diagnostic(ErrorCode.WRN_TargetDifferentRefness, "E.M3").WithArguments("ref readonly int i", "ref int i").WithLocation(4, 8), + // (5,11): error CS0123: No overload for 'M4' matches delegate 'D2' + // D2 d4 = E.M4; + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "M4").WithArguments("M4", "D2").WithLocation(5, 11)); + } + + [Fact] + public void DelegateConversion_TypeReceiver_Obsolete() + { + var source = """ +System.Action a = object.M; + +static class E +{ + extension(object) + { + [System.Obsolete("obsolete", true)] + public static void M() { } + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (1,19): error CS0619: 'E.extension(object).M()' is obsolete: 'obsolete' + // System.Action a = object.M; + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "object.M").WithArguments("E.extension(object).M()", "obsolete").WithLocation(1, 19)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void DelegateConversion_TypeReceiver_ReceiverTypeKind_01() + { + var source = """ +System.Action a = object.M; +System.Action a2 = int.M; +a(); +a2(); + +static class E +{ + extension(object) + { + public static void M() { System.Console.Write("ran "); } + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran ran").VerifyDiagnostics(); + } + + [Fact] + public void DelegateConversion_TypeReceiver_ReceiverTypeKind_02() + { + var source = """ +System.Action a2 = int.M; +a2(); + +static class E +{ + extension(int) + { + public static void M() { System.Console.Write("ran"); } + } +} +"""; + + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + } + + [Fact] + public void DelegateConversion_InstanceReceiver_ReceiverTypeKind() + { + var source = """ +object o = null; +int i = 0; + +System.Action a = o.M; +System.Action a2 = i.M; + +static class E +{ + extension(object o) + { + public void M() => throw null; + } + + extension(int i) + { + public void M() => throw null; + } +} +"""; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (5,20): error CS1113: Extension method 'E.extension(int).M()' defined on value type 'int' cannot be used to create delegates + // System.Action a2 = i.M; + Diagnostic(ErrorCode.ERR_ValueTypeExtDelegate, "i.M").WithArguments("E.extension(int).M()", "int").WithLocation(5, 20)); + } + + [Fact] + public void DelegateConversion_InstanceReceiver_RefStructReceiver() + { + var source = """ +System.Span s = default; + +System.Action a = s.M; + +static class E +{ + extension(object o) + { + public void M() => throw null; + } +} +"""; + + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net90); + comp.VerifyEmitDiagnostics( + // (3,21): error CS1061: 'Span' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'Span' could be found (are you missing a using directive or an assembly reference?) + // System.Action a = s.M; + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("System.Span", "M").WithLocation(3, 21)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "s.M"); + Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void DelegateConversion_TypeReceiver_RefStructReceiver() + { + var source = """ +System.Action a = System.Span.M; + +static class E +{ + extension(object) + { + public static void M() => throw null; + } +} +"""; + + // Note: we apply the same conversion requirements even though no conversion on the receiver + // is needed in a static scenario. + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net90); + comp.VerifyEmitDiagnostics( + // (1,36): error CS0117: 'Span' does not contain a definition for 'M' + // System.Action a = System.Span.M; + Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("System.Span", "M").WithLocation(1, 36)); + } + + [Fact] + public void InstancePropertyAccess_Obsolete() + { + var src = """ +_ = new object().Property; +new object().Property = 43; + +static class E +{ + extension(object o) + { + [System.Obsolete("Property is obsolete", true)] + public int Property { get => 42; set { } } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,5): error CS0619: 'E.extension(object).Property' is obsolete: 'Property is obsolete' + // _ = new object().Property; + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "new object().Property").WithArguments("E.extension(object).Property", "Property is obsolete").WithLocation(1, 5), + // (2,1): error CS0619: 'E.extension(object).Property' is obsolete: 'Property is obsolete' + // new object().Property = 43; + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "new object().Property").WithArguments("E.extension(object).Property", "Property is obsolete").WithLocation(2, 1)); + } + + [Fact] + public void StaticPropertyAccess_Obsolete() + { + var src = """ +_ = object.Property; +object.Property = 43; + +static class E +{ + extension(object) + { + [System.Obsolete("Property is obsolete", true)] + public static int Property { get => 42; set { } } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,5): error CS0619: 'E.extension(object).Property' is obsolete: 'Property is obsolete' + // _ = object.Property; + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "object.Property").WithArguments("E.extension(object).Property", "Property is obsolete").WithLocation(1, 5), + // (2,1): error CS0619: 'E.extension(object).Property' is obsolete: 'Property is obsolete' + // object.Property = 43; + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "object.Property").WithArguments("E.extension(object).Property", "Property is obsolete").WithLocation(2, 1)); + } + + [Fact] + public void InstancePropertyAccess_Obsolete_InInvocation() + { + var src = """ +new object().Property(); + +static class E +{ + extension(object o) + { + [System.Obsolete("Property is obsolete", true)] + public System.Action Property { get => throw null; set { } } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,1): error CS0619: 'E.extension(object).Property' is obsolete: 'Property is obsolete' + // new object().Property(); + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "new object().Property").WithArguments("E.extension(object).Property", "Property is obsolete").WithLocation(1, 1)); + } + + [Fact] + public void InstancePropertyAccess_ColorColor() + { + var src = """ +C.M(new C()); + +class C +{ + public static void M(C C) + { + C.Property = 42; + } +} + +static class E +{ + extension(C c) + { + public int Property { set { System.Console.Write(value); } } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var property = GetSyntax(tree, "C.Property"); + Assert.Equal("System.Int32 E.<>E__0.Property { set; }", model.GetSymbolInfo(property).Symbol.ToTestDisplayString()); + Assert.Empty(model.GetMemberGroup(property)); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : handle GetMemberGroup on a property access + } + + [Fact] + public void StaticPropertyAccess_ColorColor() + { + var src = """ +C.M(null); + +class C +{ + public static void M(C C) + { + C.Property = 42; + } +} + +static class E +{ + extension(C c) + { + public static int Property { set { System.Console.Write("Property"); } } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "Property").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var property = GetSyntax(tree, "C.Property"); + Assert.Equal("System.Int32 E.<>E__0.Property { set; }", model.GetSymbolInfo(property).Symbol.ToTestDisplayString()); + Assert.Empty(model.GetMemberGroup(property)); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : handle GetMemberGroup on a property access + } + + [Fact] + public void ConditionalReceiver_Property_MemberAccess() + { + var src = """ +bool b = true; +System.Console.Write((b ? "" : null).Property.ToString()); + +static class E +{ + extension(string s) + { + public int Property => 42; + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, """(b ? "" : null).Property"""); + Assert.Equal("System.Int32 E.<>E__0.Property { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void PropertyAccess_ReturnNotLValue() + { + var src = """ +object.Property.field = 1; + +public struct S +{ + public int field; +} +static class E +{ + extension(object) + { + public static S Property { get => throw null; } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,1): error CS1612: Cannot modify the return value of 'E.extension(object).Property' because it is not a variable + // object.Property.field = 1; + Diagnostic(ErrorCode.ERR_ReturnNotLValue, "object.Property").WithArguments("E.extension(object).Property").WithLocation(1, 1)); + } + + [Fact] + public void StaticPropertyAccess_RefProperty_01() + { + var src = """ +localFuncRef(ref object.Property); +localFuncOut(out object.Property); + +void localFuncRef(ref int i) => throw null; +void localFuncOut(out int i) => throw null; + +static class E +{ + extension(object) + { + public static int Property { get => throw null; set => throw null; } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,18): error CS0206: A non ref-returning property or indexer may not be used as an out or ref value + // localFuncRef(ref object.Property); + Diagnostic(ErrorCode.ERR_RefProperty, "object.Property").WithLocation(1, 18), + // (2,18): error CS0206: A non ref-returning property or indexer may not be used as an out or ref value + // localFuncOut(out object.Property); + Diagnostic(ErrorCode.ERR_RefProperty, "object.Property").WithLocation(2, 18)); + } + + [Fact] + public void StaticPropertyAccess_RefProperty_02() + { + var src = """ +localFuncRef(ref object.Property); + +void localFuncRef(ref int i) => throw null; + +static class E +{ + extension(object) + { + public static ref int Property { get => throw null; } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : metadata is undone + } + + [Fact] + public void StaticPropertyAccess_AssignReadonlyNotField() + { + var src = """ +object.Property = 1; + +static class E +{ + extension(object) + { + public static ref readonly int Property { get => throw null; } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,1): error CS8331: Cannot assign to property 'Property' or use it as the right hand side of a ref assignment because it is a readonly variable + // object.Property = 1; + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "object.Property").WithArguments("property", "Property").WithLocation(1, 1)); + } + + [Fact] + public void StaticPropertyAccess_AssgReadonlyProp() + { + var src = """ +object.Property = 1; + +static class E +{ + extension(object) + { + public static int Property { get => throw null; } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,1): error CS0200: Property or indexer 'E.extension(object).Property' cannot be assigned to -- it is read only + // object.Property = 1; + Diagnostic(ErrorCode.ERR_AssgReadonlyProp, "object.Property").WithArguments("E.extension(object).Property").WithLocation(1, 1)); + } + + [Fact] + public void StaticPropertyAccess_InitOnlyProperty() + { + var src = """ +object.Property = 1; + +static class E +{ + extension(object) + { + public static int Property { init => throw null; } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (7,38): error CS8856: The 'init' accessor is not valid on static members + // public static int Property { init => throw null; } + Diagnostic(ErrorCode.ERR_BadInitAccessor, "init").WithLocation(7, 38)); + } + + [Fact] + public void InstancePropertyAccess_InitOnlyProperty() + { + var src = """ +new object().Property = 1; + +static class E +{ + extension(object o) + { + public int Property { init => throw null; } + } +} +"""; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 :(instance) confirm whether init-only accessors should be allowed in extensions + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics( + // (1,1): error CS8852: Init-only property or indexer 'E.extension(object).Property' can only be assigned in an object initializer, or on 'this' or 'base' in an instance constructor or an 'init' accessor. + // new object().Property = 1; + Diagnostic(ErrorCode.ERR_AssignmentInitOnly, "new object().Property").WithArguments("E.extension(object).Property").WithLocation(1, 1)); + } + + [ConditionalFact(typeof(NoUsedAssembliesValidation))] // Tracked by https://github.com/dotnet/roslyn/issues/76130 : metadata is undone + public void InstancePropertyAccess_InitOnlyProperty_ObjectInitializer() + { + var src = """ +_ = new object() { Property = 1 }; + +static class E +{ + extension(object o) + { + public int Property { init => throw null; } + } +} +"""; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : confirm whether init-only accessors should be allowed in extensions + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); + comp.VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var assignment = GetSyntax(tree, "Property = 1"); + Assert.Equal("System.Int32 E.<>E__0.Property { init; }", model.GetSymbolInfo(assignment.Left).Symbol.ToTestDisplayString()); + } + + [Fact] + public void StaticPropertyAccess_InaccessibleSetter() + { + var src = """ +object.Property = 1; + +static class E +{ + extension(object) + { + public static int Property { get => throw null; private set => throw null; } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,1): error CS0272: The property or indexer 'E.extension(object).Property' cannot be used in this context because the set accessor is inaccessible + // object.Property = 1; + Diagnostic(ErrorCode.ERR_InaccessibleSetter, "object.Property").WithArguments("E.extension(object).Property").WithLocation(1, 1)); + } + + [Fact] + public void ParameterCapturing_023_ColorColor_MemberAccess_InstanceAndStatic_ExtensionTypeMethods() + { + // See ParameterCapturing_023_ColorColor_MemberAccess_InstanceAndStatic_Method + var source = """ +struct S1(Color Color) +{ + public void Test() + { + Color.M1(this); + } +} + +class Color { } + +static class E +{ + extension(Color c) + { + public void M1(S1 x, int y = 0) + { + System.Console.WriteLine("instance"); + } + + public static void M1(T x) where T : unmanaged + { + System.Console.WriteLine("static"); + } + } +} +"""; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : missing ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver + var comp = CreateCompilation(source, options: TestOptions.ReleaseDll); + comp.VerifyEmitDiagnostics( + //// (5,9): error CS9106: Identifier 'Color' is ambiguous between type 'Color' and parameter 'Color Color' in this context. + //// Color.M1(this); + //Diagnostic(ErrorCode.ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver, "Color").WithArguments("Color", "Color", "Color Color").WithLocation(5, 9) + ); + + Assert.NotEmpty(comp.GetTypeByMetadataName("S1").InstanceConstructors.OfType().Single().GetCapturedParameters()); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "Color.M1"); + Assert.Equal("void E.<>E__0.M1(S1 x, [System.Int32 y = 0])", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ParameterCapturing_023_ColorColor_MemberAccess_InstanceAndStatic_ExtensionTypeProperties() + { + var source = """ +struct S1(Color Color) +{ + public void Test() + { + _ = Color.P1; + } +} + +class Color { } + +static class E1 +{ + extension(Color c) + { + public int P1 => 0; + } +} + +static class E2 +{ + extension(Color) + { + public static int P1 => 0; + } +} +"""; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : missing ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver + var comp = CreateCompilation(source, options: TestOptions.ReleaseDll); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "Color.P1"); + Assert.Equal("System.Int32 E1.<>E__0.P1 { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ParameterCapturing_023_ColorColor_MemberAccess_InstanceAndStatic_ExtensionTypeMembersVsExtensionMethod() + { + var source = """ +public struct S1(Color Color) +{ + public void Test() + { + Color.M1(this); + } +} + +public class Color { } + +public static class E1 +{ + public static void M1(this Color c, S1 x, int y = 0) + { + System.Console.WriteLine("instance"); + } +} + +static class E +{ + extension(Color) + { + public static void M1(T x) where T : unmanaged + { + System.Console.WriteLine("static"); + } + } +} +"""; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : missing ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver + var comp = CreateCompilation(source, options: TestOptions.ReleaseDll); + comp.VerifyEmitDiagnostics( + //// (5,9): error CS9106: Identifier 'Color' is ambiguous between type 'Color' and parameter 'Color Color' in this context. + //// Color.M1(this); + //Diagnostic(ErrorCode.ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver, "Color").WithArguments("Color", "Color", "Color Color").WithLocation(5, 9) + ); + + Assert.NotEmpty(comp.GetTypeByMetadataName("S1").InstanceConstructors.OfType().Single().GetCapturedParameters()); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "Color.M1"); + Assert.Equal("void Color.M1(S1 x, [System.Int32 y = 0])", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void InstanceMethod_MemberAccess() + { + var src = """ +new object().M.ToString(); + +static class E +{ + extension(object o) + { + public int M() => 42; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,14): error CS0119: 'E.extension(object).M()' is a method, which is not valid in the given context + // new object().M.ToString(); + Diagnostic(ErrorCode.ERR_BadSKunknown, "M").WithArguments("E.extension(object).M()", "method").WithLocation(1, 14)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new object().M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + + src = """ +new object().M.ToString(); + +static class E +{ + public static int M(this object o) => 42; +} +"""; + comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,14): error CS0119: 'E.M(object)' is a method, which is not valid in the given context + // new object().M.ToString(); + Diagnostic(ErrorCode.ERR_BadSKunknown, "M").WithArguments("E.M(object)", "method").WithLocation(1, 14)); + + tree = comp.SyntaxTrees.Single(); + model = comp.GetSemanticModel(tree); + memberAccess = GetSyntax(tree, "new object().M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void InstanceMethod_MemberAccess_Missing() + { + var src = """ +new object().M.ToString(); +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,14): error CS1061: 'object' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) + // new object().M.ToString(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("object", "M").WithLocation(1, 14)); + } + + [Fact] + public void CheckValueKind_AssignToMethodGroup() + { + var src = """ +object.M = null; + +static class E +{ + extension(object) + { + public static void M() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,1): error CS1656: Cannot assign to 'M' because it is a 'method group' + // object.M = null; + Diagnostic(ErrorCode.ERR_AssgReadonlyLocalCause, "object.M").WithArguments("M", "method group").WithLocation(1, 1)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["void E.<>E__0.M()"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(CandidateReason.NotAVariable, model.GetSymbolInfo(memberAccess).CandidateReason); + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void AccessOnVoid_Invocation() + { + var src = """ +object.M().ToString(); + +static class E +{ + extension(object) + { + public static void M() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,11): error CS0023: Operator '.' cannot be applied to operand of type 'void' + // object.M().ToString(); + Diagnostic(ErrorCode.ERR_BadUnaryOp, ".").WithArguments(".", "void").WithLocation(1, 11)); + } + + [Fact] + public void ExtensionMemberLookup_InaccessibleMembers() + { + var src = """ +object.Method(); +_ = object.Property; + +static class E +{ + extension(object o) + { + private static void Method() => throw null; + private static int Property => throw null; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,8): error CS0117: 'object' does not contain a definition for 'Method' + // object.Method(); + Diagnostic(ErrorCode.ERR_NoSuchMember, "Method").WithArguments("object", "Method").WithLocation(1, 8), + // (2,12): error CS0117: 'object' does not contain a definition for 'Property' + // _ = object.Property; + Diagnostic(ErrorCode.ERR_NoSuchMember, "Property").WithArguments("object", "Property").WithLocation(2, 12)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess1 = GetSyntax(tree, "object.Method"); + Assert.Equal(["void E.<>E__0.Method()"], model.GetMemberGroup(memberAccess1).ToTestDisplayStrings()); + + var memberAccess2 = GetSyntax(tree, "object.Property"); + Assert.Equal([], model.GetMemberGroup(memberAccess2).ToTestDisplayStrings()); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : handle GetMemberGroup on a property access + } + + [Fact] + public void ExtensionMemberLookup_InterpolationHandler_Simple() + { + var src = """ +_ = f($"{(object)1} {f2()}"); + +static int f(InterpolationHandler s) => 0; +static string f2() => "hello"; + +[System.Runtime.CompilerServices.InterpolatedStringHandler] +public struct InterpolationHandler +{ + public InterpolationHandler(int literalLength, int formattedCount) => throw null; + public void AppendLiteral(string value) { } + public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; +} +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void ExtensionMemberLookup_InterpolationHandler_AppendLiteralExtensionMethod() + { + var src = """ +_ = f($"{(object)1} {f2()}"); + +static int f(InterpolationHandler s) => 0; +static string f2() => "hello"; + +[System.Runtime.CompilerServices.InterpolatedStringHandler] +public struct InterpolationHandler +{ + public InterpolationHandler(int literalLength, int formattedCount) => throw null; + public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; +} + +public static class Extensions +{ + public static void AppendLiteral(this InterpolationHandler ih, string value) { } +} +"""; + + // Interpolation handlers don't allow extension methods + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics( + // (1,20): error CS1061: 'InterpolationHandler' does not contain a definition for 'AppendLiteral' and no accessible extension method 'AppendLiteral' accepting a first argument of type 'InterpolationHandler' could be found (are you missing a using directive or an assembly reference?) + // _ = f($"{(object)1} {f2()}"); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, " ").WithArguments("InterpolationHandler", "AppendLiteral").WithLocation(1, 20), + // (1,20): error CS8941: Interpolated string handler method '?.()' is malformed. It does not return 'void' or 'bool'. + // _ = f($"{(object)1} {f2()}"); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnMalformed, " ").WithArguments("?.()").WithLocation(1, 20)); + } + + [Fact] + public void ExtensionMemberLookup_InterpolationHandler_AppendLiteralExtensionDeclarationMethod() + { + var src = """ +_ = f($"{(object)1} {f2()}"); + +static int f(InterpolationHandler s) => 0; +static string f2() => "hello"; + +[System.Runtime.CompilerServices.InterpolatedStringHandler] +public struct InterpolationHandler +{ + public InterpolationHandler(int literalLength, int formattedCount) => throw null; + public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; +} + +static class E +{ + extension(InterpolationHandler i) + { + public void AppendLiteral(string value) { } + } +} +"""; + + // Interpolation handlers don't allow extension methods + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics( + // (1,20): error CS1061: 'InterpolationHandler' does not contain a definition for 'AppendLiteral' and no accessible extension method 'AppendLiteral' accepting a first argument of type 'InterpolationHandler' could be found (are you missing a using directive or an assembly reference?) + // _ = f($"{(object)1} {f2()}"); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, " ").WithArguments("InterpolationHandler", "AppendLiteral").WithLocation(1, 20), + // (1,20): error CS8941: Interpolated string handler method '?.()' is malformed. It does not return 'void' or 'bool'. + // _ = f($"{(object)1} {f2()}"); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnMalformed, " ").WithArguments("?.()").WithLocation(1, 20)); + } + + [Fact] + public void ExtensionMemberLookup_InterpolationHandler_AppendFormattedExtensionMethod() + { + var src = """ +/**/ +_ = f($"{(object)1} {f2()}"); +/**/ + +static int f(InterpolationHandler s) => 0; +static string f2() => "hello"; + +[System.Runtime.CompilerServices.InterpolatedStringHandler] +public struct InterpolationHandler +{ + public InterpolationHandler(int literalLength, int formattedCount) => throw null; + public void AppendLiteral(string value) { } +} + +public static class Extensions +{ + public static void AppendFormatted(this InterpolationHandler ih, T hole, int alignment = 0, string format = null) { } +} +"""; + + // Interpolation handlers don't allow extension methods + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics( + // (2,9): error CS1061: 'InterpolationHandler' does not contain a definition for 'AppendFormatted' and no accessible extension method 'AppendFormatted' accepting a first argument of type 'InterpolationHandler' could be found (are you missing a using directive or an assembly reference?) + // _ = f($"{(object)1} {f2()}"); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "{(object)1}").WithArguments("InterpolationHandler", "AppendFormatted").WithLocation(2, 9), + // (2,9): error CS8941: Interpolated string handler method '?.()' is malformed. It does not return 'void' or 'bool'. + // _ = f($"{(object)1} {f2()}"); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnMalformed, "{(object)1}").WithArguments("?.()").WithLocation(2, 9), + // (2,21): error CS1061: 'InterpolationHandler' does not contain a definition for 'AppendFormatted' and no accessible extension method 'AppendFormatted' accepting a first argument of type 'InterpolationHandler' could be found (are you missing a using directive or an assembly reference?) + // _ = f($"{(object)1} {f2()}"); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "{f2()}").WithArguments("InterpolationHandler", "AppendFormatted").WithLocation(2, 21), + // (2,21): error CS8941: Interpolated string handler method '?.()' is malformed. It does not return 'void' or 'bool'. + // _ = f($"{(object)1} {f2()}"); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnMalformed, "{f2()}").WithArguments("?.()").WithLocation(2, 21) + ); + } + + [Fact] + public void ExtensionMemberLookup_InterpolationHandler_AppendFormattedExtensionTypeMethod() + { + var src = """ +_ = f($"{(object)1} {f2()}"); + +static int f(InterpolationHandler s) => 0; +static string f2() => "hello"; + +[System.Runtime.CompilerServices.InterpolatedStringHandler] +public struct InterpolationHandler +{ + public InterpolationHandler(int literalLength, int formattedCount) => throw null; + public void AppendLiteral(string value) { } +} + +static class E +{ + extension(InterpolationHandler i) + { + public void AppendFormatted(T hole, int alignment = 0, string format = null) { } + } +} +"""; + + // Interpolation handlers don't allow extension methods + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics( + // (1,9): error CS1061: 'InterpolationHandler' does not contain a definition for 'AppendFormatted' and no accessible extension method 'AppendFormatted' accepting a first argument of type 'InterpolationHandler' could be found (are you missing a using directive or an assembly reference?) + // _ = f($"{(object)1} {f2()}"); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "{(object)1}").WithArguments("InterpolationHandler", "AppendFormatted").WithLocation(1, 9), + // (1,9): error CS8941: Interpolated string handler method '?.()' is malformed. It does not return 'void' or 'bool'. + // _ = f($"{(object)1} {f2()}"); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnMalformed, "{(object)1}").WithArguments("?.()").WithLocation(1, 9), + // (1,21): error CS1061: 'InterpolationHandler' does not contain a definition for 'AppendFormatted' and no accessible extension method 'AppendFormatted' accepting a first argument of type 'InterpolationHandler' could be found (are you missing a using directive or an assembly reference?) + // _ = f($"{(object)1} {f2()}"); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "{f2()}").WithArguments("InterpolationHandler", "AppendFormatted").WithLocation(1, 21), + // (1,21): error CS8941: Interpolated string handler method '?.()' is malformed. It does not return 'void' or 'bool'. + // _ = f($"{(object)1} {f2()}"); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnMalformed, "{f2()}").WithArguments("?.()").WithLocation(1, 21)); + } + + [Fact] + public void LiteralReceiver_Property_Enum_Set() + { + var src = """ +Enum.Zero.Property = 1; + +enum Enum +{ + Zero +} + +static class E +{ + extension(Enum e) + { + public int Property { set => throw null; } + } +} +"""; + var comp = CreateCompilation(src); + // Consider improving the error message + comp.VerifyEmitDiagnostics( + // (1,1): error CS0131: The left-hand side of an assignment must be a variable, property or indexer + // Enum.Zero.Property = 1; + Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "Enum.Zero.Property").WithLocation(1, 1)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "Enum.Zero.Property"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["System.Int32 E.<>E__0.Property { set; }"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(CandidateReason.NotAVariable, model.GetSymbolInfo(memberAccess).CandidateReason); + Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : handle GetMemberGroup on a property access + } + + [Fact] + public void LiteralReceiver_Property_Integer_ForLong() + { + var src = """ +1.Property = 42; +_ = 2.Property; + +static class E +{ + extension(long l) + { + public int Property { get { System.Console.Write("get "); return 42; } set { System.Console.Write("set "); } } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,1): error CS9286: 'int' does not contain a definition for 'Property' and no accessible extension member 'Property' for receiver of type 'int' could be found (are you missing a using directive or an assembly reference?) + // 1.Property = 42; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "1.Property").WithArguments("int", "Property").WithLocation(1, 1), + // (2,5): error CS9286: 'int' does not contain a definition for 'Property' and no accessible extension member 'Property' for receiver of type 'int' could be found (are you missing a using directive or an assembly reference?) + // _ = 2.Property; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "2.Property").WithArguments("int", "Property").WithLocation(2, 5)); + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : review the behavior of the semantic model APIs + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess1 = GetSyntax(tree, "1.Property"); + Assert.Equal("System.Int32 E.<>E__0.Property { get; set; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetSymbolInfo(memberAccess1).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(CandidateReason.None, model.GetSymbolInfo(memberAccess1).CandidateReason); + + var memberAccess2 = GetSyntax(tree, "2.Property"); + Assert.Equal("System.Int32 E.<>E__0.Property { get; set; }", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetSymbolInfo(memberAccess2).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(CandidateReason.None, model.GetSymbolInfo(memberAccess2).CandidateReason); + } + + [Fact] + public void LiteralReceiver_Property_String() + { + var src = """ +"".Property = 42; +_ = "".Property; + +static class E +{ + extension(string s) + { + public int Property { get { System.Console.Write("get "); return 42; } set { System.Console.Write("set "); } } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "set get").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess1 = GetSyntaxes(tree, "\"\".Property").First(); + Assert.Equal("System.Int32 E.<>E__0.Property { get; set; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); + + var memberAccess2 = GetSyntaxes(tree, "\"\".Property").Last(); + Assert.Equal("System.Int32 E.<>E__0.Property { get; set; }", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString()); + } + + [Fact] + public void SwitchReceiver_Property_String() + { + var src = """ +bool b = true; +(b switch { true => "", _ => "" }).Property = 42; +_ = (b switch { true => "", _ => "" }).Property; + +static class E +{ + extension(string s) + { + public int Property { get { System.Console.Write("get "); return 42; } set { System.Console.Write("set "); } } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "set get").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess1 = GetSyntaxes(tree, """(b switch { true => "", _ => "" }).Property""").First(); + Assert.Equal("System.Int32 E.<>E__0.Property { get; set; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); + + var memberAccess2 = GetSyntaxes(tree, """(b switch { true => "", _ => "" }).Property""").Last(); + Assert.Equal("System.Int32 E.<>E__0.Property { get; set; }", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ConditionalReceiver_Property_String() + { + var src = """ +bool b = true; +(b ? "" : null).Property = 42; +_ = (b ? "" : null).Property; + +static class E +{ + extension(string s) + { + public int Property { get { System.Console.Write("get "); return 42; } set { System.Console.Write("set "); } } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "set get").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess1 = GetSyntaxes(tree, """(b ? "" : null).Property""").First(); + Assert.Equal("System.Int32 E.<>E__0.Property { get; set; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); + + var memberAccess2 = GetSyntaxes(tree, """(b ? "" : null).Property""").Last(); + Assert.Equal("System.Int32 E.<>E__0.Property { get; set; }", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString()); + } + + [Fact] + public void LiteralReceiver_Property_Integer_Get() + { + var src = """ +_ = 1.Property; + +static class E +{ + extension(int i) + { + public int Property { get { System.Console.Write("get"); return 42; } } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "get").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "1.Property"); + Assert.Equal("System.Int32 E.<>E__0.Property { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void LiteralReceiver_Property_Integer_Set() + { + var src = """ +1.Property = 1; + +static class E +{ + extension(int i) + { + public int Property { set => throw null; } + } +} +"""; + var comp = CreateCompilation(src); + // Consider improving the error message + comp.VerifyEmitDiagnostics( + // (1,1): error CS0131: The left-hand side of an assignment must be a variable, property or indexer + // 1.Property = 1; + Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "1.Property").WithLocation(1, 1)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "1.Property"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["System.Int32 E.<>E__0.Property { set; }"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(CandidateReason.NotAVariable, model.GetSymbolInfo(memberAccess).CandidateReason); + } + + [Fact] + public void LiteralReceiver_Property_Null() + { + var src = """ +null.Property = 1; +_ = null.Property; + +static class E +{ + extension(object o) + { + public int Property { get => throw null; set => throw null; } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,1): error CS0023: Operator '.' cannot be applied to operand of type '' + // null.Property = 1; + Diagnostic(ErrorCode.ERR_BadUnaryOp, "null.Property").WithArguments(".", "").WithLocation(1, 1), + // (2,5): error CS0023: Operator '.' cannot be applied to operand of type '' + // _ = null.Property; + Diagnostic(ErrorCode.ERR_BadUnaryOp, "null.Property").WithArguments(".", "").WithLocation(2, 5)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess1 = GetSyntaxes(tree, "null.Property").First(); + Assert.Null(model.GetSymbolInfo(memberAccess1).Symbol); + Assert.Equal([], model.GetSymbolInfo(memberAccess1).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(CandidateReason.None, model.GetSymbolInfo(memberAccess1).CandidateReason); + + var memberAccess2 = GetSyntaxes(tree, "null.Property").Last(); + Assert.Null(model.GetSymbolInfo(memberAccess2).Symbol); + Assert.Equal([], model.GetSymbolInfo(memberAccess2).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(CandidateReason.None, model.GetSymbolInfo(memberAccess2).CandidateReason); + } + + [Fact] + public void LiteralReceiver_Property_Default() + { + var src = """ +default.Property = 1; +_ = default.Property; + +static class E +{ + extension(object o) + { + public int Property { get => throw null; set => throw null; } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,1): error CS8716: There is no target type for the default literal. + // default.Property = 1; + Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(1, 1), + // (2,5): error CS8716: There is no target type for the default literal. + // _ = default.Property; + Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(2, 5)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess1 = GetSyntaxes(tree, "default.Property").First(); + Assert.Equal("System.Int32 E.<>E__0.Property { get; set; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetSymbolInfo(memberAccess1).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(CandidateReason.None, model.GetSymbolInfo(memberAccess1).CandidateReason); + + var memberAccess2 = GetSyntaxes(tree, "default.Property").Last(); + Assert.Equal("System.Int32 E.<>E__0.Property { get; set; }", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetSymbolInfo(memberAccess2).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(CandidateReason.None, model.GetSymbolInfo(memberAccess2).CandidateReason); + } + + [Fact] + public void LiteralReceiver_Property_Tuple_Get() + { + var src = """ +_ = (1, 2).Property; + +static class E +{ + extension((int, int) t) + { + public int Property { get { System.Console.Write("get "); return 42; } } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "get").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "(1, 2).Property"); + Assert.Equal("System.Int32 E.<>E__0.Property { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void LiteralReceiver_Property_Tuple_Set() + { + var src = """ +(1, 2).Property = 1; + +static class E +{ + extension((int, int) t) + { + public int Property { set { System.Console.Write($"set(value)"); }} + } +} +"""; + var comp = CreateCompilation(src); + // Consider improving the error message + comp.VerifyEmitDiagnostics( + // (1,1): error CS0131: The left-hand side of an assignment must be a variable, property or indexer + // (1, 2).Property = 1; + Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "(1, 2).Property").WithLocation(1, 1)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "(1, 2).Property"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["System.Int32 E.<>E__0.Property { set; }"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(CandidateReason.NotAVariable, model.GetSymbolInfo(memberAccess).CandidateReason); + } + + [Fact] + public void LiteralReceiver_Property_Tuple_Default() + { + var src = """ +(default, default).Property = 1; +_ = (default, default).Property; + +static class E +{ + extension((object, object) t) + { + public int Property { get => throw null; set => throw null; } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,2): error CS8716: There is no target type for the default literal. + // (default, default).Property = 1; + Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(1, 2), + // (1,11): error CS8716: There is no target type for the default literal. + // (default, default).Property = 1; + Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(1, 11), + // (2,6): error CS8716: There is no target type for the default literal. + // _ = (default, default).Property; + Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(2, 6), + // (2,15): error CS8716: There is no target type for the default literal. + // _ = (default, default).Property; + Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(2, 15)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess1 = GetSyntaxes(tree, "(default, default).Property").First(); + Assert.Null(model.GetSymbolInfo(memberAccess1).Symbol); + Assert.Equal([], model.GetSymbolInfo(memberAccess1).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(CandidateReason.None, model.GetSymbolInfo(memberAccess1).CandidateReason); + + var memberAccess2 = GetSyntaxes(tree, "(default, default).Property").Last(); + Assert.Null(model.GetSymbolInfo(memberAccess2).Symbol); + Assert.Equal([], model.GetSymbolInfo(memberAccess2).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(CandidateReason.None, model.GetSymbolInfo(memberAccess2).CandidateReason); + } + + [Fact] + public void LiteralReceiver_Property_Tuple_Integer_ForLong() + { + var src = """ +(1, 1).Property = 1; +_ = (2, 2).Property; + +static class E +{ + extension((long, long) t) + { + public int Property { get => throw null; set => throw null; } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,1): error CS9286: '(int, int)' does not contain a definition for 'Property' and no accessible extension member 'Property' for receiver of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) + // (1, 1).Property = 1; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "(1, 1).Property").WithArguments("(int, int)", "Property").WithLocation(1, 1), + // (2,5): error CS9286: '(int, int)' does not contain a definition for 'Property' and no accessible extension member 'Property' for receiver of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) + // _ = (2, 2).Property; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "(2, 2).Property").WithArguments("(int, int)", "Property").WithLocation(2, 5)); + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : review the behavior of the semantic model APIs + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess1 = GetSyntax(tree, "(1, 1).Property"); + Assert.Equal("System.Int32 E.<>E__0.Property { get; set; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetSymbolInfo(memberAccess1).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(CandidateReason.None, model.GetSymbolInfo(memberAccess1).CandidateReason); + + var memberAccess2 = GetSyntax(tree, "(2, 2).Property"); + Assert.Equal("System.Int32 E.<>E__0.Property { get; set; }", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetSymbolInfo(memberAccess2).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(CandidateReason.None, model.GetSymbolInfo(memberAccess2).CandidateReason); + } + + [Fact] + public void PreferMoreSpecific_Static_MethodAndProperty() + { + var src = """ +System.Console.Write(object.M); + +static class E1 +{ + extension(object) + { + public static string M() => throw null; + } +} + +static class E2 +{ + extension(object) + { + public static string M => throw null; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,22): error CS9286: 'object' does not contain a definition for 'M' and no accessible extension member 'M' for receiver of type 'object' could be found (are you missing a using directive or an assembly reference?) + // System.Console.Write(object.M); + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "object.M").WithArguments("object", "M").WithLocation(1, 22)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["System.String E1.<>E__0.M()", "System.String E2.<>E__0.M { get; }"], + model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + Assert.Empty(model.GetMemberGroup(memberAccess)); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : consider handling BoundBadExpression better + } + + [Fact] + public void PreferMoreSpecific_Static_MethodAndProperty_Generic() + { + var src = """ +System.Console.Write(object.M); + +static class E1 +{ + extension(T) + { + public static string M() => throw null; + } +} + +static class E2 +{ + extension(T) + { + public static string M => throw null; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,22): error CS9286: 'object' does not contain a definition for 'M' and no accessible extension member 'M' for receiver of type 'object' could be found (are you missing a using directive or an assembly reference?) + // System.Console.Write(object.M); + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "object.M").WithArguments("object", "M").WithLocation(1, 22)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : consider handling BoundBadExpression better + Assert.Equal(["System.String E1.<>E__0.M()", "System.String E2.<>E__0.M { get; }"], + model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + Assert.Empty(model.GetMemberGroup(memberAccess)); + } + + [Fact] + public void PreferMoreSpecific_Static_MethodAndProperty_Invocation() + { + var src = """ +System.Console.Write(object.M()); + +static class E1 +{ + extension(object) + { + public static string M() => "ran"; + } +} + +static class E2 +{ + extension(object) + { + public static string M => throw null; // not invocable + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Equal("System.String E1.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(["System.String E1.<>E__0.M()", "System.String E2.<>E__0.M { get; }"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void GetCompatibleExtensions_TwoSubstitutions() + { + var src = """ +C.M(); +new C().M2(); + +interface I { } +class C : I, I { } + +static class E +{ + extension(I) + { + public static void M() { } + } + + public static void M2(this I i) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyDiagnostics( + // (1,3): error CS1061: 'C' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?) + // C.M(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("C", "M").WithLocation(1, 3), + // (2,9): error CS1061: 'C' does not contain a definition for 'M2' and no accessible extension method 'M2' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?) + // new C().M2(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M2").WithArguments("C", "M2").WithLocation(2, 9)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var memberAccess1 = GetSyntax(tree, "C.M"); + Assert.Null(model.GetSymbolInfo(memberAccess1).Symbol); + Assert.Equal([], model.GetSymbolInfo(memberAccess1).CandidateSymbols.ToTestDisplayStrings()); + Assert.Empty(model.GetMemberGroup(memberAccess1)); + + var memberAccess2 = GetSyntax(tree, "new C().M2"); + Assert.Null(model.GetSymbolInfo(memberAccess2).Symbol); + Assert.Equal([], model.GetSymbolInfo(memberAccess2).CandidateSymbols.ToTestDisplayStrings()); + Assert.Empty(model.GetMemberGroup(memberAccess2)); + } + + [Theory, ClassData(typeof(ThreePermutationGenerator))] + public void PreferMoreSpecific_Static_MethodAndMoreSpecificInvocablePropertyAndMoreSpecificMethod(int first, int second, int third) + { + string[] segments = [ + """ + static class E1 + { + extension(object) + { + public static string M() => throw null; + } + } + """, + """ + static class E2 + { + extension(C) + { + public static System.Func M => null; + } + } + """, + """ + static class E3 + { + extension(C) + { + public static string M() => throw null; + } + } + """]; + + var src = $$""" +System.Console.Write(C.M()); + +class C { } + +{{segments[first]}} + +{{segments[second]}} + +{{segments[third]}} +"""; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics( + // (1,22): error CS9286: 'C' does not contain a definition for 'M' and no accessible extension member 'M' for receiver of type 'C' could be found (are you missing a using directive or an assembly reference?) + // System.Console.Write(C.M()); + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "C.M").WithArguments("C", "M").WithLocation(1, 22)); + } + + [Fact] + public void AmbiguousCallOnInterface() + { + var src = """ +I2.M(); + +interface I +{ + public static void M() { } +} + +interface I2 : I, I { } +"""; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : consider improving the symbols in this error message + comp.VerifyEmitDiagnostics( + // (1,4): error CS0121: The call is ambiguous between the following methods or properties: 'I.M()' and 'I.M()' + // I2.M(); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("I.M()", "I.M()").WithLocation(1, 4)); + } + + [Fact] + public void AmbiguousCallOnInterface_Generic() + { + var src = """ +I2.M(); + +interface I +{ + public static void M() { } +} + +interface I2 : I, I { } +"""; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics( + // (1,4): error CS0121: The call is ambiguous between the following methods or properties: 'I.M()' and 'I.M()' + // I2.M(); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("I.M()", "I.M()").WithLocation(1, 4)); + } + + [Fact] + public void OmittedTypeArguments() + { + var src = """ +object.P; +object.P<>; + +static class E +{ + extension(object) + { + public static int P => 42; + } +} +"""; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics( + // (1,1): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement + // object.P; + Diagnostic(ErrorCode.ERR_IllegalStatement, "object.P").WithLocation(1, 1), + // (1,8): error CS0117: 'object' does not contain a definition for 'P' + // object.P; + Diagnostic(ErrorCode.ERR_NoSuchMember, "P").WithArguments("object", "P").WithLocation(1, 8), + // (2,1): error CS8389: Omitting the type argument is not allowed in the current context + // object.P<>; + Diagnostic(ErrorCode.ERR_OmittedTypeArgument, "object.P<>").WithLocation(2, 1), + // (2,1): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement + // object.P<>; + Diagnostic(ErrorCode.ERR_IllegalStatement, "object.P<>").WithLocation(2, 1), + // (2,8): error CS0117: 'object' does not contain a definition for 'P' + // object.P<>; + Diagnostic(ErrorCode.ERR_NoSuchMember, "P<>").WithArguments("object", "P").WithLocation(2, 8)); + } + + [Fact] + public void ExtensionMemberLookup_PatternBased_ForEach_NoMethod() + { + var src = """ +foreach (var x in new C()) +{ + System.Console.Write(x); + break; +} + +class C { } +class D { } + +static class E +{ + extension(C c) + { + public D GetEnumerator() => new D(); + } + extension(D d) + { + public bool MoveNext() => true; + public int Current => 42; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyDiagnostics( + // (1,19): error CS0117: 'D' does not contain a definition for 'Current' + // foreach (var x in new C()) + Diagnostic(ErrorCode.ERR_NoSuchMember, "new C()").WithArguments("D", "Current").WithLocation(1, 19), + // (1,19): error CS0202: foreach requires that the return type 'D' of 'E.extension(C).GetEnumerator()' must have a suitable public 'MoveNext' method and public 'Current' property + // foreach (var x in new C()) + Diagnostic(ErrorCode.ERR_BadGetEnumerator, "new C()").WithArguments("D", "E.extension(C).GetEnumerator()").WithLocation(1, 19) + ); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var loop = tree.GetRoot().DescendantNodes().OfType().Single(); + Assert.Null(model.GetForEachStatementInfo(loop).GetEnumeratorMethod); + Assert.Null(model.GetForEachStatementInfo(loop).MoveNextMethod); + Assert.Null(model.GetForEachStatementInfo(loop).CurrentProperty); + } + + [Fact] + public void ExtensionMemberLookup_PatternBased_ForEach_NoApplicableMethod() + { + var src = """ +foreach (var x in new C()) +{ + System.Console.Write(x); + break; +} + +class C +{ + public void GetEnumerator(int notApplicable) { } // not applicable +} +class D { } + +static class E +{ + extension(C c) + { + public D GetEnumerator() => new D(); + } + extension(D d) + { + public bool MoveNext() => true; + public int Current => 42; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,19): error CS0117: 'D' does not contain a definition for 'Current' + // foreach (var x in new C()) + Diagnostic(ErrorCode.ERR_NoSuchMember, "new C()").WithArguments("D", "Current").WithLocation(1, 19), + // (1,19): error CS0202: foreach requires that the return type 'D' of 'E.extension(C).GetEnumerator()' must have a suitable public 'MoveNext' method and public 'Current' property + // foreach (var x in new C()) + Diagnostic(ErrorCode.ERR_BadGetEnumerator, "new C()").WithArguments("D", "E.extension(C).GetEnumerator()").WithLocation(1, 19) + ); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var loop = tree.GetRoot().DescendantNodes().OfType().Single(); + Assert.Null(model.GetForEachStatementInfo(loop).GetEnumeratorMethod); + Assert.Null(model.GetForEachStatementInfo(loop).MoveNextMethod); + Assert.Null(model.GetForEachStatementInfo(loop).CurrentProperty); + } + + [Fact] + public void ExtensionMemberLookup_PatternBased_ForEach_WrongArity() + { + var src = """ +using System.Collections; + +foreach (var x in new C()) { } + +class C { } + +static class E +{ + extension(C c) + { + public IEnumerator GetEnumerator() => throw null; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,19): error CS0411: The type arguments for method 'E.extension(C).GetEnumerator()' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // foreach (var x in new C()) { } + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "new C()").WithArguments("E.extension(C).GetEnumerator()").WithLocation(3, 19), + // (3,19): error CS1579: foreach statement cannot operate on variables of type 'C' because 'C' does not contain a public instance or extension definition for 'GetEnumerator' + // foreach (var x in new C()) { } + Diagnostic(ErrorCode.ERR_ForEachMissingMember, "new C()").WithArguments("C", "GetEnumerator").WithLocation(3, 19)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var loop = tree.GetRoot().DescendantNodes().OfType().Single(); + Assert.Null(model.GetForEachStatementInfo(loop).GetEnumeratorMethod); + } + + [Fact] + public void ExtensionMemberLookup_PatternBased_ForEach_NonInvocable() + { + var src = """ +using System.Collections; + +foreach (var x in new C()) { } + +class C { } + +static class E +{ + extension(C c) + { + public IEnumerator GetEnumerator => throw null; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,19): error CS1579: foreach statement cannot operate on variables of type 'C' because 'C' does not contain a public instance or extension definition for 'GetEnumerator' + // foreach (var x in new C()) { } + Diagnostic(ErrorCode.ERR_ForEachMissingMember, "new C()").WithArguments("C", "GetEnumerator").WithLocation(3, 19)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var loop = tree.GetRoot().DescendantNodes().OfType().Single(); + Assert.Null(model.GetForEachStatementInfo(loop).GetEnumeratorMethod); + } + + [Fact] + public void ExtensionMemberLookup_PatternBased_Deconstruct_NoMethod() + { + var src = """ +var (x, y) = new C(); +System.Console.Write((x, y)); + +class C { } + +static class E +{ + extension(C c) + { + public void Deconstruct(out int i, out int j) { i = 42; j = 43; } + } +} +"""; + var comp = CreateCompilation(src); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : confirm when spec'ing pattern-based deconstruction + CompileAndVerify(comp, expectedOutput: "(42, 43)").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var deconstruction = tree.GetRoot().DescendantNodes().OfType().First(); + + Assert.Equal("void E.<>E__0.Deconstruct(out System.Int32 i, out System.Int32 j)", + model.GetDeconstructionInfo(deconstruction).Method.ToTestDisplayString()); + } + + [Fact] + public void ExtensionMemberLookup_PatternBased_Deconstruct_FallbackToExtensionMethod() + { + // If the method from the extension type is not applicable, we fall back + // to a Deconstruct extension method + var src = """ +var (x, y) = new C(); +System.Console.Write((x, y)); + +public class C { } + +static class E +{ + extension(C c) + { + public void Deconstruct(int inapplicable) => throw null; + } +} + +public static class E2 +{ + public static void Deconstruct(this C c, out int i, out int j) { i = 42; j = 43; } +} +"""; + var comp = CreateCompilation(src); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : confirm when spec'ing pattern-based deconstruction + CompileAndVerify(comp, expectedOutput: "(42, 43)").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var deconstruction = tree.GetRoot().DescendantNodes().OfType().First(); + + Assert.Equal("void E2.Deconstruct(this C c, out System.Int32 i, out System.Int32 j)", + model.GetDeconstructionInfo(deconstruction).Method.ToTestDisplayString()); + } + + [Fact] + public void ExtensionMemberLookup_PatternBased_Deconstruct_DelegateTypeProperty() + { + var src = """ +var (x1, y1) = new C1(); + +var (x2, y2) = new C2(); + +class C1 { } + +class C2 +{ + public D Deconstruct => (out int i, out int j) => { i = 42; j = 43; }; +} + +delegate void D(out int i, out int j); + +static class E +{ + extension(C1 c) + { + public D Deconstruct => (out int i, out int j) => { i = 42; j = 43; }; + } +} +"""; + var comp = CreateCompilation(src); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : revisit pattern-based deconstruction + comp.VerifyDiagnostics( + // (1,6): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x1'. + // var (x1, y1) = new C1(); + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x1").WithArguments("x1").WithLocation(1, 6), + // (1,10): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'y1'. + // var (x1, y1) = new C1(); + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "y1").WithArguments("y1").WithLocation(1, 10), + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : It looks like the following error is not reported for instance scenario. Noise? + + // (1,16): error CS1061: 'C1' does not contain a definition for 'Deconstruct' and no accessible extension method 'Deconstruct' accepting a first argument of type 'C1' could be found (are you missing a using directive or an assembly reference?) + // var (x1, y1) = new C1(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "new C1()").WithArguments("C1", "Deconstruct").WithLocation(1, 16), + + // (1,16): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'C1', with 2 out parameters and a void return type. + // var (x1, y1) = new C1(); + Diagnostic(ErrorCode.ERR_MissingDeconstruct, "new C1()").WithArguments("C1", "2").WithLocation(1, 16), + // (3,6): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x2'. + // var (x2, y2) = new C2(); + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x2").WithArguments("x2").WithLocation(3, 6), + // (3,10): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'y2'. + // var (x2, y2) = new C2(); + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "y2").WithArguments("y2").WithLocation(3, 10), + // (3,16): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'C2', with 2 out parameters and a void return type. + // var (x2, y2) = new C2(); + Diagnostic(ErrorCode.ERR_MissingDeconstruct, "new C2()").WithArguments("C2", "2").WithLocation(3, 16) + ); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var deconstruction = tree.GetRoot().DescendantNodes().OfType().First(); + + Assert.Null(model.GetDeconstructionInfo(deconstruction).Method); + } + + [Fact] + public void ExtensionMemberLookup_PatternBased_Deconstruct_DynamicProperty() + { + var src = """ +var (x, y) = new C(); + +class C { } + +static class E +{ + extension(C c) + { + public dynamic Deconstruct => throw null; + } +} +"""; + var comp = CreateCompilation(src); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : revisit pattern-based deconstruction + comp.VerifyEmitDiagnostics( + // (1,6): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x'. + // var (x, y) = new C(); + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x").WithArguments("x").WithLocation(1, 6), + // (1,9): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'y'. + // var (x, y) = new C(); + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "y").WithArguments("y").WithLocation(1, 9), + // (1,14): error CS1061: 'C' does not contain a definition for 'Deconstruct' and no accessible extension method 'Deconstruct' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?) + // var (x, y) = new C(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "new C()").WithArguments("C", "Deconstruct").WithLocation(1, 14), + // (1,14): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'C', with 2 out parameters and a void return type. + // var (x, y) = new C(); + Diagnostic(ErrorCode.ERR_MissingDeconstruct, "new C()").WithArguments("C", "2").WithLocation(1, 14) + ); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var deconstruction = tree.GetRoot().DescendantNodes().OfType().First(); + + Assert.Null(model.GetDeconstructionInfo(deconstruction).Method); + } + + [Fact] + public void ExtensionMemberLookup_PatternBased_Deconstruct_NoApplicableMethod() + { + var src = """ +var (x, y) = new C(); +System.Console.Write((x, y)); + +class C +{ + public void Deconstruct() { } // not applicable +} + +static class E +{ + extension(C c) + { + public void Deconstruct(out int i, out int j) { i = 42; j = 43; } + } +} +"""; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : confirm when spec'ing pattern-based deconstruction + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "(42, 43)").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var deconstruction = tree.GetRoot().DescendantNodes().OfType().First(); + + Assert.Equal("void E.<>E__0.Deconstruct(out System.Int32 i, out System.Int32 j)", + model.GetDeconstructionInfo(deconstruction).Method.ToTestDisplayString()); + } + + [Fact] + public void ExtensionMemberLookup_PatternBased_Dispose_Async_NoMethod() + { + var src = """ +using System.Threading.Tasks; + +/**/ +await using var x1 = new C1(); +/**/ + +await using var x2 = new C2(); + +class C1 { } +class C2 { } + +static class E +{ + extension(C1 c) + { + public async Task DisposeAsync() + { + System.Console.Write("RAN"); + await Task.Yield(); + } + } + + public static async Task DisposeAsync(this C2 c) + { + System.Console.Write("RAN"); + await Task.Yield(); + } +} +"""; + var comp = CreateCompilation(src); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : confirm when spec'ing pattern-based disposal + + var expectedDiagnostics = new[] { + // (4,1): error CS8410: 'C1': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. + // await using var x1 = new C1(); + Diagnostic(ErrorCode.ERR_NoConvToIAsyncDisp, "await using var x1 = new C1();").WithArguments("C1").WithLocation(4, 1), + // (7,1): error CS8410: 'C2': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. + // await using var x2 = new C2(); + Diagnostic(ErrorCode.ERR_NoConvToIAsyncDisp, "await using var x2 = new C2();").WithArguments("C2").WithLocation(7, 1) + }; + + comp.VerifyDiagnostics(expectedDiagnostics); + + string expectedOperationTree = """ +IUsingDeclarationOperation(IsAsynchronous: True) (OperationKind.UsingDeclaration, Type: null, IsInvalid) (Syntax: 'await using ... = new C1();') + DeclarationGroup: + IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null, IsInvalid, IsImplicit) (Syntax: 'await using ... = new C1();') + IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null, IsInvalid) (Syntax: 'var x1 = new C1()') + Declarators: + IVariableDeclaratorOperation (Symbol: C1 x1) (OperationKind.VariableDeclarator, Type: null, IsInvalid) (Syntax: 'x1 = new C1()') + Initializer: + IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null, IsInvalid) (Syntax: '= new C1()') + IObjectCreationOperation (Constructor: C1..ctor()) (OperationKind.ObjectCreation, Type: C1, IsInvalid) (Syntax: 'new C1()') + Arguments(0) + Initializer: + null + Initializer: + null +"""; + + VerifyOperationTreeAndDiagnosticsForTest(src, expectedOperationTree, expectedDiagnostics); + } + + [Fact] + public void TestPatternBasedDisposal_ExtensionMethod() + { + string source = @" +public class C +{ + public static async System.Threading.Tasks.Task Main() + { + await using (var x = new C()) + { + } + + return 1; + } +} +public static class Extensions +{ + extension (C c) + { + public System.Threading.Tasks.ValueTask DisposeAsync() + => throw null; + } +} +"; + // extension methods do not contribute to pattern-based disposal + var comp = CreateCompilationWithTasksExtensions(new[] { source, IAsyncDisposableDefinition }, options: TestOptions.DebugExe); + comp.VerifyDiagnostics( + // 0.cs(6,22): error CS8410: 'C': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. + // await using (var x = new C()) + Diagnostic(ErrorCode.ERR_NoConvToIAsyncDisp, "var x = new C()").WithArguments("C").WithLocation(6, 22) + ); + } + + [Fact] + public void PatternBased_Dispose_Async_DelegateTypeProperty() + { + var src = """ +using System.Threading.Tasks; + +await using var x = new C(); + +class C +{ + public System.Func DisposeAsync => async () => { System.Console.Write("ran2"); await Task.Yield(); }; +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,1): error CS8410: 'C': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. + // await using var x = new C(); + Diagnostic(ErrorCode.ERR_NoConvToIAsyncDisp, "await using var x = new C();").WithArguments("C").WithLocation(3, 1) + ); + } + + [Fact] + public void ExtensionMemberLookup_PatternBased_Dispose_Async_DelegateTypeProperty() + { + var src = """ +using System.Threading.Tasks; + +await using var x = new C(); + +class C { } + +static class E +{ + extension(C c) + { + public System.Func DisposeAsync => async () => { System.Console.Write("ran2"); await Task.Yield(); }; + } +} +"""; + var comp = CreateCompilation(src); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 :(instance) confirm when spec'ing pattern-based disposal + comp.VerifyEmitDiagnostics( + // (3,1): error CS8410: 'C': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. + // await using var x = new C(); + Diagnostic(ErrorCode.ERR_NoConvToIAsyncDisp, "await using var x = new C();").WithArguments("C").WithLocation(3, 1) + ); + } + + [Fact] + public void ExtensionMemberLookup_PatternBased_Dispose_Async_NoApplicableMethod() + { + var src = """ +using System.Threading.Tasks; + +/**/ +await using var x = new C(); +/**/ + +class C +{ + public Task DisposeAsync(int notApplicable) => throw null; // not applicable +} + +static class E +{ + extension(C c) + { + public async Task DisposeAsync() + { + System.Console.Write("RAN"); + await Task.Yield(); + } + } +} +"""; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : confirm when spec'ing pattern-based disposal + var comp = CreateCompilation(src); + comp.VerifyDiagnostics( + // (4,1): error CS8410: 'C': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. + // await using var x = new C(); + Diagnostic(ErrorCode.ERR_NoConvToIAsyncDisp, "await using var x = new C();").WithArguments("C").WithLocation(4, 1) + ); + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : verify IOperation + } + + [Fact] + public void ExtensionMemberLookup_PatternBased_Dispose_RefStruct() + { + var src = """ +using var x1 = new S1(); +using var x2 = new S2(); + +ref struct S1 { } + +ref struct S2 +{ +} + +static class E +{ + extension(S1 s) + { + public void Dispose() { } + } + + public static void Dispose(this S2 s) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyDiagnostics( + // (1,1): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'. + // using var x1 = new S1(); + Diagnostic(ErrorCode.ERR_NoConvToIDisp, "using var x1 = new S1();").WithArguments("S1").WithLocation(1, 1), + // (2,1): error CS1674: 'S2': type used in a using statement must implement 'System.IDisposable'. + // using var x2 = new S2(); + Diagnostic(ErrorCode.ERR_NoConvToIDisp, "using var x2 = new S2();").WithArguments("S2").WithLocation(2, 1) + ); + } + + [Fact] + public void ExtensionMemberLookup_PatternBased_Fixed_NoMethod() + { + var text = """ +unsafe class C +{ + public static void Main() + { + fixed (int* p = new Fixable()) + { + System.Console.WriteLine(p[1]); + } + } +} + +class Fixable { } + +static class E +{ + extension(Fixable f) + { + public ref int GetPinnableReference() { System.Console.Write("pin "); return ref (new int[] { 1, 2, 3 })[0]; } + } +} +"""; + var comp = CreateCompilation(text, options: TestOptions.UnsafeReleaseExe); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : confirm when spec'ing pattern-based fixed + comp.VerifyEmitDiagnostics(); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : metadata is undone + } + + [Fact] + public void ExtensionMemberLookup_PatternBased_Fixed_NoMethod_DelegateTypeProperty() + { + var text = @" +unsafe class C +{ + public static void Main() + { + fixed (int* p = new Fixable1()) + { + System.Console.WriteLine(p[1]); + } + + fixed (int* p = new Fixable2()) + { + System.Console.WriteLine(p[1]); + } + } +} + +class Fixable1 { } + +class Fixable2 +{ + public MyDelegate GetPinnableReference => throw null; +} + +delegate ref int MyDelegate(); + +static class E +{ + extension(Fixable1 f) + { + public MyDelegate GetPinnableReference => throw null; + } +} +"; + var comp = CreateCompilation(text, options: TestOptions.UnsafeReleaseExe); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : confirm when spec'ing pattern-based fixed + comp.VerifyEmitDiagnostics( + // (6,25): error CS8385: The given expression cannot be used in a fixed statement + // fixed (int* p = new Fixable1()) + Diagnostic(ErrorCode.ERR_ExprCannotBeFixed, "new Fixable1()").WithLocation(6, 25), + // (11,25): error CS8385: The given expression cannot be used in a fixed statement + // fixed (int* p = new Fixable2()) + Diagnostic(ErrorCode.ERR_ExprCannotBeFixed, "new Fixable2()").WithLocation(11, 25) + ); + } + + [Fact] + public void ExtensionMemberLookup_PatternBased_Fixed_NoApplicableMethod() + { + var src = """ +unsafe class C +{ + public static void Main() + { + fixed (int* p = new Fixable()) + { + System.Console.WriteLine(p[1]); + } + } +} + +class Fixable +{ + public ref int GetPinnableReference(int notApplicable) => throw null; // not applicable +} + +static class E +{ + extension(Fixable f) + { + public ref int GetPinnableReference() { return ref (new int[] { 1, 2, 3 })[0]; } + } +} +"""; + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : confirm when spec'ing pattern-based fixed + var comp = CreateCompilation(src, options: TestOptions.UnsafeReleaseExe); + comp.VerifyEmitDiagnostics(); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : metadata is undone + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : verify IOperation + } + + [Fact] + public void ExtensionMemberLookup_PatternBased_Fixed_Static() + { + var text = @" +unsafe class C +{ + public static void Main() + { + fixed (int* p = new Fixable()) + { + } + } +} + +class Fixable { } + +static class E +{ + extension(Fixable f) + { + public static ref int GetPinnableReference() => throw null; + } +} +"; + + var comp = CreateCompilation(text, options: TestOptions.UnsafeReleaseExe); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : confirm when spec'ing pattern-based fixed + comp.VerifyEmitDiagnostics( + // (6,25): error CS0176: Member 'E.extension(Fixable).GetPinnableReference()' cannot be accessed with an instance reference; qualify it with a type name instead + // fixed (int* p = new Fixable()) + Diagnostic(ErrorCode.ERR_ObjectProhibited, "new Fixable()").WithArguments("E.extension(Fixable).GetPinnableReference()").WithLocation(6, 25), + // (6,25): error CS8385: The given expression cannot be used in a fixed statement + // fixed (int* p = new Fixable()) + Diagnostic(ErrorCode.ERR_ExprCannotBeFixed, "new Fixable()").WithLocation(6, 25)); + } + + [Fact] + public void ExtensionMemberLookup_PatternBased_Await_ExtensionIsCompleted() + { + var text = @" +using System; +using System.Runtime.CompilerServices; + +int i = await new C(); +System.Console.Write(i); + +class C +{ + public D GetAwaiter() => new D(); +} + +class D : INotifyCompletion +{ + public int GetResult() => 42; + public void OnCompleted(Action continuation) => throw null; +} + +static class E +{ + extension(D d) + { + public bool IsCompleted => true; + } +} +"; + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : confirm when spec'ing pattern-based await + var comp = CreateCompilation(text); + comp.VerifyEmitDiagnostics( + // (5,9): error CS0117: 'D' does not contain a definition for 'IsCompleted' + // int i = await new C(); + Diagnostic(ErrorCode.ERR_NoSuchMember, "await new C()").WithArguments("D", "IsCompleted").WithLocation(5, 9) + ); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : metadata is undone + } + + [Fact] + public void ExtensionMemberLookup_PatternBased_Await_ExtensionGetAwaiter() + { + var text = @" +using System; +using System.Runtime.CompilerServices; + +int i = await new C(); +System.Console.Write(i); + +class C +{ +} + +class D : INotifyCompletion +{ + public int GetResult() => 42; + public void OnCompleted(Action continuation) => throw null; + public bool IsCompleted => true; +} + +static class E +{ + extension(C c) + { + public D GetAwaiter() => new D(); + } +} +"; + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : confirm when spec'ing pattern-based await + var comp = CreateCompilation(text); + comp.VerifyEmitDiagnostics(); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : metadata is undone + } + + [Fact] + public void ExtensionMemberLookup_PatternBased_Await_ExtensionGetResult() + { + var text = @" +using System; +using System.Runtime.CompilerServices; + +int i = await new C(); +System.Console.Write(i); + +class C +{ + public D GetAwaiter() => new D(); +} + +class D : INotifyCompletion +{ + public void OnCompleted(Action continuation) => throw null; + public bool IsCompleted => true; +} + +static class E +{ + extension(D d) + { + public int GetResult() => 42; + } +} +"; + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : confirm when spec'ing pattern-based await + var comp = CreateCompilation(text); + + // The error is consistent with classic extension methods + comp.VerifyEmitDiagnostics( + // (5,9): error CS0117: 'D' does not contain a definition for 'GetResult' + // int i = await new C(); + Diagnostic(ErrorCode.ERR_NoSuchMember, "await new C()").WithArguments("D", "GetResult").WithLocation(5, 9) + ); + } + + [Fact] + public void ExtensionMemberLookup_PatternBased_IndexIndexer_NoLength() + { + var src = """ +var c = new C(); + +/**/ +_ = c[^1]; +/**/ + +class C +{ + public int this[int i] + { + get { System.Console.Write("indexer "); return 0; } + } +} + +static class E +{ + extension(C c) + { + public int Length + { + get { System.Console.Write("length "); return 42; } + } + } +} +"""; + DiagnosticDescription[] expectedDiagnostics = [ + // (4,7): error CS1503: Argument 1: cannot convert from 'System.Index' to 'int' + // _ = c[^1]; + Diagnostic(ErrorCode.ERR_BadArgType, "^1").WithArguments("1", "System.Index", "int").WithLocation(4, 7)]; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : revisit as part of "implicit indexer access" section + comp.VerifyEmitDiagnostics(expectedDiagnostics); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : metadata is undone + //CompileAndVerify(comp, expectedOutput: "length indexer"); + + string expectedOperationTree = """ +ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsInvalid) (Syntax: '_ = c[^1]') +Left: + IDiscardOperation (Symbol: System.Int32 _) (OperationKind.Discard, Type: System.Int32) (Syntax: '_') +Right: + IInvalidOperation (OperationKind.Invalid, Type: System.Int32, IsInvalid) (Syntax: 'c[^1]') + Children(2): + ILocalReferenceOperation: c (OperationKind.LocalReference, Type: C) (Syntax: 'c') + IUnaryOperation (UnaryOperatorKind.Hat) (OperationKind.Unary, Type: System.Index, IsInvalid) (Syntax: '^1') + Operand: + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsInvalid) (Syntax: '1') +"""; + + VerifyOperationTreeAndDiagnosticsForTest(src, expectedOperationTree, expectedDiagnostics, targetFramework: TargetFramework.Net70); + } + + [Fact] + public void ExtensionMemberLookup_PatternBased_RangeIndexer_NoMethod() + { + var src = """ +var c = new C(); + +/**/ +_ = c[1..^1]; +/**/ + +class C { } + +static class E +{ + extension(C c) + { + public int Slice(int i, int j) { System.Console.Write("slice "); return 0; } + + public int Length + { + get { System.Console.Write("length "); return 42; } + } + } +} +"""; + + DiagnosticDescription[] expectedDiagnostics = [ + // (4,5): error CS0021: Cannot apply indexing with [] to an expression of type 'C' + // _ = c[1..^1]; + Diagnostic(ErrorCode.ERR_BadIndexLHS, "c[1..^1]").WithArguments("C").WithLocation(4, 5)]; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : revisit as part of "implicit indexer access" section + comp.VerifyEmitDiagnostics(expectedDiagnostics); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : metadata is undone + //CompileAndVerify(comp, expectedOutput: "length slice"); + + string expectedOperationTree = """ +ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: ?, IsInvalid) (Syntax: '_ = c[1..^1]') +Left: + IDiscardOperation (Symbol: ? _) (OperationKind.Discard, Type: ?) (Syntax: '_') +Right: + IInvalidOperation (OperationKind.Invalid, Type: ?, IsInvalid) (Syntax: 'c[1..^1]') + Children(2): + IRangeOperation (OperationKind.Range, Type: System.Range, IsInvalid) (Syntax: '1..^1') + LeftOperand: + IConversionOperation (TryCast: False, Unchecked) (OperatorMethod: System.Index System.Index.op_Implicit(System.Int32 value)) (OperationKind.Conversion, Type: System.Index, IsInvalid, IsImplicit) (Syntax: '1') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: True) (MethodSymbol: System.Index System.Index.op_Implicit(System.Int32 value)) + Operand: + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsInvalid) (Syntax: '1') + RightOperand: + IUnaryOperation (UnaryOperatorKind.Hat) (OperationKind.Unary, Type: System.Index, IsInvalid) (Syntax: '^1') + Operand: + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsInvalid) (Syntax: '1') + ILocalReferenceOperation: c (OperationKind.LocalReference, Type: C, IsInvalid) (Syntax: 'c') +"""; + + VerifyOperationTreeAndDiagnosticsForTest(src, expectedOperationTree, expectedDiagnostics, targetFramework: TargetFramework.Net70); + } + + [Fact] + public void ExtensionMemberLookup_PatternBased_RangeIndexer_NoApplicableMethod() + { + var src = """ +var c = new C(); + +/**/ +_ = c[1..^1]; +/**/ + +class C +{ + public int Slice(int notApplicable) => throw null; // not applicable +} + +static class E +{ + extension(C c) + { + public int Slice(int i, int j) { System.Console.Write("slice "); return 0; } + + public int Length + { + get { System.Console.Write("length "); return 42; } + } + } +} +"""; + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : revisit as part of "implicit indexer access" section + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics( + // (4,5): error CS0021: Cannot apply indexing with [] to an expression of type 'C' + // _ = c[1..^1]; + Diagnostic(ErrorCode.ERR_BadIndexLHS, "c[1..^1]").WithArguments("C").WithLocation(4, 5)); + } + + [Fact] + public void ExtensionMemberLookup_Patterns() + { + var src = """ +var c = new C(); + +_ = c is { Property: 42 }; + +class C { } + +static class E +{ + extension(C c) + { + public int Property + { + get { System.Console.Write("property"); return 42; } + } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "property").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var nameColon = GetSyntax(tree, "Property:"); + Assert.Equal("System.Int32 E.<>E__0.Property { get; }", model.GetSymbolInfo(nameColon.Name).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ExtensionMemberLookup_Patterns_ExtendedPropertyPattern() + { + var src = """ +var c = new C(); + +_ = c is { Property.Property2: 43 }; + +class C { } + +static class E1 +{ + extension(C c) + { + public int Property { get { System.Console.Write("property "); return 42; } } + } +} + +static class E2 +{ + extension(int i) + { + public int Property2 { get { System.Console.Write("property2"); return 43; } } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "property property2").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var expressionColon = GetSyntax(tree, "Property.Property2:"); + Assert.Equal("System.Int32 E2.<>E__0.Property2 { get; }", model.GetSymbolInfo(expressionColon.Expression).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ExtensionMemberLookup_Patterns_ListPattern_NoInstanceLength() + { + var src = """ +System.Console.Write(new C() is ["hi"]); + +class C +{ + public string this[System.Index i] + { + get { System.Console.Write("indexer "); return "hi"; } + } +} + +static class E +{ + extension(C c) + { + public int Length + { + get { System.Console.Write("length "); return 42; } + } + } +} +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : confirm that we want extensions to contribute to list-patterns + comp.VerifyEmitDiagnostics( + // (1,33): error CS8985: List patterns may not be used for a value of type 'C'. No suitable 'Length' or 'Count' property was found. + // System.Console.Write(new C() is ["hi"]); + Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, @"[""hi""]").WithArguments("C").WithLocation(1, 33) + ); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : metadata is undone + //CompileAndVerify(comp, expectedOutput: "length indexer"); + } + + [ConditionalFact(typeof(NoUsedAssembliesValidation))] // Tracked by https://github.com/dotnet/roslyn/issues/76130 : metadata is undone + public void ExtensionMemberLookup_ObjectInitializer() + { + var src = """ +/**/ +_ = new C() { Property = 42 }; +/**/ + +class C { } + +static class E +{ + extension(C c) + { + public int Property { set { System.Console.Write("property"); } } + } +} +"""; + + var comp = CreateCompilation(src); + comp.VerifyDiagnostics(); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : metadata is undone + //CompileAndVerify(comp, expectedOutput: "property"); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var assignment = GetSyntax(tree, "Property = 42"); + Assert.Equal("System.Int32 E.<>E__0.Property { set; }", model.GetSymbolInfo(assignment.Left).Symbol.ToTestDisplayString()); + } + + [ConditionalFact(typeof(NoUsedAssembliesValidation))] // Tracked by https://github.com/dotnet/roslyn/issues/76130 : metadata is undone + public void ExtensionMemberLookup_With() + { + var src = """ +/**/ +_ = new S() with { Property = 42 }; +/**/ + +struct S { } + +static class E +{ + extension(S s) + { + public int Property { set { System.Console.Write("property"); } } + } +} +"""; + + var comp = CreateCompilation(src); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : need to decide whether extensions apply here + comp.VerifyDiagnostics(); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : metadata is undone + //CompileAndVerify(comp, expectedOutput: "property"); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var assignment = GetSyntax(tree, "Property = 42"); + Assert.Equal("System.Int32 E.<>E__0.Property { set; }", model.GetSymbolInfo(assignment.Left).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ExtensionMemberLookup_CollectionInitializer_NoMethod() + { + var src = """ +using System.Collections; +using System.Collections.Generic; + +/**/ +_ = new C() { 42 }; +/**/ + +class C : IEnumerable, IEnumerable +{ + IEnumerator IEnumerable.GetEnumerator() => throw null; + IEnumerator IEnumerable.GetEnumerator() => throw null; +} + +static class E +{ + extension(C c) + { + public void Add(int i) { System.Console.Write("add"); } + } +} +"""; + + var comp = CreateCompilation(src); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : confirm when spec'ing pattern-based collection initializer + CompileAndVerify(comp, expectedOutput: "add").VerifyDiagnostics(); + + string expectedOperationTree = """ +ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: C) (Syntax: '_ = new C() { 42 }') +Left: + IDiscardOperation (Symbol: C _) (OperationKind.Discard, Type: C) (Syntax: '_') +Right: + IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C) (Syntax: 'new C() { 42 }') + Arguments(0) + Initializer: + IObjectOrCollectionInitializerOperation (OperationKind.ObjectOrCollectionInitializer, Type: C) (Syntax: '{ 42 }') + Initializers(1): + IInvocationOperation ( void E.<>E__0.Add(System.Int32 i)) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '42') + Instance Receiver: + IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: C, IsImplicit) (Syntax: 'C') + Arguments(1): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '42') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 42) (Syntax: '42') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) +"""; + var expectedDiagnostics = DiagnosticDescription.None; + + VerifyOperationTreeAndDiagnosticsForTest(src, expectedOperationTree, expectedDiagnostics); + } + + [Fact] + public void ExtensionMemberLookup_CollectionInitializer_NoApplicableMethod() + { + var src = """ +using System.Collections; +using System.Collections.Generic; + +class Program +{ + static void Main() + { + /**/ + _ = new C() { 42 }; + /**/ + } +} + +class C : IEnumerable, IEnumerable +{ + IEnumerator IEnumerable.GetEnumerator() => throw null; + IEnumerator IEnumerable.GetEnumerator() => throw null; + public void Add(string notApplicable) => throw null; +} + +static class E +{ + extension(object o) + { + public void Add(int i) { System.Console.Write("add"); } + } +} +"""; + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : confirm when spec'ing pattern-based collection initializer + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: "add").VerifyDiagnostics(); + + string expectedOperationTree = """ +ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: C) (Syntax: '_ = new C() { 42 }') + Left: + IDiscardOperation (Symbol: C _) (OperationKind.Discard, Type: C) (Syntax: '_') + Right: + IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C) (Syntax: 'new C() { 42 }') + Arguments(0) + Initializer: + IObjectOrCollectionInitializerOperation (OperationKind.ObjectOrCollectionInitializer, Type: C) (Syntax: '{ 42 }') + Initializers(1): + IInvocationOperation ( void E.<>E__0.Add(System.Int32 i)) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '42') + Instance Receiver: + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'C') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null) + Operand: + IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: C, IsImplicit) (Syntax: 'C') + Arguments(1): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '42') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 42) (Syntax: '42') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) +"""; + var expectedDiagnostics = DiagnosticDescription.None; + + VerifyOperationTreeAndDiagnosticsForTest(src, expectedOperationTree, expectedDiagnostics); + + VerifyFlowGraph(comp, comp.SyntaxTrees.Single().GetRoot().DescendantNodes().OfType().First(), """ +Block[B0] - Entry + Statements (0) + Next (Regular) Block[B1] + Entering: {R1} +.locals {R1} +{ + CaptureIds: [0] + Block[B1] - Block + Predecessors: [B0] + Statements (3) + IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'new C() { 42 }') + Value: + IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C) (Syntax: 'new C() { 42 }') + Arguments(0) + Initializer: + null + IInvocationOperation ( void E.<>E__0.Add(System.Int32 i)) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '42') + Instance Receiver: + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'C') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null) + (ImplicitReference) + Operand: + IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: C, IsImplicit) (Syntax: 'new C() { 42 }') + Arguments(1): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '42') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 42) (Syntax: '42') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '_ = new C() { 42 };') + Expression: + ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: C) (Syntax: '_ = new C() { 42 }') + Left: + IDiscardOperation (Symbol: C _) (OperationKind.Discard, Type: C) (Syntax: '_') + Right: + IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: C, IsImplicit) (Syntax: 'new C() { 42 }') + Next (Regular) Block[B2] + Leaving: {R1} +} +Block[B2] - Exit + Predecessors: [B1] + Statements (0) +"""); + } + + [Fact] + public void ExtensionMemberLookup_CollectionInitializer_NoApplicableMethod_ExpressionTree() + { + var src = """ +using System.Collections; +using System.Collections.Generic; + +try +{ + System.Linq.Expressions.Expression> e = () => new C() { 42 }; + System.Console.Write(e); +} +catch (System.ArgumentException ae) +{ + System.Console.Write(ae.Message); +} + +class C : IEnumerable, IEnumerable +{ + IEnumerator IEnumerable.GetEnumerator() => throw null; + IEnumerator IEnumerable.GetEnumerator() => throw null; + public void Add(string notApplicable) => throw null; +} + +static class E +{ + extension(object o) + { + public void Add(int i) { System.Console.Write("add"); } + } +} +"""; + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : confirm when spec'ing pattern-based collection initializer + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : expression trees + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); + comp.VerifyEmitDiagnostics( + // (6,76): error CS8075: An extension Add method is not supported for a collection initializer in an expression lambda. + // System.Linq.Expressions.Expression> e = () => new C() { 42 }; + Diagnostic(ErrorCode.ERR_ExtensionCollectionElementInitializerInExpressionTree, "42").WithLocation(6, 76) + ); + } + + [Fact] + public void ExtensionMemberLookup_Query_NoMethod() + { + var src = """ +/**/ +string query = from x in new C() select x; +/**/ + +System.Console.Write(query); + +class C { } + +static class E +{ + extension(C c) + { + public string Select(System.Func selector) => "hello"; + } +} +"""; + + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "hello").VerifyDiagnostics(); + + string expectedOperationTree = """ +IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null) (Syntax: 'string quer ... ) select x;') + IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null) (Syntax: 'string quer ... () select x') + Declarators: + IVariableDeclaratorOperation (Symbol: System.String query) (OperationKind.VariableDeclarator, Type: null) (Syntax: 'query = fro ... () select x') + Initializer: + IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null) (Syntax: '= from x in ... () select x') + ITranslatedQueryOperation (OperationKind.TranslatedQuery, Type: System.String) (Syntax: 'from x in n ... () select x') + Expression: + IInvocationOperation ( System.String E.<>E__0.Select(System.Func selector)) (OperationKind.Invocation, Type: System.String, IsImplicit) (Syntax: 'select x') + Instance Receiver: + IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C) (Syntax: 'new C()') + Arguments(0) + Initializer: + null + Arguments(1): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: selector) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'x') + IDelegateCreationOperation (OperationKind.DelegateCreation, Type: System.Func, IsImplicit) (Syntax: 'x') + Target: + IAnonymousFunctionOperation (Symbol: lambda expression) (OperationKind.AnonymousFunction, Type: null, IsImplicit) (Syntax: 'x') + IBlockOperation (1 statements) (OperationKind.Block, Type: null, IsImplicit) (Syntax: 'x') + IReturnOperation (OperationKind.Return, Type: null, IsImplicit) (Syntax: 'x') + ReturnedValue: + IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: C) (Syntax: 'x') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Initializer: + null +"""; + + VerifyOperationTreeAndDiagnosticsForTest(src, expectedOperationTree, DiagnosticDescription.None); + } + + [Fact] + public void ExtensionMemberLookup_Query_NoApplicableMethod() + { + var src = """ +/**/ +string query = from x in new C() select x; +/**/ + +System.Console.Write(query); + +class C +{ + public string Select(int notApplicable) => throw null; // not applicable +} + +static class E +{ + extension(C c) + { + public string Select(System.Func selector) => "hello"; + } +} +"""; + + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "hello").VerifyDiagnostics(); + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : verify IOperation + } + + [Fact] + public void ExtensionMemberLookup_Invocation_ZeroArityMatchesAny() + { + var source = $$""" +object.Method(""); +object.Method(""); + +static class E +{ + extension(object) + { + public static void Method(int i) => throw null; + public static void Method(T t) { System.Console.Write("Method "); } + public static void Method(T1 t1, T2 t2) => throw null; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "Method Method").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var invocation = GetSyntax(tree, """object.Method("")"""); + Assert.Equal("void E.<>E__0.Method(System.String t)", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); + Assert.Empty(model.GetMemberGroup(invocation)); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : need to fix the semantic model + } + + [Fact] + public void StaticPropertyAccess_ZeroArityMatchesAny() + { + var source = """ +int i = object.P; + +static class E1 +{ + extension(object) + { + public static int P => 42; + } +} + +static class E2 +{ + extension(object) + { + public static void P() => throw null; + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (1,9): error CS9286: 'object' does not contain a definition for 'P' and no accessible extension member 'P' for receiver of type 'object' could be found (are you missing a using directive or an assembly reference?) + // int i = object.P; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "object.P").WithArguments("object", "P").WithLocation(1, 9)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.P"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["System.Int32 E1.<>E__0.P { get; }", "void E2.<>E__0.P()"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + } + + [Fact] + public void StaticPropertyAccess_NonZeroArity() + { + var source = """ +int i = object.P; + +static class E1 +{ + extension(object) + { + public static int P => 42; + } +} + +static class E2 +{ + extension(object) + { + public static void P() => throw null; + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (1,16): error CS0428: Cannot convert method group 'P' to non-delegate type 'int'. Did you intend to invoke the method? + // int i = object.P; + Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "P").WithArguments("P", "int").WithLocation(1, 16)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.P"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["void E2.<>E__0.P()"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + } + + [Fact] + public void StaticMethodAccess_NonZeroArity() + { + var source = """ +object.M(); + +static class E1 +{ + extension(object) + { + public static void M() { } + public static void M() { } + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (1,8): error CS0117: 'object' does not contain a definition for 'M' + // object.M(); + Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("object", "M").WithLocation(1, 8)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["void E1.<>E__0.M()", "void E1.<>E__0.M()"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(["void E1.<>E__0.M()", "void E1.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void AddressOf_TypeReceiver() + { + var src = """ +unsafe class C +{ + static void Main() + { + delegate* ptr = &C.M; + ptr("ran", null); + } +} + +static class E +{ + extension(C) + { + public static void M(string s, object o) { System.Console.Write(s); } + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.UnsafeDebugExe); + comp.VerifyEmitDiagnostics(); + var verifier = CompileAndVerify(comp, expectedOutput: "ran", verify: Verification.Fails with { ILVerifyMessage = "[Main]: ImportCalli not implemented" }); + verifier.VerifyIL("C.Main", """ +{ + // Code size 24 (0x18) + .maxstack 3 + .locals init (delegate* V_0, //ptr + delegate* V_1) + IL_0000: nop + IL_0001: ldftn "void E.M(string, object)" + IL_0007: stloc.0 + IL_0008: ldloc.0 + IL_0009: stloc.1 + IL_000a: ldstr "ran" + IL_000f: ldnull + IL_0010: ldloc.1 + IL_0011: calli "delegate*" + IL_0016: nop + IL_0017: ret +} +"""); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "C.M"); + Assert.Equal("void E.<>E__0.M(System.String s, System.Object o)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void AddressOf_InstanceReceiver() + { + var src = """ +unsafe class C +{ + static void Main() + { + C c = new C(); + delegate* ptr = &c.M; + ptr("ran", null); + + delegate* ptr2 = &c.M2; + } +} + +static class E +{ + extension(C) + { + public void M(string s, object o) { System.Console.Write(s); } + } + public static void M2(this C c, string s, object o) { System.Console.Write(s); } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.UnsafeDebugExe); + comp.VerifyEmitDiagnostics( + // (6,48): error CS8759: Cannot create a function pointer for 'E.extension(C).M(string, object)' because it is not a static method + // delegate* ptr = &c.M; + Diagnostic(ErrorCode.ERR_FuncPtrMethMustBeStatic, "c.M").WithArguments("E.extension(C).M(string, object)").WithLocation(6, 48), + // (9,48): error CS8788: Cannot use an extension method with a receiver as the target of a '&' operator. + // delegate* ptr2 = &c.M2; + Diagnostic(ErrorCode.ERR_CannotUseReducedExtensionMethodInAddressOf, "&c.M2").WithLocation(9, 48)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "c.M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + } + + [Fact] + public void AddressOf_AmbiguousBestMethod() + { + var src = """ +unsafe class C +{ + static void M1() + { + delegate* ptr = &C.M; + } +} + +static class E +{ + extension(C) + { + public static void M(string s, object o) {} + public static void M(object o, string s) {} + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.UnsafeDebugDll); + comp.VerifyEmitDiagnostics( + // (5,48): error CS0121: The call is ambiguous between the following methods or properties: 'E.extension(C).M(string, object)' and 'E.extension(C).M(object, string)' + // delegate* ptr = &C.M; + Diagnostic(ErrorCode.ERR_AmbigCall, "C.M").WithArguments("E.extension(C).M(string, object)", "E.extension(C).M(object, string)").WithLocation(5, 48)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "C.M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["void E.<>E__0.M(System.String s, System.Object o)", "void E.<>E__0.M(System.Object o, System.String s)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void AddressOf_TypeReceiver_UnmanagedCallersOnly_01() + { + var src = """ +unsafe class C +{ + static void Main() + { + delegate* ptr = &C.M; + delegate* ptr2 = &E.M; + } +} + +static class E +{ + extension(C) + { + [System.Runtime.InteropServices.UnmanagedCallersOnly] + public static void M() { } + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.UnsafeDebugExe, targetFramework: TargetFramework.Net90); + comp.VerifyEmitDiagnostics( + // (5,32): error CS8786: Calling convention of 'E.extension(C).M()' is not compatible with 'Default'. + // delegate* ptr = &C.M; + Diagnostic(ErrorCode.ERR_WrongFuncPtrCallingConvention, "C.M").WithArguments("E.extension(C).M()", "Default").WithLocation(5, 32), + // (6,33): error CS8786: Calling convention of 'E.M()' is not compatible with 'Default'. + // delegate* ptr2 = &E.M; + Diagnostic(ErrorCode.ERR_WrongFuncPtrCallingConvention, "E.M").WithArguments("E.M()", "Default").WithLocation(6, 33)); + } + + [Fact] + public void AddressOf_TypeReceiver_UnmanagedCallersOnly_02() + { + var src = """ +unsafe class C +{ + static void Main() + { + delegate* unmanaged ptr = &C.M; + delegate* unmanaged ptr2 = &E.M; + } +} + +static class E +{ + extension(C) + { + [System.Runtime.InteropServices.UnmanagedCallersOnly] + public static void M() { } + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.UnsafeDebugExe, targetFramework: TargetFramework.Net90); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void TwoExtensions_MethodAndProperty() + { + var src = """ +System.Console.Write(object.M()); + +static class E1 +{ + extension(object) + { + public static string M() => throw null; + } +} + +static class E2 +{ + extension(object) + { + public static System.Func M => null; + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics( + // (1,22): error CS9286: 'object' does not contain a definition for 'M' and no accessible extension member 'M' for receiver of type 'object' could be found (are you missing a using directive or an assembly reference?) + // System.Console.Write(object.M()); + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "object.M").WithArguments("object", "M").WithLocation(1, 22)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + + Assert.Equal(["System.String E1.<>E__0.M()", "System.Func E2.<>E__0.M { get; }"], + model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + + Assert.Empty(model.GetMemberGroup(memberAccess)); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : consider handling BoundBadExpression better + } + + [Fact] + public void Nameof_Static_Method() + { + var src = """ +System.Console.Write(nameof(C.Method)); + +class C { } + +static class E +{ + extension(C) + { + public static string Method() => throw null; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,29): error CS8093: Extension method groups are not allowed as an argument to 'nameof'. + // System.Console.Write(nameof(C.Method)); + Diagnostic(ErrorCode.ERR_NameofExtensionMethod, "C.Method").WithLocation(1, 29)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "C.Method"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["System.String E.<>E__0.Method()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void Nameof_Instance_Method() + { + var src = """ +C c = null; +_ = nameof(c.Method); + +class C { } + +static class E +{ + extension(C) + { + public string Method() => throw null; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (2,12): error CS8093: Extension method groups are not allowed as an argument to 'nameof'. + // _ = nameof(c.Method); + Diagnostic(ErrorCode.ERR_NameofExtensionMethod, "c.Method").WithLocation(2, 12)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "c.Method"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + } + + [Fact] + public void Nameof_Static_Property() + { + var src = """ +System.Console.Write(nameof(C.Property)); + +class C { } + +static class E +{ + extension(C) + { + public static string Property => throw null; + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "Property").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "C.Property"); + Assert.Equal("System.String E.<>E__0.Property { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void Nameof_Static_WrongArityMethod() + { + var src = """ +System.Console.Write(nameof(C.Method)); + +class C { } + +static class E +{ + extension(C) + { + public static string Method() => throw null; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,29): error CS8093: Extension method groups are not allowed as an argument to 'nameof'. + // System.Console.Write(nameof(C.Method)); + Diagnostic(ErrorCode.ERR_NameofExtensionMethod, "C.Method").WithLocation(1, 29)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "C.Method"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["System.String E.<>E__0.Method()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void Nameof_Instance_Property() + { + var src = """ +C c = null; +System.Console.Write(nameof(c.Property)); + +class C { } + +static class E +{ + extension(C) + { + public string Property => "Property"; + } +} +"""; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : should we get an error as with methods? + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "Property").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "c.Property"); + Assert.Equal("System.String E.<>E__0.Property { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void Nameof_Static_Property_Generic_01() + { + var src = """ +System.Console.Write(nameof(C.Property)); + +class C : I { } +interface I { } + +static class E +{ + extension(I i) + { + public static string Property => throw null; + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "Property").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "C.Property"); + Assert.Equal("System.String E.<>E__0.Property { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void Nameof_Static_Property_Generic_02() + { + var src = """ +System.Console.Write(nameof(C.Property)); + +class C : I, I { } +interface I { } + +static class E +{ + extension(I i) + { + public static string Property => throw null; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,29): error CS9286: 'C' does not contain a definition for 'Property' and no accessible extension member 'Property' for receiver of type 'C' could be found (are you missing a using directive or an assembly reference?) + // System.Console.Write(nameof(C.Property)); + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "C.Property").WithArguments("C", "Property").WithLocation(1, 29)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "C.Property"); + Assert.Equal("System.String E.<>E__0.Property { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void Nameof_Overloads_01() + { + var src = """ +System.Console.Write($"{nameof(object.M)} "); + +static class E +{ + extension(object) + { + public static void M() { } + public static void M(int i) { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,32): error CS8093: Extension method groups are not allowed as an argument to 'nameof'. + // System.Console.Write($"{nameof(object.M)} "); + Diagnostic(ErrorCode.ERR_NameofExtensionMethod, "object.M").WithLocation(1, 32)); + } + + [Fact] + public void Nameof_Overloads_02() + { + var src = """ +System.Console.Write($"{nameof(object.M)} "); + +static class E1 +{ + extension(T) where T : class + { + public static void M() { } + } +} + +static class E2 +{ + extension(T) where T : struct + { + public static void M() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,32): error CS8093: Extension method groups are not allowed as an argument to 'nameof'. + // System.Console.Write($"{nameof(object.M)} "); + Diagnostic(ErrorCode.ERR_NameofExtensionMethod, "object.M").WithLocation(1, 32)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["void E1.<>E__0.M()"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(["void E1.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void Nameof_SimpleName() + { + var src = """ +class C +{ + void M() + { + _ = nameof(Method); + _ = nameof(Property); + } +} + +static class E +{ + extension(object) + { + public static void Method() { } + public static int Property => 0; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyDiagnostics( + // (5,20): error CS0103: The name 'Method' does not exist in the current context + // _ = nameof(Method); + Diagnostic(ErrorCode.ERR_NameNotInContext, "Method").WithArguments("Method").WithLocation(5, 20), + // (6,20): error CS0103: The name 'Property' does not exist in the current context + // _ = nameof(Property); + Diagnostic(ErrorCode.ERR_NameNotInContext, "Property").WithArguments("Property").WithLocation(6, 20)); + } + + [Fact] + public void Nameof_NoParameter() + { + var src = """ +class C +{ + void M() + { + System.Console.Write(nameof()); + } +} + +static class E +{ + extension(C c) + { + public string nameof() => throw null; + } +} +"""; + + var comp = CreateCompilation(src); + comp.VerifyDiagnostics( + // (5,30): error CS0103: The name 'nameof' does not exist in the current context + // System.Console.Write(nameof()); + Diagnostic(ErrorCode.ERR_NameNotInContext, "nameof").WithArguments("nameof").WithLocation(5, 30)); + } + + [Fact] + public void Nameof_SingleParameter() + { + var src = """ +class C +{ + public static void Main() + { + string x = ""; + System.Console.Write(nameof(x)); + } +} + +static class E +{ + extension(C c) + { + public string nameof(string s) => throw null; + } +} +"""; + + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: "x").VerifyDiagnostics(); + } + + [Fact] + public void StaticMethodInvocation_TypeParameter_InNameof() + { + var source = """ +public static class C +{ + static void M() + { + _ = nameof(T.Method); + } + + extension(T) + { + public static void Method() { } + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // 0.cs(5,20): error CS0704: Cannot do non-virtual member lookup in 'T' because it is a type parameter + // _ = nameof(T.Method); + Diagnostic(ErrorCode.ERR_LookupInTypeVariable, "T").WithArguments("T").WithLocation(5, 20)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "T.Method"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Empty(model.GetMemberGroup(memberAccess)); + } + + [Fact] + public void SymbolInfoForMethodGroup03() + { + var source = """ +public class A { } + +static class E +{ + extension(A a) + { + public string Extension() { return null; } + } +} +public class Program +{ + public static void Main(string[] args) + { + A a = null; + _ = nameof(a.Extension); + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (15,20): error CS8093: Extension method groups are not allowed as an argument to 'nameof'. + // _ = nameof(a.Extension); + Diagnostic(ErrorCode.ERR_NameofExtensionMethod, "a.Extension").WithLocation(15, 20)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "a.Extension"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Assert.Empty(model.GetMemberGroup(memberAccess)); + } + + [Fact] + public void StaticMethodInvocation_PartialStaticClass() + { + var source = """ +object.M(); +object.M2(); + +public static partial class C +{ + extension(object) + { + public static void M() { System.Console.Write("ran "); } + } +} + +public static partial class C +{ + extension(object) + { + public static void M2() { System.Console.Write("ran2"); } + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran ran2").VerifyDiagnostics(); + } + + [Fact] + public void StaticMethodInvocation_TupleTypeReceiver() + { + var src = """ +(string, string).M(); +(int a, int b).M(); +"""; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : consider parsing this + var comp = CreateCompilation(src); + comp.VerifyDiagnostics( + // (1,2): error CS1525: Invalid expression term 'string' + // (string, string).M(); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "string").WithArguments("string").WithLocation(1, 2), + // (1,10): error CS1525: Invalid expression term 'string' + // (string, string).M(); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "string").WithArguments("string").WithLocation(1, 10), + // (2,2): error CS8185: A declaration is not allowed in this context. + // (int a, int b).M(); + Diagnostic(ErrorCode.ERR_DeclarationExpressionNotPermitted, "int a").WithLocation(2, 2), + // (2,2): error CS0165: Use of unassigned local variable 'a' + // (int a, int b).M(); + Diagnostic(ErrorCode.ERR_UseDefViolation, "int a").WithArguments("a").WithLocation(2, 2), + // (2,9): error CS8185: A declaration is not allowed in this context. + // (int a, int b).M(); + Diagnostic(ErrorCode.ERR_DeclarationExpressionNotPermitted, "int b").WithLocation(2, 9), + // (2,9): error CS0165: Use of unassigned local variable 'b' + // (int a, int b).M(); + Diagnostic(ErrorCode.ERR_UseDefViolation, "int b").WithArguments("b").WithLocation(2, 9), + // (2,16): error CS1061: '(int a, int b)' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type '(int a, int b)' could be found (are you missing a using directive or an assembly reference?) + // (int a, int b).M(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("(int a, int b)", "M").WithLocation(2, 16)); + } + + [Fact] + public void StaticMethodInvocation_TupleTypeReceiver_02() + { + var src = """ +((string, string)).M(); +((int a, int b)).M(); +"""; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : consider parsing this + var comp = CreateCompilation(src); + comp.VerifyDiagnostics( + // (1,3): error CS1525: Invalid expression term 'string' + // ((string, string)).M(); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "string").WithArguments("string").WithLocation(1, 3), + // (1,11): error CS1525: Invalid expression term 'string' + // ((string, string)).M(); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "string").WithArguments("string").WithLocation(1, 11), + // (2,3): error CS8185: A declaration is not allowed in this context. + // ((int a, int b)).M(); + Diagnostic(ErrorCode.ERR_DeclarationExpressionNotPermitted, "int a").WithLocation(2, 3), + // (2,3): error CS0165: Use of unassigned local variable 'a' + // ((int a, int b)).M(); + Diagnostic(ErrorCode.ERR_UseDefViolation, "int a").WithArguments("a").WithLocation(2, 3), + // (2,10): error CS8185: A declaration is not allowed in this context. + // ((int a, int b)).M(); + Diagnostic(ErrorCode.ERR_DeclarationExpressionNotPermitted, "int b").WithLocation(2, 10), + // (2,10): error CS0165: Use of unassigned local variable 'b' + // ((int a, int b)).M(); + Diagnostic(ErrorCode.ERR_UseDefViolation, "int b").WithArguments("b").WithLocation(2, 10), + // (2,18): error CS1061: '(int a, int b)' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type '(int a, int b)' could be found (are you missing a using directive or an assembly reference?) + // ((int a, int b)).M(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("(int a, int b)", "M").WithLocation(2, 18)); + } + + [Fact] + public void StaticMethodInvocation_PointerTypeReceiver() + { + var src = """ +unsafe class C +{ + void M() + { + int*.M(); + delegate*.M(); + } +} +"""; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : consider parsing this + var comp = CreateCompilation(src, options: TestOptions.UnsafeDebugDll); + comp.VerifyDiagnostics( + // (5,13): error CS1001: Identifier expected + // int*.M(); + Diagnostic(ErrorCode.ERR_IdentifierExpected, ".").WithLocation(5, 13), + // (5,13): error CS1003: Syntax error, ',' expected + // int*.M(); + Diagnostic(ErrorCode.ERR_SyntaxError, ".").WithArguments(",").WithLocation(5, 13), + // (5,14): error CS1002: ; expected + // int*.M(); + Diagnostic(ErrorCode.ERR_SemicolonExpected, "M").WithLocation(5, 14), + // (6,17): error CS1514: { expected + // delegate*.M(); + Diagnostic(ErrorCode.ERR_LbraceExpected, "*").WithLocation(6, 17), + // (6,17): warning CS8848: Operator '*' cannot be used here due to precedence. Use parentheses to disambiguate. + // delegate*.M(); + Diagnostic(ErrorCode.WRN_PrecedenceInversion, "*").WithArguments("*").WithLocation(6, 17), + // (6,18): error CS1525: Invalid expression term '<' + // delegate*.M(); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "<").WithArguments("<").WithLocation(6, 18), + // (6,19): error CS1525: Invalid expression term 'void' + // delegate*.M(); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "void").WithArguments("void").WithLocation(6, 19), + // (6,24): error CS1525: Invalid expression term '.' + // delegate*.M(); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ".").WithArguments(".").WithLocation(6, 24)); + } + + [Fact] + public void StaticMethodInvocation_DynamicTypeReceiver() + { + var src = """ +dynamic.M(); +"""; + var comp = CreateCompilation(src); + comp.VerifyDiagnostics( + // (1,1): error CS0103: The name 'dynamic' does not exist in the current context + // dynamic.M(); + Diagnostic(ErrorCode.ERR_NameNotInContext, "dynamic").WithArguments("dynamic").WithLocation(1, 1)); + } + + [Fact] + public void DisplayString_Constraint() + { + var source = """ +static class E +{ + extension(T) where T : struct + { + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + var symbol = model.GetDeclaredSymbol(extension); + + var format = new SymbolDisplayFormat(genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeTypeConstraints); + Assert.Equal("extension(T) where T : struct", symbol.ToDisplayString(format)); + } + + [Fact] + public void DisplayString_Modifier() + { + var source = """ +static class E +{ + extension(ref readonly int) + { + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + var symbol = model.GetDeclaredSymbol(extension); + + var format = new SymbolDisplayFormat(parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeModifiers); + Assert.Equal("extension(ref readonly Int32)", symbol.ToDisplayString(format)); + } + + [Fact] + public void NameConflict_01_EnclosingStaticTypeNameWithExtensionTypeParameterName() + { + var src = """ +static class Extensions +{ + extension(Extensions) + { + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void NameConflict_02_EnclosingStaticTypeNameWithReceiverParameterName() + { + var src = """ +static class Extensions +{ + extension(int Extensions) + { + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void NameConflict_03_ExtensionTypeParameterNameWithReceiverParameterName() + { + var src = """ +static class Extensions +{ +#line 7 + extension(T[] T) + { + void M1(){} + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (7,22): error CS9287: 'T': a receiver parameter cannot have the same name as an extension container type parameter + // extension(T[] T) + Diagnostic(ErrorCode.ERR_ReceiverParameterSameNameAsTypeParameter, "T").WithArguments("T").WithLocation(7, 22) + ); + } + + [Fact] + public void NameConflict_04_ExtensionTypeParameterNameWithMemberParameterName() + { + var src = """ +static class Extensions +{ + extension(T[] p) + { +#line 14 + void M2(int T){} + static void M3(int T){} + int this[int T] => 0; + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (14,21): error CS9288: 'T': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + // void M2(int T){} + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(14, 21), + // (15,28): error CS9288: 'T': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + // static void M3(int T){} + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(15, 28), + // (16,22): error CS9288: 'T': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + // int this[int T] => 0; + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(16, 22) + ); + } + + [Theory] + [CombinatorialData] + public void NameConflict_05_ExtensionTypeParameterNameWithSetterValueParameter(bool isStatic) + { + var src = @" +static class Extensions +{ + extension(value[] p) + { + " + (isStatic ? "static" : "") + @" + int P11 {set{}} + + " + (isStatic ? "static" : "") + @" + int P12 => 0; + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (4,15): warning CS8981: The type name 'value' only contains lower-cased ascii characters. Such names may become reserved for the language. + // extension(value[] p) + Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "value").WithArguments("value").WithLocation(4, 15), + // (7,18): error CS9294: 'value': an automatically-generated parameter name conflicts with an extension type parameter name + // int P11 {set{}} + Diagnostic(ErrorCode.ERR_ValueParameterSameNameAsExtensionTypeParameter, "set").WithLocation(7, 18) + ); + } + + [Fact] + public void NameConflict_06_ExtensionTypeParameterNameWithSetterValueParameter() + { + var src = @" +static class Extensions +{ + extension(value[] p) + { + int this[int i] {set{}} + int this[long i] => 0; + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (4,15): warning CS8981: The type name 'value' only contains lower-cased ascii characters. Such names may become reserved for the language. + // extension(value[] p) + Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "value").WithArguments("value").WithLocation(4, 15), + // (6,26): error CS9294: 'value': an automatically-generated parameter name conflicts with an extension type parameter name + // int this[int i] {set{}} + Diagnostic(ErrorCode.ERR_ValueParameterSameNameAsExtensionTypeParameter, "set").WithLocation(6, 26) + ); + } + + [Theory] + [CombinatorialData] + public void NameConflict_07_ExtensionTypeParameterNameWithLocalFunctionParameterName(bool isStatic1, bool isStatic2) + { + var modifier1 = isStatic1 ? "static " : ""; + var modifier2 = isStatic2 ? "static " : ""; + + var src = @" +#pragma warning disable CS8321 // The local function 'local' is declared but never used + +static class Extensions +{ + extension(T[] p) + { + " + modifier1 + @"void M4() + { + " + modifier2 + @"int local(int T) + { + return T; + } + } + " + modifier1 + @"int P7 + { + set + { + " + modifier2 + @"int local(int T) + { + return T; + } + } + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void NameConflict_08_ExtensionTypeParameterNameWithLambdaParameterName(bool isStatic1, bool isStatic2) + { + var modifier1 = isStatic1 ? "static " : ""; + var modifier2 = isStatic2 ? "static " : ""; + + var src = @" +static class Extensions +{ + extension(T[] p) + { + " + modifier1 + @"void M4() + { + System.Func l = " + modifier2 + @"(int T) => + { + return T; + }; + } + " + modifier1 + @"int P7 + { + set + { + System.Func l = " + modifier2 + @"(int T) => + { + return T; + }; + } + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void NameConflict_09_ExtensionTypeParameterNameWithLocalName(bool isStatic) + { + var modifier = isStatic ? "static " : ""; + + var src = @" +static class Extensions +{ + extension(T[] p) + { + " + modifier + @"int M4() + { +#line 19 + int T = 0; + return T; + } + " + modifier + @"int M5() + { + int T() => 0; + return T(); + } + " + modifier + @"int P7 + { + get + { + int T = 0; + return T; + } + } + " + modifier + @"int P8 + { + get + { + int T() => 0; + return T(); + } + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (19,17): error CS9288: 'T': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + // int T = 0; + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(19, 17), + // (24,17): error CS9288: 'T': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + // int T() => 0; + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(24, 17), + // (31,21): error CS9288: 'T': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + // int T = 0; + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(31, 21), + // (39,21): error CS9288: 'T': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + // int T() => 0; + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(39, 21) + ); + } + + [Theory] + [CombinatorialData] + public void NameConflict_10_ExtensionTypeParameterNameWithLocalNameInLocalFunction(bool isStatic1, bool isStatic2) + { + var modifier1 = isStatic1 ? "static " : ""; + var modifier2 = isStatic2 ? "static " : ""; + + var src = @" +#pragma warning disable CS8321 // The local function 'local' is declared but never used + +static class Extensions +{ + extension(T[] p) + { + " + modifier1 + @"void M4() + { + " + modifier2 + @"int local() + { + int T = 0; + return T; + } + } + " + modifier1 + @"void M5() + { + " + modifier2 + @"int local() + { + int T() => 0; + return T(); + } + } + " + modifier1 + @"int P7 + { + set + { + " + modifier2 + @"int local() + { + int T = 0; + return T; + } + } + } + " + modifier1 + @"int P8 + { + set + { + " + modifier2 + @"int local() + { + int T() => 0; + return T(); + } + } + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void NameConflict_11_ExtensionTypeParameterNameWithLocalNameInLambda(bool isStatic1, bool isStatic2) + { + var modifier1 = isStatic1 ? "static " : ""; + var modifier2 = isStatic2 ? "static " : ""; + + var src = @" +static class Extensions +{ + extension(T[] p) + { + " + modifier1 + @"void M4() + { + System.Func l = " + modifier2 + @"() => + { + int T = 0; + return T; + }; + } + " + modifier1 + @"void M5() + { + System.Func l = " + modifier2 + @"() => + { + int T() => 0; + return T(); + }; + } + " + modifier1 + @"int P7 + { + set + { + System.Func l = " + modifier2 + @"() => + { + int T = 0; + return T; + }; + } + } + " + modifier1 + @"int P8 + { + set + { + System.Func l = " + modifier2 + @"() => + { + int T() => 0; + return T(); + }; + } + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void NameConflict_12_ExtensionTypeParameterNameWithAnotherExtensionTypeParameterName() + { + var src = """ +static class Extensions +{ +#line 55 + extension(T[] p) + {} +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (55,18): error CS0692: Duplicate type parameter 'T' + // extension(T[] p) + Diagnostic(ErrorCode.ERR_DuplicateTypeParameter, "T").WithArguments("T").WithLocation(55, 18), + // (55,21): error CS0229: Ambiguity between 'T' and 'T' + // extension(T[] p) + Diagnostic(ErrorCode.ERR_AmbigMember, "T").WithArguments("T", "T").WithLocation(55, 21), + // (55,25): error CS9295: The extended type 'T[]' must reference all the type parameters declared by the extension, but type parameter 'T' is not referenced. + // extension(T[] p) + Diagnostic(ErrorCode.ERR_UnderspecifiedExtension, "p").WithArguments("T[]", "T").WithLocation(55, 25), + // (55,25): error CS9295: The extended type 'T[]' must reference all the type parameters declared by the extension, but type parameter 'T' is not referenced. + // extension(T[] p) + Diagnostic(ErrorCode.ERR_UnderspecifiedExtension, "p").WithArguments("T[]", "T").WithLocation(55, 25) + ); + } + + [Theory] + [CombinatorialData] + public void NameConflict_13_ExtensionTypeParameterNameWithMemberTypeParameterName(bool isStatic) + { + var modifier = isStatic ? "static" : ""; + + var src = @" +static class Extensions +{ + extension(T[] p) + { + " + modifier + @" +#line 60 + void M9(){} + + " + modifier + @" +#line 61 + void M10(){} + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (60,17): error CS9289: Type parameter 'T' has the same name as an extension container type parameter + // void M9(){} + Diagnostic(ErrorCode.ERR_TypeParameterSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(60, 17), + // (61,18): error CS9289: Type parameter 'T' has the same name as an extension container type parameter + // void M10(){} + Diagnostic(ErrorCode.ERR_TypeParameterSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(61, 18), + // (61,21): error CS9289: Type parameter 'T' has the same name as an extension container type parameter + // void M10(){} + Diagnostic(ErrorCode.ERR_TypeParameterSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(61, 21) + ); + } + + [Theory] + [CombinatorialData] + public void NameConflict_14_ExtensionTypeParameterNameWithLocalFunctionTypeParameterName(bool isStatic1, bool isStatic2) + { + var modifier1 = isStatic1 ? "static " : ""; + var modifier2 = isStatic2 ? "static" : ""; + + var src = @" +#pragma warning disable CS8321 // The local function 'local' is declared but never used + +static class Extensions +{ + extension(T[] p) + { + " + modifier1 + @"void M4() + { + " + modifier2 + @" + T local(T p1) + { + return p1; + } + } + " + modifier1 + @"void M5() + { + void local2() + { + " + modifier2 + @" + T local(T p1) + { + return p1; + } + } + } + " + modifier1 + @"int P7 + { + set + { + " + modifier2 + @" + T local(T p1) + { + return p1; + } + } + } + " + modifier1 + @"int P8 + { + set + { + void local2() + { + " + modifier2 + @" + T local(T p1) + { + return p1; + } + } + } + } + } +} +"; + var comp = CreateCompilation(src); + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : We might need to add a new warning if we don't want to refer to extension as a type in diagnostics + + comp.VerifyEmitDiagnostics( + // (11,21): warning CS0693: Type parameter 'T' has the same name as the type parameter from outer type 'Extensions.extension(T[])' + // T local(T p1) + Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, "T").WithArguments("T", "Extensions.extension(T[])").WithLocation(11, 21), + // (21,25): warning CS0693: Type parameter 'T' has the same name as the type parameter from outer type 'Extensions.extension(T[])' + // T local(T p1) + Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, "T").WithArguments("T", "Extensions.extension(T[])").WithLocation(21, 25), + // (32,25): warning CS0693: Type parameter 'T' has the same name as the type parameter from outer type 'Extensions.extension(T[])' + // T local(T p1) + Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, "T").WithArguments("T", "Extensions.extension(T[])").WithLocation(32, 25), + // (45,29): warning CS0693: Type parameter 'T' has the same name as the type parameter from outer type 'Extensions.extension(T[])' + // T local(T p1) + Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, "T").WithArguments("T", "Extensions.extension(T[])").WithLocation(45, 29) + ); + } + + [Fact] + public void NameConflict_15_ExtensionTypeParameterNameWithMemberName() + { + var src = """ +static class Extensions +{ + extension(C1 p) + { + int T() + { + return T; + } + } + + extension(C2 p) + { + int T => T; + } + + extension(C3 p) + { + [System.Runtime.CompilerServices.IndexerName("T")] + int this[int x] => T; + } + + extension(C4 p) + { + static int T() + { + return T; + } + } + + extension(C5 p) + { + static int T => T; + } + + extension(C6 p) + { + int P => 0; + } + + extension(C7 p) + { + [System.Runtime.CompilerServices.IndexerName("Indexer")] + int this[int x] => 0; + } + + extension(C8 p) + { + int this[int x] => 0; + } +} + +class C1 {} +class C2 {} +class C3 {} +class C4 {} +class C5 {} +class C6 {} +class C7 {} +class C8 {} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (7,20): error CS0119: 'T' is a type, which is not valid in the given context + // return T; + Diagnostic(ErrorCode.ERR_BadSKunknown, "T").WithArguments("T", "type").WithLocation(7, 20), + // (13,18): error CS0119: 'T' is a type, which is not valid in the given context + // int T => T; + Diagnostic(ErrorCode.ERR_BadSKunknown, "T").WithArguments("T", "type").WithLocation(13, 18), + // (19,28): error CS0119: 'T' is a type, which is not valid in the given context + // int this[int x] => T; + Diagnostic(ErrorCode.ERR_BadSKunknown, "T").WithArguments("T", "type").WithLocation(19, 28), + // (26,20): error CS0119: 'T' is a type, which is not valid in the given context + // return T; + Diagnostic(ErrorCode.ERR_BadSKunknown, "T").WithArguments("T", "type").WithLocation(26, 20), + // (32,25): error CS0119: 'T' is a type, which is not valid in the given context + // static int T => T; + Diagnostic(ErrorCode.ERR_BadSKunknown, "T").WithArguments("T", "type").WithLocation(32, 25) + ); + } + + [Fact] + public void NameConflict_16_ReceiverParameterNameWithMemberName() + { + var src = """ +static class Extensions +{ + extension(int M1) + { + void M1() + { + int x = M1; + x++; + } + } + + extension(long P1) + { + int P1 + { + get + { + P1 = long.MaxValue; + return 0; + } + } + } + + extension(byte Indexer) + { + [System.Runtime.CompilerServices.IndexerName("Indexer")] + int this[int y] + { + get + { + byte x = Indexer; + x++; + return 0; + } + } + } + + extension(short M1) + { + static void M1() + { + short x = M1; + x++; + } + } + + extension(string P1) + { + static int P1 + { + get + { + P1 = "val"; + return 0; + } + } + } + + extension(int[] get_P) + { + int P => 0; + } + + extension(long[] get_Indexer) + { + [System.Runtime.CompilerServices.IndexerName("Indexer")] + int this[int x] => 0; + } + + extension(byte[] get_Item) + { + int this[int x] => 0; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (42,23): error CS9293: Cannot use extension parameter 'short M1' in this context. + // short x = M1; + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "M1").WithArguments("short M1").WithLocation(42, 23), + // (53,17): error CS9293: Cannot use extension parameter 'string P1' in this context. + // P1 = "val"; + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "P1").WithArguments("string P1").WithLocation(53, 17) + ); + } + + [Theory] + [CombinatorialData] + public void NameConflict_17_ReceiverParameterNameWithMemberTypeParameterName(bool isStatic) + { + var modifier = isStatic ? "static" : ""; + + var src = @" +static class Extensions +{ + extension(int T) + { + " + modifier + @" +#line 5 + void M1(){} + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (5,17): error CS9292: Type parameter 'T' has the same name as an extension parameter + // void M1(){} + Diagnostic(ErrorCode.ERR_TypeParameterSameNameAsExtensionParameter, "T").WithArguments("T").WithLocation(5, 17) + ); + } + + [Theory] + [CombinatorialData] + public void NameConflict_18_ReceiverParameterNameWithLocalFunctionTypeParameterName(bool isStatic1, bool isStatic2) + { + var modifier1 = isStatic1 ? "static " : ""; + var modifier2 = isStatic2 ? "static" : ""; + + var src = @" +#pragma warning disable CS8321 // The local function 'local' is declared but never used + +static class Extensions +{ + extension(int T) + { + " + modifier1 + @"void M4() + { + " + modifier2 + @" + T local(T p1) + { + return p1; + } + } + " + modifier1 + @"void M5() + { + void local2() + { + " + modifier2 + @" + T local(T p1) + { + return p1; + } + } + } + " + modifier1 + @"int P7 + { + set + { + " + modifier2 + @" + T local(T p1) + { + return p1; + } + } + } + " + modifier1 + @"int P8 + { + set + { + void local2() + { + " + modifier2 + @" + T local(T p1) + { + return p1; + } + } + } + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void NameConflict_19_ReceiverParameterNameWithMemberParameterName() + { + var src = """ +static class Extensions +{ + extension(int p) + { + void M2(int p){} + static void M3(int p){} + int this[int p] => 0; + void M3(int p2, int p2) {} + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (5,21): error CS9290: 'p': a parameter, local variable, or local function cannot have the same name as an extension parameter + // void M2(int p){} + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionParameter, "p").WithArguments("p").WithLocation(5, 21), + // (6,28): error CS9290: 'p': a parameter, local variable, or local function cannot have the same name as an extension parameter + // static void M3(int p){} + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionParameter, "p").WithArguments("p").WithLocation(6, 28), + // (7,22): error CS9290: 'p': a parameter, local variable, or local function cannot have the same name as an extension parameter + // int this[int p] => 0; + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionParameter, "p").WithArguments("p").WithLocation(7, 22), + // (8,29): error CS0100: The parameter name 'p2' is a duplicate + // void M3(int p2, int p2) {} + Diagnostic(ErrorCode.ERR_DuplicateParamName, "p2").WithArguments("p2").WithLocation(8, 29) + ); + } + + [Fact] + public void NameConflict_20_ReceiverParameterNameWithSetterValueParameter() + { + var src = """ +static class Extensions +{ + extension(int value) + { + int P1 {get=>0;} + int P2 {set{}} + int this[int x] {get=>0;} + int this[long x] {set{}} + int this[long x, int value] {set{}} + static int P6 {get=>0;} + static int P7 {set{}} + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (6,17): error CS9291: 'value': an automatically-generated parameter name conflicts with an extension parameter name + // int P2 {set{}} + Diagnostic(ErrorCode.ERR_ValueParameterSameNameAsExtensionParameter, "set").WithLocation(6, 17), + // (8,27): error CS9291: 'value': an automatically-generated parameter name conflicts with an extension parameter name + // int this[long x] {set{}} + Diagnostic(ErrorCode.ERR_ValueParameterSameNameAsExtensionParameter, "set").WithLocation(8, 27), + // (9,30): error CS9290: 'value': a parameter, local variable, or local function cannot have the same name as an extension parameter + // int this[long x, int value] {set{}} + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionParameter, "value").WithArguments("value").WithLocation(9, 30), + // (9,30): error CS0316: The parameter name 'value' conflicts with an automatically-generated parameter name + // int this[long x, int value] {set{}} + Diagnostic(ErrorCode.ERR_DuplicateGeneratedName, "value").WithArguments("value").WithLocation(9, 30), + // (9,38): error CS9291: 'value': an automatically-generated parameter name conflicts with an extension parameter name + // int this[long x, int value] {set{}} + Diagnostic(ErrorCode.ERR_ValueParameterSameNameAsExtensionParameter, "set").WithLocation(9, 38), + // (11,24): error CS9291: 'value': an automatically-generated parameter name conflicts with an extension parameter name + // static int P7 {set{}} + Diagnostic(ErrorCode.ERR_ValueParameterSameNameAsExtensionParameter, "set").WithLocation(11, 24) + ); + } + + [Theory] + [CombinatorialData] + public void NameConflict_21_ReceiverParameterNameWithLocalFunctionParameterName(bool isStatic1, bool isStatic2) + { + var modifier1 = isStatic1 ? "static " : ""; + var modifier2 = isStatic2 ? "static " : ""; + + var src = @" +#pragma warning disable CS8321 // The local function 'local' is declared but never used + +static class Extensions +{ + extension(string p) + { + " + modifier1 + @"void M4() + { + " + modifier2 + @"int local(int p) + { + return p; + } + } + " + modifier1 + @"int P7 + { + set + { + " + modifier2 + @"int local(int p) + { + return p; + } + } + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void NameConflict_22_ReceiverParameterNameWithLambdaParameterName(bool isStatic1, bool isStatic2) + { + var modifier1 = isStatic1 ? "static " : ""; + var modifier2 = isStatic2 ? "static " : ""; + + var src = @" +static class Extensions +{ + extension(string p) + { + " + modifier1 + @"void M4() + { + System.Func l = " + modifier2 + @"(int p) => + { + return p; + }; + } + " + modifier1 + @"int P7 + { + set + { + System.Func l = " + modifier2 + @"(int p) => + { + return p; + }; + } + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void NameConflict_23_ReceiverParameterNameWithLocalName(bool isStatic) + { + var modifier = isStatic ? "static " : ""; + + var src = @" +static class Extensions +{ + extension(int p) + { + " + modifier + @"int M4() + { +#line 7 + int p = 0; + return p; + } + " + modifier + @"int M5() + { + int p() => 0; + return p(); + } + " + modifier + @"int P7 + { + get + { + int p = 0; + return p; + } + } + " + modifier + @"int P8 + { + get + { + int p() => 0; + return p(); + } + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (7,17): error CS0136: A local or parameter named 'p' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter + // int p = 0; + Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "p").WithArguments("p").WithLocation(7, 17), + // (12,17): error CS0136: A local or parameter named 'p' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter + // int p() => 0; + Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "p").WithArguments("p").WithLocation(12, 17), + // (19,21): error CS0136: A local or parameter named 'p' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter + // int p = 0; + Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "p").WithArguments("p").WithLocation(19, 21), + // (27,21): error CS0136: A local or parameter named 'p' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter + // int p() => 0; + Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "p").WithArguments("p").WithLocation(27, 21) + ); + } + + [Theory] + [CombinatorialData] + public void NameConflict_24_ReceiverParameterNameWithLocalNameInLocalFunction(bool isStatic1, bool isStatic2) + { + var modifier1 = isStatic1 ? "static " : ""; + var modifier2 = isStatic2 ? "static " : ""; + + var src = @" +#pragma warning disable CS8321 // The local function 'local' is declared but never used + +static class Extensions +{ + extension(string p) + { + " + modifier1 + @"void M4() + { + " + modifier2 + @"int local() + { + int p = 0; + return p; + } + } + " + modifier1 + @"void M5() + { + " + modifier2 + @"int local() + { + int p() => 0; + return p(); + } + } + " + modifier1 + @"int P7 + { + set + { + " + modifier2 + @"int local() + { + int p = 0; + return p; + } + } + } + " + modifier1 + @"int P8 + { + set + { + " + modifier2 + @"int local() + { + int p() => 0; + return p(); + } + } + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void NameConflict_25_ReceiverParameterNameWithLocalNameInLambda(bool isStatic1, bool isStatic2) + { + var modifier1 = isStatic1 ? "static " : ""; + var modifier2 = isStatic2 ? "static " : ""; + + var src = @" +static class Extensions +{ + extension(string p) + { + " + modifier1 + @"void M4() + { + System.Func l = " + modifier2 + @"() => + { + int p = 0; + return p; + }; + } + " + modifier1 + @"void M5() + { + System.Func l = " + modifier2 + @"() => + { + int p() => 0; + return p(); + }; + } + " + modifier1 + @"int P7 + { + set + { + System.Func l = " + modifier2 + @"() => + { + int p = 0; + return p; + }; + } + } + " + modifier1 + @"int P8 + { + set + { + System.Func l = " + modifier2 + @"() => + { + int p() => 0; + return p(); + }; + } + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void NameConflict_26_ExampleFromSpec() + { + var src = @" +using System.Linq; + +public static class E +{ + extension(T[] ts) + { + public bool M1(T t) => ts.Contains(t); // `T` and `ts` are in scope + public static bool M2(T t) => ts.Contains(t); // Error: Cannot refer to `ts` from static context + public void M3(int T, string ts) { } // Error: Cannot reuse names `T` and `ts` + public void M4(string s) { } // Error: Cannot reuse names `T` and `ts` + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (9,39): error CS9293: Cannot use extension parameter 'T[] ts' in this context. + // public static bool M2(T t) => ts.Contains(t); // Error: Cannot refer to `ts` from static context + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "ts").WithArguments("T[] ts").WithLocation(9, 39), + // (10,28): error CS9288: 'T': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + // public void M3(int T, string ts) { } // Error: Cannot reuse names `T` and `ts` + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(10, 28), + // (10,38): error CS9290: 'ts': a parameter, local variable, or local function cannot have the same name as an extension parameter + // public void M3(int T, string ts) { } // Error: Cannot reuse names `T` and `ts` + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionParameter, "ts").WithArguments("ts").WithLocation(10, 38), + // (11,24): error CS9289: Type parameter 'T' has the same name as an extension container type parameter + // public void M4(string s) { } // Error: Cannot reuse names `T` and `ts` + Diagnostic(ErrorCode.ERR_TypeParameterSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(11, 24), + // (11,27): warning CS8981: The type name 'ts' only contains lower-cased ascii characters. Such names may become reserved for the language. + // public void M4(string s) { } // Error: Cannot reuse names `T` and `ts` + Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "ts").WithArguments("ts").WithLocation(11, 27), + // (11,27): error CS9292: Type parameter 'ts' has the same name as an extension parameter + // public void M4(string s) { } // Error: Cannot reuse names `T` and `ts` + Diagnostic(ErrorCode.ERR_TypeParameterSameNameAsExtensionParameter, "ts").WithArguments("ts").WithLocation(11, 27) + ); + } + + [Fact] + public void NameConflict_27_ExampleFromSpec() + { + var src = @" +public static class E +{ + extension(T[] ts) + { + public int T() { return M(ts); } // Generated static method M(T[]) is found + public string M() { return T(ts); } // Error: T is a type parameter + } +} + +class CTest +{ + static int M(T[] ts) + { + return T(ts); + } + + static int T(U[] ts) => 0; +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (6,33): error CS0029: Cannot implicitly convert type 'string' to 'int' + // public int T() { return M(ts); } // Generated static method M(T[]) is found + Diagnostic(ErrorCode.ERR_NoImplicitConv, "M(ts)").WithArguments("string", "int").WithLocation(6, 33), + // (7,36): error CS0119: 'T' is a type, which is not valid in the given context + // public string M() { return T(ts); } // Error: T is a type parameter + Diagnostic(ErrorCode.ERR_BadSKunknown, "T").WithArguments("T", "type").WithLocation(7, 36), + // (15,16): error CS0119: 'T' is a type, which is not valid in the given context + // return T(ts); + Diagnostic(ErrorCode.ERR_BadSKunknown, "T").WithArguments("T", "type").WithLocation(15, 16) + ); + } + + [Fact] + public void NameConflict_28_ExampleFromSpec() + { + var src = @" +public static class E +{ + extension(int P) + { + public int P() { return M(P); } // Generated static method M(T[]) is found + public string M() { return P(P); } // Error: P is a parameter + } +} + +class CTest +{ + static int M(int P) + { + return P(P); + } + + static int P(int P) => 0; +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (6,33): error CS0029: Cannot implicitly convert type 'string' to 'int' + // public int P() { return M(P); } // Generated static method M(T[]) is found + Diagnostic(ErrorCode.ERR_NoImplicitConv, "M(P)").WithArguments("string", "int").WithLocation(6, 33), + // (7,36): error CS0149: Method name expected + // public string M() { return P(P); } // Error: P is a parameter + Diagnostic(ErrorCode.ERR_MethodNameExpected, "P").WithLocation(7, 36), + // (15,16): error CS0149: Method name expected + // return P(P); + Diagnostic(ErrorCode.ERR_MethodNameExpected, "P").WithLocation(15, 16) + ); + } + + [Fact] + public void NameConflict_29_WithStaticTypeTypeParameter() + { + var src = @" +public static class E +{ + extension(int p) + { + public void M1() {} + } + + extension(T[] p) + { + public void M2() {} + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (4,5): error CS9283: Extensions must be declared in a top-level, non-generic, static class + // extension(int p) + Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(4, 5), + // (6,24): warning CS0693: Type parameter 'T' has the same name as the type parameter from outer type 'E' + // public void M1() {} + Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, "T").WithArguments("T", "E").WithLocation(6, 24), + // (9,5): error CS9283: Extensions must be declared in a top-level, non-generic, static class + // extension(T[] p) + Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(9, 5), + // (9,15): warning CS0693: Type parameter 'T' has the same name as the type parameter from outer type 'E' + // extension(T[] p) + Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, "T").WithArguments("T", "E").WithLocation(9, 15), + // (11,24): error CS9289: Type parameter 'T' has the same name as an extension container type parameter + // public void M2() {} + Diagnostic(ErrorCode.ERR_TypeParameterSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(11, 24) + ); + } + + [Fact] + public void ReceiverParameterScope_01_InStaticMember() + { + var src = """ +static class Extensions +{ + extension(int p) + { + static int P1 { get => p; } + static int M2() + { + return p; + } + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (5,32): error CS9293: Cannot use extension parameter 'int p' in this context. + // static int P1 { get => p; } + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "p").WithArguments("int p").WithLocation(5, 32), + // (8,20): error CS9293: Cannot use extension parameter 'int p' in this context. + // return p; + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "p").WithArguments("int p").WithLocation(8, 20) + ); + } + + [Fact] + public void ReceiverParameterScope_02_InStaticMember() + { + var src = """ +static class Extensions +{ + extension(int p) + { + static int P1 + { + get + { + int local() => p; + return local(); + } + } + static int M2() + { + int local() => p; + return local(); + } + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (9,32): error CS9293: Cannot use extension parameter 'int p' in this context. + // int local() => p; + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "p").WithArguments("int p").WithLocation(9, 32), + // (15,28): error CS9293: Cannot use extension parameter 'int p' in this context. + // int local() => p; + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "p").WithArguments("int p").WithLocation(15, 28) + ); + } + + [Fact] + public void ReceiverParameterScope_03_InStaticMember() + { + var src = """ +static class Extensions +{ + extension(int p) + { + static string P1 { get => nameof(p); } + static string M2() + { + return nameof(p); + } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void ReceiverParameterScope_04_InStaticLocalFunction() + { + var src = """ +static class Extensions +{ + extension(int p) + { + int P1 + { + get + { + static int local() => p; + return local(); + } + } + int M2() + { + static int local() => p; + return local(); + } + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (9,39): error CS8421: A static local function cannot contain a reference to 'p'. + // static int local() => p; + Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureVariable, "p").WithArguments("p").WithLocation(9, 39), + // (15,35): error CS8421: A static local function cannot contain a reference to 'p'. + // static int local() => p; + Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureVariable, "p").WithArguments("p").WithLocation(15, 35) + ); + } + + [Theory] + [CombinatorialData] + public void ReceiverParameterScope_05_InAttribute(bool isStatic) + { + var modifier = isStatic ? "static " : ""; + + var src = @" +static class Extensions +{ + extension(int p) + { + [MyAttr(nameof(p))] + " + modifier + @"int P1 { get => 0; } + + [MyAttr(nameof(p))] + " + modifier + @"int M2() + { + return 0; + } + } +} + +class MyAttr : System.Attribute +{ + public MyAttr(string s) {} +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void ReceiverParameterScope_06_InAttribute(bool isStatic) + { + var modifier = isStatic ? "static " : ""; + + var src = @" +static class Extensions +{ + extension(int p) + { + [MyAttr(p)] + " + modifier + @"int P1 { get => 0; } + + [MyAttr(p)] + " + modifier + @"int M2() + { + return 0; + } + } +} + +class MyAttr : System.Attribute +{ + public MyAttr(int p) {} +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics( + // (6,17): error CS9293: Cannot use extension parameter 'int p' in this context. + // [MyAttr(p)] + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "p").WithArguments("int p").WithLocation(6, 17), + // (6,17): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // [MyAttr(p)] + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "p").WithLocation(6, 17), + // (9,17): error CS9293: Cannot use extension parameter 'int p' in this context. + // [MyAttr(p)] + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "p").WithArguments("int p").WithLocation(9, 17), + // (9,17): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // [MyAttr(p)] + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "p").WithLocation(9, 17) + ); + } + + [Fact] + public void ReceiverParameterScope_07_InAttribute() + { + var src = @" +static class Extensions +{ + extension(int p) + { + [MyAttr(nameof(p))] + int this[int y] + { + get + { + return 0; + } + } + } +} + +class MyAttr : System.Attribute +{ + public MyAttr(string p) {} +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void ReceiverParameterScope_08_InAttribute() + { + var src = @" +static class Extensions +{ + extension(string p) + { + [System.Runtime.CompilerServices.IndexerName(p)] + int this[int y] + { + get + { + return 0; + } + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (6,54): error CS9293: Cannot use extension parameter 'string p' in this context. + // [System.Runtime.CompilerServices.IndexerName(p)] + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "p").WithArguments("string p").WithLocation(6, 54), + // (6,54): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // [System.Runtime.CompilerServices.IndexerName(p)] + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "p").WithLocation(6, 54) + ); + } + + [Theory] + [CombinatorialData] + public void ReceiverParameterScope_09_InDefaultValue(bool isStatic) + { + var modifier = isStatic ? "static " : ""; + + var src = @" +static class Extensions +{ + extension(int p) + { + " + modifier + @"int M2(string x = nameof(p)) + { + return 0; + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void ReceiverParameterScope_10_InDefaultValue(bool isStatic) + { + var modifier = isStatic ? "static" : ""; + + var src = @" +static class Extensions +{ + extension(int p) + { + " + modifier + @" +#line 6 + int M2(int x = p) + { + return 0; + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics( + // (6,24): error CS9293: Cannot use extension parameter 'int p' in this context. + // int M2(int x = p) + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "p").WithArguments("int p").WithLocation(6, 24), + // (6,24): error CS1736: Default parameter value for 'x' must be a compile-time constant + // int M2(int x = p) + Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "p").WithArguments("x").WithLocation(6, 24) + ); + } + + [Theory] + [CombinatorialData] + public void ReceiverParameterScope_11_InNestedType(bool isStatic) + { + var modifier = isStatic ? "static" : ""; + + var src = @" +static class Extensions +{ + extension(int p) + { + class Nested + { + " + modifier + @" + int M2() + { + return p; + } + + " + modifier + @" + string M3() + { + return nameof(p); + } + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics( + // (6,15): error CS9282: Extension declarations can include only methods or properties + // class Nested + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "Nested").WithLocation(6, 15), + // (11,24): error CS9293: Cannot use extension parameter 'int p' in this context. + // return p; + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "p").WithArguments("int p").WithLocation(11, 24) + ); + } + + [Fact] + public void CycleInAttribute_01() + { + var src = @" +static class Extensions +{ + const string Str = ""val""; + extension(string p) + { + [System.Runtime.CompilerServices.IndexerName(Str)] + int this[int y] + { + get + { + return 0; + } + } + } +} +"; + var comp = CreateCompilation(src); + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : We do not allow complex forms of IndexerName attribute due to a possible binding cycle + comp.VerifyEmitDiagnostics( + // (7,54): error CS8078: An expression is too long or complex to compile + // [System.Runtime.CompilerServices.IndexerName(Str)] + Diagnostic(ErrorCode.ERR_InsufficientStack, "Str").WithLocation(7, 54) + ); + } + + [Fact] + public void MemberNameAndSignatureConflict_01() + { + var src = """ +static class Extensions +{ + extension(object receiver) + { + public void M1() {} + } + + extension(object receiver) + { + public void M1() {} + } + + extension(int receiver) + { + public void M2() {} + } + + extension(ref int receiver) + { + public void M2() {} + } + + extension(in int receiver) + { + public void M3() {} + } + + extension(ref int receiver) + { + public void M3() {} + } + + extension(ref readonly int receiver) + { + public void M4() {} + } + + extension(ref int receiver) + { + public void M4() {} + } + + extension(ref readonly int receiver) + { + public void M5() {} + } + + extension(in int receiver) + { + public void M5() {} + } + + static public void M6(this int receiver) {} + + static public void M6(this ref int receiver) {} + + static public void M7(this in int receiver) {} + + static public void M7(this ref int receiver) {} + + static public void M8(this ref readonly int receiver) {} + + static public void M8(this ref int receiver) {} + + static public void M9(this ref readonly int receiver) {} + + static public void M9(this in int receiver) {} + + extension(object receiver) + { + public void M10() {} + public void M10() {} + } + + extension(object receiver1) + { + public void M13() {} + } + + extension(object receiver2) + { + public void M13() {} + } +} +"""; + var comp = CreateCompilation(src); + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Despite the fact that we do not complain about M6, should we report an error for M2 (the only difference is receiver ref-ness)? + comp.VerifyDiagnostics( + // (10,21): error CS0111: Type 'Extensions' already defines a member called 'M1' with the same parameter types + // public void M1() {} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "Extensions").WithLocation(10, 21), + // (20,21): error CS0111: Type 'Extensions' already defines a member called 'M2' with the same parameter types + // public void M2() {} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M2").WithArguments("M2", "Extensions").WithLocation(20, 21), + // (30,21): error CS0111: Type 'Extensions' already defines a member called 'M3' with the same parameter types + // public void M3() {} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M3").WithArguments("M3", "Extensions").WithLocation(30, 21), + // (40,21): error CS0111: Type 'Extensions' already defines a member called 'M4' with the same parameter types + // public void M4() {} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M4").WithArguments("M4", "Extensions").WithLocation(40, 21), + // (50,21): error CS0111: Type 'Extensions' already defines a member called 'M5' with the same parameter types + // public void M5() {} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M5").WithArguments("M5", "Extensions").WithLocation(50, 21), + // (59,24): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'ref' and 'in' + // static public void M7(this ref int receiver) {} + Diagnostic(ErrorCode.ERR_OverloadRefKind, "M7").WithArguments("Extensions", "method", "ref", "in").WithLocation(59, 24), + // (63,24): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'ref' and 'ref readonly' + // static public void M8(this ref int receiver) {} + Diagnostic(ErrorCode.ERR_OverloadRefKind, "M8").WithArguments("Extensions", "method", "ref", "ref readonly").WithLocation(63, 24), + // (67,24): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'in' and 'ref readonly' + // static public void M9(this in int receiver) {} + Diagnostic(ErrorCode.ERR_OverloadRefKind, "M9").WithArguments("Extensions", "method", "in", "ref readonly").WithLocation(67, 24), + // (72,21): error CS0111: Type 'Extensions' already defines a member called 'M10' with the same parameter types + // public void M10() {} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M10").WithArguments("M10", "Extensions").WithLocation(72, 21), + // (82,21): error CS0111: Type 'Extensions' already defines a member called 'M13' with the same parameter types + // public void M13() {} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M13").WithArguments("M13", "Extensions").WithLocation(82, 21) + ); + + comp = CreateCompilation(""" +static class Extensions +{ + static void Main() + { + int i = 0; + i.M11(); + "".M11(); + + ((long)i).M12(i); + ((long)i).M12(ref i); + } + + extension(int receiver) + { + public void M11() {} + } + + extension(string receiver) + { + public void M11() {} + } + + extension(long receiver) + { + public void M12(int x) {} + } + + extension(long receiver) + { + public void M12(ref int x) {} + } +} +"""); + + CompileAndVerify(comp).VerifyDiagnostics(); + } + + [Fact] + public void MemberNameAndSignatureConflict_02() + { + var src = """ +static class Extensions +{ + extension(object receiver) + { + static public void M1() {} + } + + extension(object receiver) + { + static public void M1() {} + } + + extension(object receiver) + { + static public void M2(ref int x) {} + } + + extension(object receiver) + { + static public void M2(ref readonly int x) {} + } + + extension(object receiver) + { + static public void M3(in int x) {} + } + + extension(object receiver) + { + static public void M3(ref readonly int x) {} + } + + extension(object receiver) + { + static public void M4(ref int x) {} + } + + extension(object receiver) + { + static public void M4(in int x) {} + } + + extension(object receiver) + { + static public void M5() {} + static public void M5() {} + } + + extension(int receiver) + { + static public void M6() {} + } + + extension(string receiver) + { + static public void M6() {} + } + + extension(int receiver) + { + static public int M7() => 0; + } + + extension(long receiver) + { + static public long M7() => 0; + } + + extension(int receiver) + { + public static void M8() {} + } + + extension(ref int receiver) + { + public static void M8() {} + } + + extension(int receiver) + { + public void M9() {} + } + + extension(int receiver) + { + public static void M9(int x) {} + } + + extension(ref int receiver) + { + public void M10() {} + } + + extension(int receiver) + { + public static void M10(in int x) {} + } + + extension(int receiver) + { + public void M11() {} + public static void M11(int x) {} + } + + extension(ref int receiver) + { + public void M12() {} + public static void M12(in int x) {} + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (10,28): error CS0111: Type 'Extensions' already defines a member called 'M1' with the same parameter types + // static public void M1() {} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "Extensions").WithLocation(10, 28), + // (20,28): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'ref readonly' and 'ref' + // static public void M2(ref readonly int x) {} + Diagnostic(ErrorCode.ERR_OverloadRefKind, "M2").WithArguments("Extensions", "method", "ref readonly", "ref").WithLocation(20, 28), + // (30,28): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'ref readonly' and 'in' + // static public void M3(ref readonly int x) {} + Diagnostic(ErrorCode.ERR_OverloadRefKind, "M3").WithArguments("Extensions", "method", "ref readonly", "in").WithLocation(30, 28), + // (40,28): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'in' and 'ref' + // static public void M4(in int x) {} + Diagnostic(ErrorCode.ERR_OverloadRefKind, "M4").WithArguments("Extensions", "method", "in", "ref").WithLocation(40, 28), + // (46,28): error CS0111: Type 'Extensions' already defines a member called 'M5' with the same parameter types + // static public void M5() {} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M5").WithArguments("M5", "Extensions").WithLocation(46, 28), + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : It feels unfortunate that we generate conflicting signatures, the methods extend different types (refer to M6 and M7 cases) + + // (56,28): error CS0111: Type 'Extensions' already defines a member called 'M6' with the same parameter types + // static public void M6() {} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M6").WithArguments("M6", "Extensions").WithLocation(56, 28), + // (66,28): error CS0111: Type 'Extensions' already defines a member called 'M7' with the same parameter types + // static public long M7() => 0; + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M7").WithArguments("M7", "Extensions").WithLocation(66, 28), // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Signatures in metadata are different in this case (return type is different), consider if we want to enable this specific case + + // (76,28): error CS0111: Type 'Extensions' already defines a member called 'M8' with the same parameter types + // public static void M8() {} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M8").WithArguments("M8", "Extensions").WithLocation(76, 28), + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Are we comfortable with these four conflicts? + + // (86,28): error CS0111: Type 'Extensions' already defines a member called 'M9' with the same parameter types + // public static void M9(int x) {} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M9").WithArguments("M9", "Extensions").WithLocation(86, 28), + // (96,28): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'in' and 'ref' + // public static void M10(in int x) {} + Diagnostic(ErrorCode.ERR_OverloadRefKind, "M10").WithArguments("Extensions", "method", "in", "ref").WithLocation(96, 28), + // (102,28): error CS0111: Type 'Extensions' already defines a member called 'M11' with the same parameter types + // public static void M11(int x) {} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M11").WithArguments("M11", "Extensions").WithLocation(102, 28), + // (108,28): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'in' and 'ref' + // public static void M12(in int x) {} + Diagnostic(ErrorCode.ERR_OverloadRefKind, "M12").WithArguments("Extensions", "method", "in", "ref").WithLocation(108, 28) + ); + + comp = CreateCompilation(""" +static class Extensions +{ + static void Main() + { + int i = 0; + i.M13(); + int.M13(ref i); + M13(i); + M13(ref i); + + i.M14(); + int.M14(i); + M14(ref i); + M14(i); + } + + extension(int receiver) + { + public void M13() => System.Console.Write(1); + } + + extension(int receiver) + { + public static void M13(ref int x) => System.Console.Write(2); + } + + extension(ref int receiver) + { + public void M14() => System.Console.Write(3); + } + + extension(int receiver) + { + public static void M14(int x) => System.Console.Write(4); + } +} +""", options: TestOptions.DebugExe); + + CompileAndVerify(comp, expectedOutput: "12123434").VerifyDiagnostics(); + } + + [Fact] + public void MemberNameAndSignatureConflict_03() + { + var src = """ +static class Extensions +{ + extension(object receiver) + { + public int P1 => 1; + } + + extension(object receiver) + { + public int P1 => 4; + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (10,20): error CS0102: The type 'Extensions' already contains a definition for 'P1' + // public int P1 => 4; + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P1").WithArguments("Extensions", "P1").WithLocation(10, 20) + ); + } + + [Fact] + public void MemberNameAndSignatureConflict_04() + { + var src = """ +static class Extensions +{ + extension(object receiver) + { + static public int P1 => 1; + } + + extension(object receiver) + { + static public int P1 => 4; + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (10,27): error CS0102: The type 'Extensions' already contains a definition for 'P1' + // static public int P1 => 4; + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P1").WithArguments("Extensions", "P1").WithLocation(10, 27) + ); + } + + [Fact] + public void MemberNameAndSignatureConflict_05() + { + var src = """ +static class Extensions +{ + extension(object receiver) + { + public int P1 => 1; + public int get_P2() => 2; + } + + extension(object receiver) + { + public int get_P1() => 3; + public int P2 => 4; + } +} + +static class Extensions2 +{ + extension(object receiver) + { + public int P3 => 1; + public int get_P4() => 2; + public int get_P3() => 3; + public int P4 => 4; + } +} + +static class Extensions3 +{ + extension(object receiver) + { + public int P1 => 1; + public int set_P2(int x) => 2; + } + + extension(object receiver) + { + public int set_P1(int y) => 3; + public int P2 => 4; + } +} + +static class Extensions4 +{ + extension(object receiver) + { + public int P3 => 1; + public int set_P4(int z) => 2; + public int set_P3(int z) => 3; + public int P4 => 4; + } +} + +static class Extensions5 +{ + extension(object receiver) + { + public int this[int x] => 1; + public int get_Item(long y) => 2; + } + + extension(object receiver) + { + public int get_Item(int a) => 3; + public int this[long b] => 4; + } +} + +static class Extensions6 +{ + extension(object receiver) + { + [System.Runtime.CompilerServices.IndexerName("Indexer")] + public int this[int x] => 1; + } + + extension(object receiver) + { + public int get_Indexer(int a) => 3; + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (5,26): error CS0082: Type 'Extensions' already reserves a member called 'get_P1' with the same parameter types + // public int P1 => 1; + Diagnostic(ErrorCode.ERR_MemberReserved, "1").WithArguments("get_P1", "Extensions").WithLocation(5, 26), + // (12,26): error CS0082: Type 'Extensions' already reserves a member called 'get_P2' with the same parameter types + // public int P2 => 4; + Diagnostic(ErrorCode.ERR_MemberReserved, "4").WithArguments("get_P2", "Extensions").WithLocation(12, 26), + // (20,26): error CS0082: Type 'Extensions2' already reserves a member called 'get_P3' with the same parameter types + // public int P3 => 1; + Diagnostic(ErrorCode.ERR_MemberReserved, "1").WithArguments("get_P3", "Extensions2").WithLocation(20, 26), + // (23,26): error CS0082: Type 'Extensions2' already reserves a member called 'get_P4' with the same parameter types + // public int P4 => 4; + Diagnostic(ErrorCode.ERR_MemberReserved, "4").WithArguments("get_P4", "Extensions2").WithLocation(23, 26), + // (31,20): error CS0082: Type 'Extensions3' already reserves a member called 'set_P1' with the same parameter types + // public int P1 => 1; + Diagnostic(ErrorCode.ERR_MemberReserved, "P1").WithArguments("set_P1", "Extensions3").WithLocation(31, 20), + // (38,20): error CS0082: Type 'Extensions3' already reserves a member called 'set_P2' with the same parameter types + // public int P2 => 4; + Diagnostic(ErrorCode.ERR_MemberReserved, "P2").WithArguments("set_P2", "Extensions3").WithLocation(38, 20), + // (46,20): error CS0082: Type 'Extensions4' already reserves a member called 'set_P3' with the same parameter types + // public int P3 => 1; + Diagnostic(ErrorCode.ERR_MemberReserved, "P3").WithArguments("set_P3", "Extensions4").WithLocation(46, 20), + // (49,20): error CS0082: Type 'Extensions4' already reserves a member called 'set_P4' with the same parameter types + // public int P4 => 4; + Diagnostic(ErrorCode.ERR_MemberReserved, "P4").WithArguments("set_P4", "Extensions4").WithLocation(49, 20), + // (57,35): error CS0082: Type 'Extensions5' already reserves a member called 'get_Item' with the same parameter types + // public int this[int x] => 1; + Diagnostic(ErrorCode.ERR_MemberReserved, "1").WithArguments("get_Item", "Extensions5").WithLocation(57, 35), + // (64,36): error CS0082: Type 'Extensions5' already reserves a member called 'get_Item' with the same parameter types + // public int this[long b] => 4; + Diagnostic(ErrorCode.ERR_MemberReserved, "4").WithArguments("get_Item", "Extensions5").WithLocation(64, 36), + // (73,35): error CS0082: Type 'Extensions6' already reserves a member called 'get_Indexer' with the same parameter types + // public int this[int x] => 1; + Diagnostic(ErrorCode.ERR_MemberReserved, "1").WithArguments("get_Indexer", "Extensions6").WithLocation(73, 35) + ); + } + + [Fact] + public void MemberNameAndSignatureConflict_06() + { + var src = """ +static class Extensions1 +{ + extension(object receiver) + { + public int P1 => 1; + } + + extension(object receiver) + { + public int P1 {set{}} + } +} + +static class Extensions2 +{ + extension(object receiver1) + { + public int this[int x] => 1; + } + + extension(object receiver2) + { + public int this[int y] {set{}} + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (10,20): error CS0102: The type 'Extensions1' already contains a definition for 'P1' + // public int P1 {set{}} + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P1").WithArguments("Extensions1", "P1").WithLocation(10, 20), + // (23,20): error CS0111: Type 'Extensions2' already defines a member called 'this' with the same parameter types + // public int this[int y] {set{}} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "this").WithArguments("this", "Extensions2").WithLocation(23, 20) + ); + } + + [Fact] + public void MemberNameAndSignatureConflict_07() + { + var src = """ +static class Extensions +{ + extension(object receiver) + { + public void M(){} + } + + extension(__arglist) + { + public void M(object x){} + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (8,15): error CS1669: __arglist is not valid in this context + // extension(__arglist) + Diagnostic(ErrorCode.ERR_IllegalVarArgs, "__arglist").WithLocation(8, 15) + ); + } + + [Fact] + public void MemberNameAndSignatureConflict_08() + { + var src = """ +static class Extensions +{ + extension(object receiver) + { + public void M1() {} + } + + public static void M1(object receiver) {} + + extension(int receiver) + { + public void M2() {} + } + + public static void M2(ref int receiver) {} + + extension(in int receiver) + { + public void M3() {} + } + + public static void M3(ref int receiver) {} + + extension(ref readonly int receiver) + { + public void M4() {} + } + + public static void M4(ref int receiver) {} + + extension(ref readonly int receiver) + { + public void M5() {} + } + + public static void M5(in int receiver) {} + + extension(object receiver1) + { + public void M13() {} + } + + public static void M13(object receiver2) {} +} +"""; + var comp = CreateCompilation(src); + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Should we report an error for M2 (the only difference is receiver ref-ness)? + comp.VerifyDiagnostics( + // (5,21): error CS0111: Type 'Extensions' already defines a member called 'M1' with the same parameter types + // public void M1() {} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "Extensions").WithLocation(5, 21), + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : The error might be somewhat confusing in this scenario because there are no parameters and we complain about ref-ness of the receiver. + + // (19,21): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'in' and 'ref' + // public void M3() {} + Diagnostic(ErrorCode.ERR_OverloadRefKind, "M3").WithArguments("Extensions", "method", "in", "ref").WithLocation(19, 21), + // (26,21): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'ref readonly' and 'ref' + // public void M4() {} + Diagnostic(ErrorCode.ERR_OverloadRefKind, "M4").WithArguments("Extensions", "method", "ref readonly", "ref").WithLocation(26, 21), + // (33,21): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'ref readonly' and 'in' + // public void M5() {} + Diagnostic(ErrorCode.ERR_OverloadRefKind, "M5").WithArguments("Extensions", "method", "ref readonly", "in").WithLocation(33, 21), + // (40,21): error CS0111: Type 'Extensions' already defines a member called 'M13' with the same parameter types + // public void M13() {} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M13").WithArguments("M13", "Extensions").WithLocation(40, 21) + ); + + comp = CreateCompilation(""" +static class Extensions +{ + static void Main() + { + 1.M2(); + } + + extension(int receiver) + { + public void M2() {} + } + + public static void M2(this ref int receiver) {} +} +"""); + + comp.VerifyDiagnostics( + // (5,11): error CS0121: The call is ambiguous between the following methods or properties: 'Extensions.extension(int).M2()' and 'Extensions.M2(ref int)' + // 1.M2(); + Diagnostic(ErrorCode.ERR_AmbigCall, "M2").WithArguments("Extensions.extension(int).M2()", "Extensions.M2(ref int)").WithLocation(5, 11) + ); + + comp = CreateCompilation(""" +static class Extensions +{ + static void Main() + { + int i = 0; + 1.M2(); + M2(i); + M2(ref i); + + ((long)i).M12(i); + ((long)i).M12(ref i); + } + + extension(int receiver) + { + public void M2() {} + } + + public static void M2(ref int receiver) {} + + extension(long receiver) + { + public void M12(int x) {} + } + + public static void M12(this long receiver, ref int x) {} +} +"""); + + CompileAndVerify(comp).VerifyDiagnostics(); + } + + [Fact] + public void MemberNameAndSignatureConflict_09() + { + var src = """ +static class Extensions +{ + public static void M1(object receiver) {} + + extension(object receiver) + { + public void M1() {} + } + + public static void M2(ref int receiver) {} + + extension(int receiver) + { + public void M2() {} + } + + public static void M3(ref int receiver) {} + + extension(in int receiver) + { + public void M3() {} + } + + public static void M4(ref int receiver) {} + + extension(ref readonly int receiver) + { + public void M4() {} + } + + public static void M5(in int receiver) {} + + extension(ref readonly int receiver) + { + public void M5() {} + } + + public static void M13(object receiver2) {} + + extension(object receiver1) + { + public void M13() {} + } +} +"""; + var comp = CreateCompilation(src); + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Should we report an error for M2 (the only difference is receiver ref-ness)? + comp.VerifyDiagnostics( + // (7,21): error CS0111: Type 'Extensions' already defines a member called 'M1' with the same parameter types + // public void M1() {} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "Extensions").WithLocation(7, 21), + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : The error might be somewhat confusing in this scenario because there are no parameters and we complain about ref-ness of the receiver. + + // (21,21): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'in' and 'ref' + // public void M3() {} + Diagnostic(ErrorCode.ERR_OverloadRefKind, "M3").WithArguments("Extensions", "method", "in", "ref").WithLocation(21, 21), + // (28,21): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'ref readonly' and 'ref' + // public void M4() {} + Diagnostic(ErrorCode.ERR_OverloadRefKind, "M4").WithArguments("Extensions", "method", "ref readonly", "ref").WithLocation(28, 21), + // (35,21): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'ref readonly' and 'in' + // public void M5() {} + Diagnostic(ErrorCode.ERR_OverloadRefKind, "M5").WithArguments("Extensions", "method", "ref readonly", "in").WithLocation(35, 21), + // (42,21): error CS0111: Type 'Extensions' already defines a member called 'M13' with the same parameter types + // public void M13() {} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M13").WithArguments("M13", "Extensions").WithLocation(42, 21) + ); + + comp = CreateCompilation(""" +static class Extensions +{ + static void Main() + { + 1.M2(); + } + + public static void M2(this ref int receiver) {} + + extension(int receiver) + { + public void M2() {} + } +} +"""); + + comp.VerifyDiagnostics( + // (5,11): error CS0121: The call is ambiguous between the following methods or properties: 'Extensions.extension(int).M2()' and 'Extensions.M2(ref int)' + // 1.M2(); + Diagnostic(ErrorCode.ERR_AmbigCall, "M2").WithArguments("Extensions.extension(int).M2()", "Extensions.M2(ref int)").WithLocation(5, 11) + ); + } + + [Fact] + public void MemberNameAndSignatureConflict_10() + { + var src = """ +static class Extensions +{ + extension(object receiver) + { + static public void M1() {} + } + + static public void M1() {} + + extension(object receiver) + { + static public void M2(ref int x) {} + } + + static public void M2(ref readonly int x) {} + + extension(object receiver) + { + static public void M3(in int x) {} + } + + static public void M3(ref readonly int x) {} + + extension(object receiver) + { + static public void M4(ref int x) {} + } + + static public void M4(in int x) {} + + + extension(int receiver) + { + static public int M7() => 0; + } + + static public long M7() => 0; + + + public static void M9(int receiver) {} + + extension(int receiver) + { + public static void M9(int x) {} + } + + public static void M10(ref int receiver) {} + + extension(int receiver) + { + public static void M10(in int x) {} + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (5,28): error CS0111: Type 'Extensions' already defines a member called 'M1' with the same parameter types + // static public void M1() {} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "Extensions").WithLocation(5, 28), + // (12,28): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'ref' and 'ref readonly' + // static public void M2(ref int x) {} + Diagnostic(ErrorCode.ERR_OverloadRefKind, "M2").WithArguments("Extensions", "method", "ref", "ref readonly").WithLocation(12, 28), + // (19,28): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'in' and 'ref readonly' + // static public void M3(in int x) {} + Diagnostic(ErrorCode.ERR_OverloadRefKind, "M3").WithArguments("Extensions", "method", "in", "ref readonly").WithLocation(19, 28), + // (26,28): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'ref' and 'in' + // static public void M4(ref int x) {} + Diagnostic(ErrorCode.ERR_OverloadRefKind, "M4").WithArguments("Extensions", "method", "ref", "in").WithLocation(26, 28), + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : It feels unfortunate that we generate conflicting signatures + + // (34,27): error CS0111: Type 'Extensions' already defines a member called 'M7' with the same parameter types + // static public int M7() => 0; + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M7").WithArguments("M7", "Extensions").WithLocation(34, 27), + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Are we comfortable with these two conflicts? + + // (44,28): error CS0111: Type 'Extensions' already defines a member called 'M9' with the same parameter types + // public static void M9(int x) {} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M9").WithArguments("M9", "Extensions").WithLocation(44, 28), + // (51,28): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'in' and 'ref' + // public static void M10(in int x) {} + Diagnostic(ErrorCode.ERR_OverloadRefKind, "M10").WithArguments("Extensions", "method", "in", "ref").WithLocation(51, 28) + ); + + comp = CreateCompilation(""" +static class Extensions +{ + static void Main() + { + int i = 0; + i.M13(); + int.M13(ref i); + M13(i); + M13(ref i); + + i.M14(); + int.M14(i); + M14(ref i); + M14(i); + } + + public static void M13(this int receiver) => System.Console.Write(1); + + extension(int receiver) + { + public static void M13(ref int x) => System.Console.Write(2); + } + + public static void M14(this ref int receiver) => System.Console.Write(3); + + extension(int receiver) + { + public static void M14(int x) => System.Console.Write(4); + } +} +""", options: TestOptions.DebugExe); + + CompileAndVerify(comp, expectedOutput: "12123434").VerifyDiagnostics(); + } + + [Fact] + public void MemberNameAndSignatureConflict_11() + { + var src = """ +static class Extensions +{ + static public void M1() {} + + extension(object receiver) + { + static public void M1() {} + } + + static public void M2(ref readonly int x) {} + + extension(object receiver) + { + static public void M2(ref int x) {} + } + + static public void M3(ref readonly int x) {} + + extension(object receiver) + { + static public void M3(in int x) {} + } + + static public void M4(in int x) {} + + extension(object receiver) + { + static public void M4(ref int x) {} + } + + static public long M7() => 0; + + extension(int receiver) + { + static public int M7() => 0; + } + + extension(int receiver) + { + public static void M9(int x) {} + } + + public static void M9(int receiver) {} + + extension(int receiver) + { + public static void M10(in int x) {} + } + + public static void M10(ref int receiver) {} +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (7,28): error CS0111: Type 'Extensions' already defines a member called 'M1' with the same parameter types + // static public void M1() {} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "Extensions").WithLocation(7, 28), + // (14,28): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'ref' and 'ref readonly' + // static public void M2(ref int x) {} + Diagnostic(ErrorCode.ERR_OverloadRefKind, "M2").WithArguments("Extensions", "method", "ref", "ref readonly").WithLocation(14, 28), + // (21,28): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'in' and 'ref readonly' + // static public void M3(in int x) {} + Diagnostic(ErrorCode.ERR_OverloadRefKind, "M3").WithArguments("Extensions", "method", "in", "ref readonly").WithLocation(21, 28), + // (28,28): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'ref' and 'in' + // static public void M4(ref int x) {} + Diagnostic(ErrorCode.ERR_OverloadRefKind, "M4").WithArguments("Extensions", "method", "ref", "in").WithLocation(28, 28), + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : It feels unfortunate that we generate conflicting signatures + + // (35,27): error CS0111: Type 'Extensions' already defines a member called 'M7' with the same parameter types + // static public int M7() => 0; + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M7").WithArguments("M7", "Extensions").WithLocation(35, 27), + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Are we comfortable with these two conflicts? + + // (40,28): error CS0111: Type 'Extensions' already defines a member called 'M9' with the same parameter types + // public static void M9(int x) {} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M9").WithArguments("M9", "Extensions").WithLocation(40, 28), + // (47,28): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'in' and 'ref' + // public static void M10(in int x) {} + Diagnostic(ErrorCode.ERR_OverloadRefKind, "M10").WithArguments("Extensions", "method", "in", "ref").WithLocation(47, 28) + ); + } + + [Fact] + public void MemberNameAndSignatureConflict_12() + { + var src = """ +static class Extensions +{ + extension(object receiver) + { + public int P1 => 1; + } + + public static int get_P1(object receiver) => 4; + + public static int get_P2(object receiver) => 4; + + extension(object receiver) + { + public int P2 => 1; + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (5,26): error CS0111: Type 'Extensions' already defines a member called 'get_P1' with the same parameter types + // public int P1 => 1; + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "1").WithArguments("get_P1", "Extensions").WithLocation(5, 26), + // (14,26): error CS0111: Type 'Extensions' already defines a member called 'get_P2' with the same parameter types + // public int P2 => 1; + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "1").WithArguments("get_P2", "Extensions").WithLocation(14, 26) + ); + } + + [Fact] + public void MemberNameAndSignatureConflict_13() + { + var src = """ +static class Extensions +{ + extension(object receiver) + { + static public int P1 => 1; + } + + public static int P1 => 4; + + public static int P2 => 4; + + extension(object receiver) + { + static public int P2 => 1; + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (8,29): error CS0082: Type 'Extensions' already reserves a member called 'get_P1' with the same parameter types + // public static int P1 => 4; + Diagnostic(ErrorCode.ERR_MemberReserved, "4").WithArguments("get_P1", "Extensions").WithLocation(8, 29), + // (10,29): error CS0082: Type 'Extensions' already reserves a member called 'get_P2' with the same parameter types + // public static int P2 => 4; + Diagnostic(ErrorCode.ERR_MemberReserved, "4").WithArguments("get_P2", "Extensions").WithLocation(10, 29) + ); + } + + [Fact] + public void MemberNameAndSignatureConflict_14() + { + var src = """ +static class Extensions +{ + extension(object receiver) + { + static public int get_P1() => 1; + } + + public static int P1 => 4; + + public static int P2 => 4; + + extension(object receiver) + { + static public int get_P2() => 1; + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (8,29): error CS0082: Type 'Extensions' already reserves a member called 'get_P1' with the same parameter types + // public static int P1 => 4; + Diagnostic(ErrorCode.ERR_MemberReserved, "4").WithArguments("get_P1", "Extensions").WithLocation(8, 29), + // (10,29): error CS0082: Type 'Extensions' already reserves a member called 'get_P2' with the same parameter types + // public static int P2 => 4; + Diagnostic(ErrorCode.ERR_MemberReserved, "4").WithArguments("get_P2", "Extensions").WithLocation(10, 29) + ); + } + + [Fact] + public void MemberNameAndSignatureConflict_15() + { + var src = """ +static class Extensions +{ + extension(object receiver) + { + public int P1 => 1; + } + + public static int set_P1(object receiver, int x) => 4; +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void MemberNameAndSignatureConflict_16() + { + var src = """ +static class Extensions +{ + extension(object receiver) + { + static public int P1 => 1; + } + + public static int P1 {set{}} + + static public int get_P2() => 1; + public static int P2 {set{}} +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Are we comfortable reporting an error like this? + + // (8,23): error CS0082: Type 'Extensions' already reserves a member called 'get_P1' with the same parameter types + // public static int P1 {set{}} + Diagnostic(ErrorCode.ERR_MemberReserved, "P1").WithArguments("get_P1", "Extensions").WithLocation(8, 23), + + // (11,23): error CS0082: Type 'Extensions' already reserves a member called 'get_P2' with the same parameter types + // public static int P2 {set{}} + Diagnostic(ErrorCode.ERR_MemberReserved, "P2").WithArguments("get_P2", "Extensions").WithLocation(11, 23) + ); + } + + [Fact] + public void MemberNameAndSignatureConflict_17() + { + var src = """ +static class Extensions +{ + extension(object receiver) + { + static public int set_P1(int x) => 1; + } + + public static int P1 => 4; + + static public int set_P2(int x) => 1; + public static int P2 => 4; +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Are we comfortable reporting an error like this? + + // (8,23): error CS0082: Type 'Extensions' already reserves a member called 'set_P1' with the same parameter types + // public static int P1 => 4; + Diagnostic(ErrorCode.ERR_MemberReserved, "P1").WithArguments("set_P1", "Extensions").WithLocation(8, 23), + + // (11,23): error CS0082: Type 'Extensions' already reserves a member called 'set_P2' with the same parameter types + // public static int P2 => 4; + Diagnostic(ErrorCode.ERR_MemberReserved, "P2").WithArguments("set_P2", "Extensions").WithLocation(11, 23) + ); + } + + [Fact] + public void MemberNameAndSignatureConflict_18() + { + var src = """ +public static class Extensions +{ + extension(object receiver) + { + static public void M1(int x) {} + } + + public static int M1 => 4; + + extension(object receiver) + { + static public void M2(int x) {} + } + + public static int M2 = 4; + + extension(object receiver) + { + static public void M3(int x) {} + } + +#pragma warning disable CS0067 // The event 'Extensions.M3' is never used + public static event System.Action M3; +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (5,28): error CS0102: The type 'Extensions' already contains a definition for 'M1' + // static public void M1(int x) {} + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "M1").WithArguments("Extensions", "M1").WithLocation(5, 28), + // (12,28): error CS0102: The type 'Extensions' already contains a definition for 'M2' + // static public void M2(int x) {} + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "M2").WithArguments("Extensions", "M2").WithLocation(12, 28), + // (19,28): error CS0102: The type 'Extensions' already contains a definition for 'M3' + // static public void M3(int x) {} + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "M3").WithArguments("Extensions", "M3").WithLocation(19, 28) + ); + } + + [Fact] + public void MemberNameAndSignatureConflict_19() + { + var src = """ +public static class Extensions +{ + public static int M1 => 4; + + extension(object receiver) + { + static public void M1(int x) {} + } + + public static int M2 = 4; + + extension(object receiver) + { + static public void M2(int x) {} + } + +#pragma warning disable CS0067 // The event 'Extensions.M3' is never used + public static event System.Action M3; + + extension(object receiver) + { + static public void M3(int x) {} + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (7,28): error CS0102: The type 'Extensions' already contains a definition for 'M1' + // static public void M1(int x) {} + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "M1").WithArguments("Extensions", "M1").WithLocation(7, 28), + // (14,28): error CS0102: The type 'Extensions' already contains a definition for 'M2' + // static public void M2(int x) {} + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "M2").WithArguments("Extensions", "M2").WithLocation(14, 28), + // (22,28): error CS0102: The type 'Extensions' already contains a definition for 'M3' + // static public void M3(int x) {} + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "M3").WithArguments("Extensions", "M3").WithLocation(22, 28) + ); + } + + [Fact] + public void MemberNameAndSignatureConflict_20_ReceiverType_TupleNameDifference() + { + var src = """ +public static class Extensions +{ + extension((int a, int b) receiver) + { + void M1() {} + } + + extension((int c, int d)) + { + static void M1() {} + } + + extension(int receiver) + { + void M1() {} + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (10,21): error CS0111: Type 'Extensions' already defines a member called 'M1' with the same parameter types + // static void M1() {} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "Extensions").WithLocation(10, 21) + ); + } + + [Fact] + public void MemberNameAndSignatureConflict_21_ReceiverType_NativeIntDifference() + { + var src = """ +public static class Extensions +{ + extension(System.IntPtr receiver) + { + void M1() {} + } + + extension(nint) + { + static void M1() {} + } + + extension(int receiver) + { + void M1() {} + } +} +"""; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); + + comp.VerifyDiagnostics( + // (10,21): error CS0111: Type 'Extensions' already defines a member called 'M1' with the same parameter types + // static void M1() {} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "Extensions").WithLocation(10, 21) + ); + } + + [Fact] + public void MemberNameAndSignatureConflict_22_ReceiverType_NullabilityDifference() + { + var src = """ +#nullable enable + +public static class Extensions +{ + extension(string[]) + { + static void M1() {} + } + + extension(string?[] receiver) + { + void M1() {} + } + + extension(int receiver) + { + void M1() {} + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (12,14): error CS0111: Type 'Extensions' already defines a member called 'M1' with the same parameter types + // void M1() {} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "Extensions").WithLocation(12, 14) + ); + } + + [Fact] + public void MemberNameAndSignatureConflict_23_Receiver_TypeDifference() + { + var src = """ +public static class Extensions +{ + extension(int receiver) + { + void M1() {} + } + + extension(long) + { + static void M1() {} + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp).VerifyDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void MemberNameAndSignatureConflict_24_Genericity(bool insertAtTheBeginning) + { + var insert = """ + extension(S[]) + { + static void M1(int z) {} + } +"""; + + var src = @" +public static class Extensions +{ +" + (insertAtTheBeginning ? insert : "") + @" + + extension(T[]) where T : class + { + static void M1(T x) {} + } + +" + (!insertAtTheBeginning ? insert : "") + @" + + extension(U[] receiver) where U : struct + { +#line 17 + void M1(U y) {} + void M2(U y) {} + static void M2(U x) {} + } + + extension(int[] receiver) + { + void M1(int a) {} + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (17,14): error CS0111: Type 'Extensions' already defines a member called 'M1' with the same parameter types + // void M1(U y) {} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "Extensions").WithLocation(17, 14), + // (19,21): error CS0111: Type 'Extensions' already defines a member called 'M2' with the same parameter types + // static void M2(U x) {} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M2").WithArguments("M2", "Extensions").WithLocation(19, 21) + ); + } + + [Fact] + public void MemberNameAndSignatureConflict_25_Genericity_DifferentArity() + { + var src = """ +public static class Extensions1 +{ + extension(T1) + { + static void M1(T1 x) {} + } + + extension(T1) + { + static void M1(T1 x) {} + } +} + +public static class Extensions2 +{ + extension(T2) + { + static void M1(T2 x) {} + } + + extension(T2) + { + static void M1(T2 x) {} + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (8,23): error CS9295: The extended type 'T1' must reference all the type parameters declared by the extension, but type parameter 'U1' is not referenced. + // extension(T1) + Diagnostic(ErrorCode.ERR_UnderspecifiedExtension, "T1").WithArguments("T1", "U1").WithLocation(8, 23), + // (16,23): error CS9295: The extended type 'T2' must reference all the type parameters declared by the extension, but type parameter 'U2' is not referenced. + // extension(T2) + Diagnostic(ErrorCode.ERR_UnderspecifiedExtension, "T2").WithArguments("T2", "U2").WithLocation(16, 23)); + } + + [Fact] + public void MemberNameAndSignatureConflict_26_Genericity() + { + var src = """ +public static class Extensions1 +{ + extension(C) + { + static void M1() {} + } + + extension(C) + { + static void M1() {} + } +} + +class C {} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (10,21): error CS0111: Type 'Extensions1' already defines a member called 'M1' with the same parameter types + // static void M1() {} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "Extensions1").WithLocation(10, 21) + ); + } + + [Fact] + public void MemberNameAndSignatureConflict_27_Genericity() + { + var src = """ +public static class Extensions1 +{ + extension(C) + { + void M1() {} + } + + extension(C) + { + void M1() {} + } +} + +class C {} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp).VerifyDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void MemberNameAndSignatureConflict_28_Genericity(bool insertAtTheBeginning) + { + var insert = """ + extension(S[]) + { + static void M1(ref int z) {} + } +"""; + + var src = @" +public static class Extensions +{ +" + (insertAtTheBeginning ? insert : "") + @" + + extension(T[]) + { + static void M1(ref T x) {} + } + +" + (!insertAtTheBeginning ? insert : "") + @" + + extension(U[] receiver) + { +#line 17 + void M1(in U y) {} + void M2(ref U y) {} + static void M2(in U x) {} + } + + extension(int[] receiver) + { + void M1(ref int a) {} + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (17,14): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'in' and 'ref' + // void M1(in U y) {} + Diagnostic(ErrorCode.ERR_OverloadRefKind, "M1").WithArguments("Extensions", "method", "in", "ref").WithLocation(17, 14), + // (19,21): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'in' and 'ref' + // static void M2(in U x) {} + Diagnostic(ErrorCode.ERR_OverloadRefKind, "M2").WithArguments("Extensions", "method", "in", "ref").WithLocation(19, 21) + ); + } + + [Theory] + [CombinatorialData] + public void MemberNameAndSignatureConflict_29_Indexers(bool insertAtTheBeginning) + { + var insert = """ + extension(S[]) + { + static void M1(int z) {} + } +"""; + + var src = @" +public static class Extensions +{ +" + (insertAtTheBeginning ? insert : "") + @" + + extension(T[]) + { +#line 8 + int this[T x] => default; + } + +" + (!insertAtTheBeginning ? insert : "") + @" + + extension(U[] receiver) + { + void Item(U x) {} + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (8,13): error CS0102: The type 'Extensions' already contains a definition for 'Item' + // int this[T x] => default; + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "this").WithArguments("Extensions", "Item").WithLocation(8, 13) + ); + } + + [Theory] + [CombinatorialData] + public void MemberNameAndSignatureConflict_30_Indexers(bool insertAtTheBeginning) + { + var insert = """ + extension(S[]) + { + static void M1(int z) {} + } +"""; + + var src = @" +public static class Extensions +{ +" + (insertAtTheBeginning ? insert : "") + @" + + extension(T[]) + { + int this[T x] => default; + } + +" + (!insertAtTheBeginning ? insert : "") + @" + + extension(U[] receiver) + { +#line 18 + int this[U x] { set{}} + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (18,13): error CS0111: Type 'Extensions' already defines a member called 'this' with the same parameter types + // int this[U x] { set{}} + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "this").WithArguments("this", "Extensions").WithLocation(18, 13) + ); + } + + [Theory] + [CombinatorialData] + public void MemberNameAndSignatureConflict_31_Indexers(bool insertAtTheBeginning) + { + var insert = """ + extension(S[]) + { + static void M1(int z) {} + } +"""; + + var src = @" +public static class Extensions +{ +" + (insertAtTheBeginning ? insert : "") + @" + + extension(T[]) + { + int this[T x] => default; + } + +" + (!insertAtTheBeginning ? insert : "") + @" + + extension(U[] receiver) + { +#line 18 + [System.Runtime.CompilerServices.IndexerName(""NotItem"")] + int this[int x] { set{}} + } +} +"; + var comp = CreateCompilation(src); + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : The "within a type" part of the message might be somewhat misleading + comp.VerifyDiagnostics( + // (19,13): error CS0668: Two indexers have different names; the IndexerName attribute must be used with the same name on every indexer within a type + // int this[int x] { set{}} + Diagnostic(ErrorCode.ERR_InconsistentIndexerNames, "this").WithLocation(19, 13) + ); + } + + [Theory] + [CombinatorialData] + public void MemberNameAndSignatureConflict_32_Properties(bool insertAtTheBeginning) + { + var insert = """ + extension(S[]) + { + static void M1(int z) {} + } +"""; + + var src = @" +public static class Extensions +{ +" + (insertAtTheBeginning ? insert : "") + @" + + extension(T[]) + { + T P => default; + } + +" + (!insertAtTheBeginning ? insert : "") + @" + + extension(U[] receiver) + { +#line 18 + void P(U x) {} + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (18,14): error CS0102: The type 'Extensions' already contains a definition for 'P' + // void P(U x) {} + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P").WithArguments("Extensions", "P").WithLocation(18, 14) + ); + } + + [Theory] + [CombinatorialData] + public void MemberNameAndSignatureConflict_33_Properties(bool insertAtTheBeginning) + { + var insert = """ + extension(S[]) + { + static void M1(int z) {} + } +"""; + + var src = @" +public static class Extensions +{ +" + (insertAtTheBeginning ? insert : "") + @" + + extension(T[]) + { +#line 8 + T P => default; + } + +" + (!insertAtTheBeginning ? insert : "") + @" + + extension(U[] receiver) + { + static void set_P(U x) {} + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (8,11): error CS0082: Type 'Extensions' already reserves a member called 'set_P' with the same parameter types + // T P => default; + Diagnostic(ErrorCode.ERR_MemberReserved, "P").WithArguments("set_P", "Extensions").WithLocation(8, 11) + ); + } + + [Theory] + [CombinatorialData] + public void MemberNameAndSignatureConflict_34_Properties(bool insertAtTheBeginning) + { + var insert = """ + extension(S[]) + { + static void M1(int z) {} + } +"""; + + var src = @" +public static class Extensions +{ +" + (insertAtTheBeginning ? insert : "") + @" + + extension(T[]) + { +#line 8 + T P => default; + } + +" + (!insertAtTheBeginning ? insert : "") + @" + + extension(U[] receiver) + { + U[] get_P => null; + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (8,16): error CS0102: The type 'Extensions' already contains a definition for 'get_P' + // T P => default; + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "default").WithArguments("Extensions", "get_P").WithLocation(8, 16) + ); + } + + [Fact] + public void MethodInvocation_01() + { + var source = """ +new object().M(); + +static class E1 +{ + extension(object o) + { + public void M() { } + } +} +static class E2 +{ + public static void M(this object o) { } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (1,14): error CS0121: The call is ambiguous between the following methods or properties: 'E1.extension(object).M()' and 'E2.M(object)' + // new object().M(); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("E1.extension(object).M()", "E2.M(object)").WithLocation(1, 14)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new object().M"); + Assert.Equal(["void E1.<>E__0.M()", "void System.Object.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void MethodInvocation_02() + { + var source = """ +new object().M(42); + +static class E1 +{ + extension(object o) + { + public void M(int i) { System.Console.Write("ran"); } + } +} +static class E2 +{ + public static void M(this object o, string s) => throw null; +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new object().M"); + Assert.Equal("void E1.<>E__0.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void MethodInvocation_03() + { + var source = """ +new object().M(""); + +static class E1 +{ + extension(object o) + { + public void M(int i) => throw null; + } +} +static class E2 +{ + public static void M(this object o, string s) { System.Console.Write("ran"); } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "new object().M"); + Assert.Equal("void System.Object.M(System.String s)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void MethodInvocation_04() + { + var source = """ +42.M(); + +static class E1 +{ + extension(int i) + { + public void M() { System.Console.Write("ran"); } + } +} +static class E2 +{ + public static void M(this int? i) => throw null; +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "42.M"); + Assert.Equal("void E1.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void MethodInvocation_05() + { + var source = """ +42.M(); + +static class E1 +{ + extension(int? i) + { + public void M() => throw null; + } +} +static class E2 +{ + public static void M(this int i) { System.Console.Write("ran"); } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "42.M"); + Assert.Equal("void System.Int32.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void MethodInvocation_06() + { + var src = """ +object.M(); + +public static class E +{ + extension(object) + { + public static void M() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,8): error CS0411: The type arguments for method 'E.extension(object).M()' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // object.M(); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "M").WithArguments("E.extension(object).M()").WithLocation(1, 8)); + } + + [Fact] + public void MethodInvocation_RemoveLowerPriorityMembers_01() + { + var source = """ +42.M(43); + +static class E1 +{ + extension(int i) + { + public void M(int j) => throw null; + + [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] + public void M(long l) { System.Console.Write("ran"); } + } +} +"""; + var comp = CreateCompilation([source, OverloadResolutionPriorityAttributeDefinition]); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "42.M"); + Assert.Equal("void E1.<>E__0.M(System.Int64 l)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void MethodInvocation_RemoveLowerPriorityMembers_02() + { + var source = """ +42.M(43); + +static class E1 +{ + extension(int i) + { + public void M(int j) { System.Console.Write("ran"); } + } + extension(int i) + { + [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] + public void M(long l) => throw null; + } +} +"""; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : ORPA should look at the containing static class (rather than look at the extension declaration) as the "containing type" + var comp = CreateCompilation([source, OverloadResolutionPriorityAttributeDefinition]); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "42.M"); + Assert.Equal("void E1.<>E__0.M(System.Int32 j)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void MethodInvocation_RemoveLowerPriorityMembers_03() + { + var source = """ +42.M(43); + +static class E1 +{ + extension(int i) + { + public void M(int j) { System.Console.Write("ran"); } + } + [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] + public static void M(this int i, long l) => throw null; +} +"""; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : ORPA should look at the containing static class (rather than look at the extension declaration) as the "containing type" + var comp = CreateCompilation([source, OverloadResolutionPriorityAttributeDefinition]); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "42.M"); + Assert.Equal("void E1.<>E__0.M(System.Int32 j)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void MethodInvocation_RemoveLowerPriorityMembers_04() + { + var source = """ +42.M(43); + +static class E1 +{ + public static void M(this int i, int j) { System.Console.Write("ran"); } + extension(int i) + { + [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] + public void M(long l) => throw null; + } +} +"""; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : ORPA should look at the containing static class (rather than look at the extension declaration) as the "containing type" + var comp = CreateCompilation([source, OverloadResolutionPriorityAttributeDefinition]); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "42.M"); + Assert.Equal("void System.Int32.M(System.Int32 j)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void MethodInvocation_RemoveStaticInstanceMismatches_01() + { + var src = """ +using N; + +42.M(); + +static class E1 +{ + extension(object o) + { + public static void M() => throw null; // skipped + } +} + +namespace N +{ + static class E2 + { + extension(object o) + { + public void M() { System.Console.Write("ran"); } + } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "42.M"); + Assert.Equal("void N.E2.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void MethodInvocation_RemoveStaticInstanceMismatches_02() + { + var src = """ +using N; + +42.M(); + +static class E1 +{ + extension(object o) + { + public void M() { System.Console.Write("ran"); } + } +} + +namespace N +{ + static class E2 + { + extension(object o) + { + public void M() => throw null; + } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,1): hidden CS8019: Unnecessary using directive. + // using N; + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using N;").WithLocation(1, 1)); + CompileAndVerify(comp, expectedOutput: "ran"); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "42.M"); + Assert.Equal("void E1.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void MethodInvocation_RemoveStaticInstanceMismatches_03() + { + var src = """ +using N; + +int.M(); + +static class E1 +{ + extension(object o) + { + public void M() => throw null; + } +} + +namespace N +{ + static class E2 + { + extension(object o) + { + public static void M() { System.Console.Write("ran"); } + } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "int.M"); + Assert.Equal("void N.E2.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void MethodInvocation_RemoveStaticInstanceMismatches_ColorColor_01() + { + var src = """ +using N; + +Color.M2(null); + +class Color +{ + public static void M2(Color Color) + { + Color.M(); + } +} + +static class E1 +{ + extension(Color) + { + public static void M() { System.Console.Write("ran"); } + } +} + +namespace N +{ + static class E2 + { + extension(Color c) + { + public void M() => throw null; + } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,1): hidden CS8019: Unnecessary using directive. + // using N; + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using N;").WithLocation(1, 1)); + + CompileAndVerify(comp, expectedOutput: "ran"); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "Color.M"); + Assert.Equal("void E1.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(SymbolKind.NamedType, model.GetSymbolInfo(memberAccess.Expression).Symbol.Kind); + } + + [Fact] + public void MethodInvocation_RemoveStaticInstanceMismatches_ColorColor_02() + { + var src = """ +using N; + +Color.M2(new Color()); + +class Color +{ + public static void M2(Color Color) + { + Color.M(); + } +} + +static class E1 +{ + extension(Color c) + { + public void M() { System.Console.Write("ran"); } + } +} + +namespace N +{ + static class E2 + { + extension(Color) + { + public static void M() => throw null; + } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,1): hidden CS8019: Unnecessary using directive. + // using N; + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using N;").WithLocation(1, 1)); + CompileAndVerify(comp, expectedOutput: "ran"); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "Color.M"); + Assert.Equal("void E1.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(SymbolKind.Parameter, model.GetSymbolInfo(memberAccess.Expression).Symbol.Kind); + } + + [Fact] + public void MethodInvocation_RemoveInaccessibleTypeArguments() + { + var src = """ +int.M(new A.C()); + +static class E1 +{ + extension(int) + { + public static void M(I x) { } + } +} + +interface I { } + +class A +{ + private class B { } + public class C : I { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,5): error CS0122: 'E1.extension(int).M(I)' is inaccessible due to its protection level + // int.M(new A.C()); + Diagnostic(ErrorCode.ERR_BadAccess, "M").WithArguments("E1.extension(int).M(I)").WithLocation(1, 5)); + } + + [Fact] + public void MethodInvocation_RemoveLessDerivedMembers() + { + var src = """ +"".M(""); + +static class E +{ + extension(object o) + { + public void M(string s) { } + } + extension(string s) + { + public void M(object o) { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,4): error CS0121: The call is ambiguous between the following methods or properties: 'E.extension(object).M(string)' and 'E.extension(string).M(object)' + // "".M(""); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("E.extension(object).M(string)", "E.extension(string).M(object)").WithLocation(1, 4)); + } + + [Fact] + public void MethodInvocation_RemoveWorseMembers_01() + { + var src = """ +I i = null; +i.M(); + +static class E1 +{ + extension(I i) + { + public void M() { } + } +} +static class E2 +{ + extension(I i) + { + public void M() { } + } +} +interface I { } +class C1 { } +class C2 : C1 { } +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "i.M"); + Assert.Equal("void E1.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void MethodInvocation_RemoveWorseMembers_02() + { + var src = """ +I.M(); + +static class E1 +{ + extension(I) + { + public static void M() { } + } +} +static class E2 +{ + extension(I) + { + public static void M() { } + } +} +interface I { } +class C1 { } +class C2 : C1 { } +"""; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : confirm whether we want this betterness behavior (for methods and/or properties) + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "I.M"); + Assert.Equal("void E1.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void MethodInvocation_RemoveWorseMembers_03() + { + var src = """ +42.M(); + +static class E1 +{ + extension(T t) + { + public void M() { } + } +} +static class E2 +{ + extension(int i) + { + public void M() { System.Console.Write("ran"); } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "42.M"); + Assert.Equal("void E2.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void MethodInvocation_RemoveWorseMembers_04() + { + var src = """ +int.M(); + +static class E1 +{ + extension(T) + { + public static void M() { } + } +} +static class E2 +{ + extension(int) + { + public static void M() { System.Console.Write("ran"); } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "int.M"); + Assert.Equal("void E2.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void MethodInvocation_RemoveWorseMembers_05() + { + var src = """ +42.M(); + +static class E1 +{ + extension(int i) + { + public void M() { } + } +} +static class E2 +{ + extension(in int i) + { + public void M() => throw null; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "42.M"); + Assert.Equal("void E1.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void MethodInvocation_RemoveWorseMembers_06() + { + var src = """ +int.M(); + +static class E1 +{ + extension(int) + { + public static void M() { } + } +} +static class E2 +{ + extension(in int i) + { + public static void M() => throw null; + } +} +"""; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : confirm whether we want this betterness behavior (for methods and/or properties) + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "int.M"); + Assert.Equal("void E1.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void MethodInvocation_RemoveWorseMembers_07() + { + var src = """ +int.M(42); + +static class E1 +{ + extension(int) + { + public static void M(T t) { } + } +} +static class E2 +{ + extension(T t) + { + public static void M(int i) => throw null; + } +} +"""; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : confirm whether we want this betterness behavior for methods + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,5): error CS0121: The call is ambiguous between the following methods or properties: 'E1.extension(int).M(T)' and 'E2.extension(T).M(int)' + // int.M(42); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("E1.extension(int).M(T)", "E2.extension(T).M(int)").WithLocation(1, 5)); + } + + [Fact] + public void MethodInvocation_RemoveWorseMembers_08() + { + var src = """ +int.M(42); +0.M2(42); + +static class E1 +{ + extension(T t) + { + public static void M(U u) => throw null; + public void M2(U u) => throw null; + } +} +static class E2 +{ + extension(T t) + { + public static void M(int i) { System.Console.Write("ran "); } + public void M2(int i) { System.Console.Write("ran2"); } + } +} +"""; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : confirm whether we want this betterness behavior for methods when the receiver is a type + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "ran ran2").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "int.M"); + Assert.Equal("void E2.<>E__0.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void MethodInvocation_ByValueArgumentForRefReadonlyParameter_01() + { + var src = """ +int.M(42); + +static class E +{ + extension(int) + { + public static void M(ref readonly int i) { System.Console.Write(i); } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,7): warning CS9193: Argument 1 should be a variable because it is passed to a 'ref readonly' parameter + // int.M(42); + Diagnostic(ErrorCode.WRN_RefReadonlyNotVariable, "42").WithArguments("1").WithLocation(1, 7)); + + CompileAndVerify(comp, expectedOutput: "42"); + } + + [Fact] + public void MethodInvocation_ByValueArgumentForRefReadonlyParameter_02() + { + var src = """ +int i = 42; +int.M(i); + +static class E +{ + extension(int) + { + public static void M(ref readonly int i) { System.Console.Write(i); } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (2,7): warning CS9192: Argument 1 should be passed with 'ref' or 'in' keyword + // int.M(i); + Diagnostic(ErrorCode.WRN_ArgExpectedRefOrIn, "i").WithArguments("1").WithLocation(2, 7)); + + CompileAndVerify(comp, expectedOutput: "42"); + } + + [Fact] + public void MethodInvocation_ByValueArgumentForRefReadonlyParameter_03() + { + var src = """ +var f = (ref readonly int i) => int.M(i); +int i = 42; +f(ref i); + + +static class E +{ + extension(int) + { + public static void M(ref readonly int i) { System.Console.Write(i); } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,39): warning CS9195: Argument 1 should be passed with the 'in' keyword + // var f = (ref readonly int i) => int.M(i); + Diagnostic(ErrorCode.WRN_ArgExpectedIn, "i").WithArguments("1").WithLocation(1, 39)); + + CompileAndVerify(comp, expectedOutput: "42"); + } + + [Fact] + public void MethodInvocation_RefArgumentForInParameter() + { + var src = """ +int i = 42; +int.M(ref i); + +static class E +{ + extension(int) + { + public static void M(in int i) { System.Console.Write(i); } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (2,11): warning CS9191: The 'ref' modifier for argument 1 corresponding to 'in' parameter is equivalent to 'in'. Consider using 'in' instead. + // int.M(ref i); + Diagnostic(ErrorCode.WRN_BadArgRef, "i").WithArguments("1").WithLocation(2, 11)); + + CompileAndVerify(comp, expectedOutput: "42"); + } + + [Fact] + public void MethodInvocation_ByValueReceiverForRefReadonlyParameter_01() + { + var src = """ +42.M(); + +static class E +{ + extension(ref readonly int i) + { + public void M() { System.Console.Write(42); } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,1): warning CS9193: Argument 0 should be a variable because it is passed to a 'ref readonly' parameter + // 42.M(); + Diagnostic(ErrorCode.WRN_RefReadonlyNotVariable, "42").WithArguments("0").WithLocation(1, 1)); + + CompileAndVerify(comp, expectedOutput: "42"); + } + + [Fact] + public void MethodInvocation_ByValueReceiverForRefReadonlyParameter_02() + { + var src = """ +int i = 42; +i.M(); + +static class E +{ + extension(ref readonly int i) + { + public void M() { System.Console.Write(i); } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + } + + [Fact] + public void MethodInvocation_ByValueReceiverForRefReadonlyParameter_03() + { + var src = """ +var f = (ref readonly int i) => i.M(); +int i = 42; +f(ref i); + +static class E +{ + extension(ref readonly int i) + { + public void M() { System.Console.Write(i); } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + } + + [Fact] + public void MethodInvocation_Params() + { + var src = """ +int.M(42, 43); + +static class E +{ + extension(int) + { + public static void M(params int[] i) { System.Console.Write((i[0], i[1])); } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "(42, 43)").VerifyDiagnostics(); + } + + [Fact] + public void MethodInvocation_Params_02() + { + var src = """ +int.M([42, 43]); + +static class E +{ + extension(int) + { + public static void M(params int[] i) { System.Console.Write((i[0], i[1])); } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "(42, 43)").VerifyDiagnostics(); + } + + [Fact] + public void MethodInvocation_Params_03() + { + var src = """ +int.M([42, 43]); + +static class E +{ + extension(int) + { + public static void M(params long[] l) { System.Console.Write((l[0], l[1])); } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "(42, 43)").VerifyDiagnostics(); + } + + [Fact] + public void MethodInvocation_DefaultValue() + { + var src = """ +int.M(); + +static class E +{ + extension(int) + { + public static void M(int i = 42) { System.Console.Write(i); } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + } + + [Fact] + public void MethodInvocation_DefaultValue_02() + { + var src = """ +42.M(); + +static class E +{ + extension(int i = 0) + { + public void M(int j = 1) { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (5,15): error CS9284: The receiver parameter of an extension cannot have a default value + // extension(int i = 0) + Diagnostic(ErrorCode.ERR_ExtensionParameterDisallowsDefaultValue, "int i = 0").WithLocation(5, 15)); + } + + [Fact] + public void MethodInvocation_InaccessibleTypeArguments() + { + var src = """ +new A.C().M(); +new A.C().M2(); + +static class E1 +{ + extension(I i) + { + public void M() { } + } + public static void M2(this I i) { } +} + +interface I { } + +class A +{ + private class B { } + public class C : I { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,11): error CS0122: 'E1.extension(I).M()' is inaccessible due to its protection level + // new A.C().M(); + Diagnostic(ErrorCode.ERR_BadAccess, "M").WithArguments("E1.extension(I).M()").WithLocation(1, 11), + // (2,11): error CS0122: 'E1.M2(I)' is inaccessible due to its protection level + // new A.C().M2(); + Diagnostic(ErrorCode.ERR_BadAccess, "M2").WithArguments("E1.M2(I)").WithLocation(2, 11)); + } + + [Fact] + public void PropertyAccess_InaccessibleTypeArguments() + { + var src = """ +_ = new A.C().P; + +static class E1 +{ + extension(I i) + { + public int P => 0; + } +} + +interface I { } + +class A +{ + private class B { } + public class C : I { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,5): error CS9286: 'A.C' does not contain a definition for 'P' and no accessible extension member 'P' for receiver of type 'A.C' could be found (are you missing a using directive or an assembly reference?) + // _ = new A.C().P; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "new A.C().P").WithArguments("A.C", "P").WithLocation(1, 5)); + } + + [Fact] + public void MethodInvocation_ReceiverConversion() + { + var src = """ +42.M(); + +static class E +{ + extension(object o) + { + public void M() => throw null; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var literal = GetSyntax(tree, "42"); + Assert.Equal("System.Int32", model.GetTypeInfo(literal).Type.ToTestDisplayString()); + Assert.Equal("System.Object", model.GetTypeInfo(literal).ConvertedType.ToTestDisplayString()); + } + + [Fact] + public void MethodInvocation_ReceiverConversion_ColorColor() + { + var src = """ +Color.M2(new Color(42)); + +class Color(int i) : Base(i) +{ + public static void M2(Color Color) + { + Color.M(); + } +} + +class Base(int i) { public int value = i; } + +static class E +{ + extension(Base b) + { + public void M() { System.Console.Write(b.value); } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var color = GetSyntax(tree, "Color.M").Expression; + Assert.Equal("Color", model.GetTypeInfo(color).Type.ToTestDisplayString()); + Assert.Equal("Base", model.GetTypeInfo(color).ConvertedType.ToTestDisplayString()); + } + + [Fact] + public void PropertyAccess_ReceiverConversion() + { + var src = """ +_ = 42.P; + +static class E +{ + extension(object o) + { + public int P => throw null; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var literal = GetSyntax(tree, "42"); + Assert.Equal("System.Int32", model.GetTypeInfo(literal).Type.ToTestDisplayString()); + Assert.Equal("System.Object", model.GetTypeInfo(literal).ConvertedType.ToTestDisplayString()); + } + + [Fact] + public void PropertyAccess_ReceiverConversion_ColorColor() + { + var src = """ +Color.M2(new Color(42)); + +class Color(int i) : Base(i) +{ + public static void M2(Color Color) + { + _ = Color.P; + } +} + +class Base(int i) { public int value = i; } + +static class E +{ + extension(Base b) + { + public int P { get { System.Console.Write(b.value); return 0; } } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var color = GetSyntax(tree, "Color.P").Expression; + Assert.Equal("Color", model.GetTypeInfo(color).Type.ToTestDisplayString()); + Assert.Equal("Base", model.GetTypeInfo(color).ConvertedType.ToTestDisplayString()); + } + + [Fact] + public void MethodInvocation_BrokenConstraint_01() + { + var src = """ +42.M("", null); + +static class E +{ + extension(object o) + { + public void M(T t, C c) where T : struct => throw null; + } +} + +class C where U : struct { } +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,4): error CS0453: The type 'string' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'E.extension(object).M(T, C)' + // 42.M("", null); + Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "M").WithArguments("E.extension(object).M(T, C)", "T", "string").WithLocation(1, 4)); + } + + [Fact] + public void MethodInvocation_BrokenConstraint_02() + { + var src = """ +42.M(null, ""); + +static class E +{ + extension(object o) + { + public void M(C c, T t) where T : struct => throw null; + } +} + +class C where U : struct { } +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,4): error CS0453: The type 'string' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'E.extension(object).M(C, T)' + // 42.M(null, ""); + Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "M").WithArguments("E.extension(object).M(C, T)", "T", "string").WithLocation(1, 4)); + } + + [Fact] + public void MethodInvocation_ExtraRef() + { + var src = """ +int i = 0; +int.M(ref i); + +static class E +{ + extension(int) + { + public static void M(int i) => throw null; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (2,11): error CS1615: Argument 2 may not be passed with the 'ref' keyword + // int.M(ref i); + Diagnostic(ErrorCode.ERR_BadArgExtraRef, "i").WithArguments("2", "ref").WithLocation(2, 11)); + } + + [Fact] + public void SingleCandidate_Extension() + { + string src = """ +public class C +{ + static void Main() + { + dynamic d = 1; + var result = new C().Test("name", d); + System.Console.Write(result); + } +} + +static class Extensions +{ + extension(C c) + { + public int Test(string name, object value) => 123; + } +} +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.StandardAndCSharp); + + comp.VerifyDiagnostics( + // (6,22): error CS1973: 'C' has no applicable method named 'Test' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax. + // var result = new C().Test("name", d); + Diagnostic(ErrorCode.ERR_BadArgTypeDynamicExtension, @"new C().Test(""name"", d)").WithArguments("C", "Test").WithLocation(6, 22)); + } + + [Fact] + public void ArgList_Error() + { + string source = """ +dynamic d = 1; +object.M(d); + +static class Extensions +{ + extension(object) + { + public static int M(__arglist) => 123; + } +} +"""; + CreateCompilation(source, targetFramework: TargetFramework.Net90).VerifyDiagnostics( + // (2,10): error CS1503: Argument 2: cannot convert from 'dynamic' to '__arglist' + // object.M(d); + Diagnostic(ErrorCode.ERR_BadArgType, "d").WithArguments("2", "dynamic", "__arglist").WithLocation(2, 10)); + } + + [Fact] + public void ArgList() + { + string source = """ +int i = 1; +object.M(__arglist(i)); + +static class Extensions +{ + extension(object) + { + public static void M(__arglist) { System.Console.Write("ran"); } + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void MethodInvocation_ReceiverWithTupleDifferences() + { + string source = """ +C<(int, int other)>.M(); + +static class Extensions +{ + extension(C<(int a, int b)>) + { + public static void M() { System.Console.Write("ran"); } + } +} + +class C { } +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + } + + [Fact] + public void PropertyAccess_RemoveStaticInstanceMismatches_InstanceReceiver() + { + var source = """ +System.Console.Write(42.P); + +static class E1 +{ + extension(int i) + { + public int P => 43; + } +} +static class E2 +{ + extension(int) + { + public static int P => throw null; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "43").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "42.P"); + Assert.Equal("System.Int32 E1.<>E__0.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void PropertyAccess_RemoveStaticInstanceMismatches_StaticReceiver() + { + var source = """ +System.Console.Write(int.P); + +static class E1 +{ + extension(int i) + { + public int P => throw null; + } +} +static class E2 +{ + extension(int) + { + public static int P => 42; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "int.P"); + Assert.Equal("System.Int32 E2.<>E__0.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + } + + [Fact] + public void PropertyAccess_RemoveStaticInstanceMismatches_ColorColor_01() + { + var source = """ +class Color +{ + static void M(Color Color) + { + _ = Color.P; + } +} + +static class E1 +{ + extension(Color c) + { + public int P => 0; + } +} +static class E2 +{ + extension(Color) + { + public static int P => 0; + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (5,13): error CS9286: 'Color' does not contain a definition for 'P' and no accessible extension member 'P' for receiver of type 'Color' could be found (are you missing a using directive or an assembly reference?) + // _ = Color.P; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "Color.P").WithArguments("Color", "P").WithLocation(5, 13)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "Color.P"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["System.Int32 E1.<>E__0.P { get; }", "System.Int32 E2.<>E__0.P { get; }"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + } + + [Fact] + public void PropertyAccess_RemoveStaticInstanceMismatches_ColorColor_02() + { + var source = """ +Color.M(new Color()); + +class Color +{ + public static void M(Color Color) + { + _ = Color.P; + } +} + +static class E1 +{ + extension(Color c) + { + public int P { get { System.Console.Write("ran"); return 0; } } + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "Color.P"); + Assert.Equal("System.Int32 E1.<>E__0.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal("Color Color", model.GetSymbolInfo(memberAccess.Expression).Symbol.ToTestDisplayString()); + Assert.Equal(SymbolKind.Parameter, model.GetSymbolInfo(memberAccess.Expression).Symbol.Kind); + } + + [Fact] + public void PropertyAccess_RemoveStaticInstanceMismatches_ColorColor_03() + { + var source = """ +Color.M(null); + +class Color +{ + public static void M(Color Color) + { + _ = Color.P; + } +} + +static class E1 +{ + extension(Color c) + { + public static int P { get { System.Console.Write("ran"); return 0; } } + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "Color.P"); + Assert.Equal("System.Int32 E1.<>E__0.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal("Color", model.GetSymbolInfo(memberAccess.Expression).Symbol.ToTestDisplayString()); + Assert.Equal(SymbolKind.NamedType, model.GetSymbolInfo(memberAccess.Expression).Symbol.Kind); + } + + [Fact] + public void RefOmittedComCall() + { + // For COM import type, omitting the ref is allowed + string source = @" +using System; +using System.Runtime.InteropServices; + +short x = 123; +C c = new C(); +c.M(x); +c.I(123); + +[ComImport, Guid(""1234C65D-1234-447A-B786-64682CBEF136"")] +class C { } + +static class E +{ + extension(C c) + { + public void M(ref short p) { } + public void M(sbyte p) { } + public void I(ref int p) { } + } +} +"; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void RefOmittedComCall_02() + { + string source = @" +using System; +using System.Runtime.InteropServices; + +C c = default; +c.M(); +c.M2(); + +[ComImport, Guid(""1234C65D-1234-447A-B786-64682CBEF136"")] +class C { } + +static class E +{ + extension(ref C c) + { + public void M() { } + } + public static void M2(this ref C c) { } +} +"; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : missing ERR_RefExtensionMustBeValueTypeOrConstrainedToOne on the extension parameter + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (7,3): error CS1061: 'C' does not contain a definition for 'M2' and no accessible extension method 'M2' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?) + // c.M2(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M2").WithArguments("C", "M2").WithLocation(7, 3), + // (18,24): error CS8337: The first parameter of a 'ref' extension method 'M2' must be a value type or a generic type constrained to struct. + // public static void M2(this ref C c) { } + Diagnostic(ErrorCode.ERR_RefExtensionMustBeValueTypeOrConstrainedToOne, "M2").WithArguments("M2").WithLocation(18, 24)); + } + + [Fact] + public void RefOmittedComCall_03() + { + string source = @" +using System; +using System.Runtime.InteropServices; + +C c = default; +c.M(); +c.M2(); + +[ComImport, Guid(""1234C65D-1234-447A-B786-64682CBEF136"")] +struct C { } + +static class E +{ + extension(ref C c) + { + public void M() { } + } + public static void M2(this ref C c) { } +} +"; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (9,2): error CS0592: Attribute 'ComImport' is not valid on this declaration type. It is only valid on 'class, interface' declarations. + // [ComImport, Guid("1234C65D-1234-447A-B786-64682CBEF136")] + Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "ComImport").WithArguments("ComImport", "class, interface").WithLocation(9, 2)); + } + + [Fact] + public void RefOmittedComCall_04() + { + // For COM import type, omitting the ref is allowed (even in static scenarios) + string source = @" +using System; +using System.Runtime.InteropServices; + +short x = 42; +short y = 43; +C.M(x.ToString(), y.ToString()); + +[ComImport, Guid(""1234C65D-1234-447A-B786-64682CBEF136"")] +class C { } + +static class E +{ + extension(C) + { + public static void M(ref string p, ref string p2) { } + } +} +"; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + var verifier = CompileAndVerify(comp); + verifier.VerifyIL("", """ +{ + // Code size 32 (0x20) + .maxstack 2 + .locals init (short V_0, //x + short V_1, //y + string V_2, + string V_3) + IL_0000: ldc.i4.s 42 + IL_0002: stloc.0 + IL_0003: ldc.i4.s 43 + IL_0005: stloc.1 + IL_0006: ldloca.s V_0 + IL_0008: call "string short.ToString()" + IL_000d: stloc.2 + IL_000e: ldloca.s V_2 + IL_0010: ldloca.s V_1 + IL_0012: call "string short.ToString()" + IL_0017: stloc.3 + IL_0018: ldloca.s V_3 + IL_001a: call "void E.M(ref string, ref string)" + IL_001f: ret +} +"""); + + source = """ +using System; +using System.Runtime.InteropServices; + +short x = 42; +C.M(x.ToString()); + +[ComImport, Guid("1234C65D-1234-447A-B786-64682CBEF136")] +class C +{ + public extern static void M(ref string p); +} +"""; + comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + verifier = CompileAndVerify(comp, verify: Verification.FailsPEVerify); + verifier.VerifyIL("", """ +{ + // Code size 19 (0x13) + .maxstack 1 + .locals init (short V_0, //x + string V_1) + IL_0000: ldc.i4.s 42 + IL_0002: stloc.0 + IL_0003: ldloca.s V_0 + IL_0005: call "string short.ToString()" + IL_000a: stloc.1 + IL_000b: ldloca.s V_1 + IL_000d: call "void C.M(ref string)" + IL_0012: ret +} +"""); + } + + [Fact] + public void RefOmittedComCall_05() + { + string source = @" +using System; +using System.Runtime.InteropServices; + +short x = 42; +C.M(x.ToString()); + +[ComImport, Guid(""1234C65D-1234-447A-B786-64682CBEF136"")] +class C { } + +static class E +{ + extension(C) + { + public static void M(string p) { } + } +} +"; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + var verifier = CompileAndVerify(comp); + verifier.VerifyIL("", """ +{ + // Code size 16 (0x10) + .maxstack 1 + .locals init (short V_0) //x + IL_0000: ldc.i4.s 42 + IL_0002: stloc.0 + IL_0003: ldloca.s V_0 + IL_0005: call "string short.ToString()" + IL_000a: call "void E.M(string)" + IL_000f: ret +} +"""); + } + + [Fact] + public void Nullability_Method_01() + { + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Nullability is undone + string source = """ +#nullable enable + +string? s = null; +s.M(); + +static class E +{ + extension(T t) + { + public void M() { System.Console.Write(t is null); } + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (4,1): warning CS8602: Dereference of a possibly null reference. + // s.M(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(4, 1)); + CompileAndVerify(comp, expectedOutput: "True"); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "s.M"); + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void Nullability_Method_02() + { + string source = """ +#nullable enable + +string s = ""; +s.M(null); + +static class E +{ + extension(T t) + { + public void M(T t2) { System.Console.Write(t2 is null); } + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + CompileAndVerify(comp, expectedOutput: "True"); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "s.M"); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Nullability is undone + Assert.Equal("void E.<>E__0.M(System.String t2)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + } + + [Fact] + public void PropertyAccess_RemoveWorseMembers_01() + { + string source = """ +string s = ""; +System.Console.Write(s.P); + +static class E +{ + extension(string s) + { + public int P => 42; + } + extension(object o) + { + public int P => throw null; + } +} +"""; + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "s.P"); + Assert.Equal("System.Int32 E.<>E__0.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + } + + [Fact] + public void PropertyAccess_RemoveWorseMembers_02() + { + string source = """ +System.Console.Write(string.P); + +static class E1 +{ + extension(string s) + { + public static int P => 42; + } +} +static class E2 +{ + extension(object o) + { + public static int P => throw null; + } +} +"""; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : confirm what betterness behavior we want for static properties + var comp = CreateCompilation(source); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "string.P"); + Assert.Equal("System.Int32 E1.<>E__0.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + } + + [Fact] + public void PropertyAccess_RemoveWorseMembers_03() + { + var src = """ +I i = null; +System.Console.Write(i.P); + +interface I { } + +static class E +{ + extension(I i) + { + public int P => 42; + } + extension(I i) + { + public int P => throw null; + } +} +"""; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : confirm what betterness behavior we want for properties + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "i.P"); + Assert.Equal("System.Int32 E.<>E__0.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + } + + [Fact] + public void PropertyAccess_RemoveWorseMembers_04() + { + var src = """ +I i = null; +System.Console.Write(i.P); + +interface I { } + +static class E +{ + extension(I i) + { + public int P => throw null; + } + extension(I i) + { + public int P => 42; + } +} +"""; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : confirm what betterness behavior we want for properties + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "i.P"); + Assert.Equal("System.Int32 E.<>E__1.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + } + + [Fact] + public void PropertyAccess_RemoveWorseMembers_05() + { + var src = """ +System.Console.Write(42.P); + +static class E1 +{ + extension(int i) + { + public int P => 42; + } +} +static class E2 +{ + extension(in int i) + { + public int P => throw null; + } +} +"""; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : confirm what betterness behavior we want for properties + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "42.P"); + Assert.Equal("System.Int32 E1.<>E__0.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + } + + [Fact] + public void PropertyAccess_RemoveWorseMembers_06() + { + var src = """ +System.Console.Write(int.P); + +static class E1 +{ + extension(int i) + { + public static int P => 42; + } +} + +static class E2 +{ + extension(in int i) + { + public static int P => throw null; + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "int.P"); + Assert.Equal("System.Int32 E1.<>E__0.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + } + + [Fact] + public void PropertyAccess_RemoveWorseMembers_07() + { + var src = """ +System.Console.Write(int.P); + +static class E1 +{ + extension(int i) + { + public static int P => 42; + } +} + +static class E2 +{ + extension(T t) + { + public static int P => throw null; + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "int.P"); + Assert.Equal("System.Int32 E1.<>E__0.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + } + + [Fact] + public void PropertyOrMethod_RemoveWorseMembers_01() + { + var src = """ +string s = null; +s.M(); + +static class E +{ + extension(string s) + { + public System.Action M => throw null; + } + extension(object o) + { + public string M() => throw null; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (2,1): error CS9286: 'string' does not contain a definition for 'M' and no accessible extension member 'M' for receiver of type 'string' could be found (are you missing a using directive or an assembly reference?) + // s.M(); + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "s.M").WithArguments("string", "M").WithLocation(2, 1)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "s.M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["System.Action E.<>E__0.M { get; }", "System.String E.<>E__1.M()"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + } + + [Fact] + public void PropertyOrMethod_RemoveWorseMembers_02() + { + var src = """ +string.M(); + +static class E +{ + extension(object) + { + public static System.Action M => throw null; + } + extension(string) + { + public static string M() => throw null; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,1): error CS9286: 'string' does not contain a definition for 'M' and no accessible extension member 'M' for receiver of type 'string' could be found (are you missing a using directive or an assembly reference?) + // string.M(); + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "string.M").WithArguments("string", "M").WithLocation(1, 1)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "string.M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["System.Action E.<>E__0.M { get; }", "System.String E.<>E__1.M()"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + } + + [Fact] + public void PropertyOrMethod_RemoveWorseMembers_03() + { + var src = """ +I i = null; +i.M(); + +interface I { } + +static class E +{ + extension(I i) + { + public System.Action M => throw null; + } + extension(I i) + { + public string M() => throw null; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (2,1): error CS9286: 'I' does not contain a definition for 'M' and no accessible extension member 'M' for receiver of type 'I' could be found (are you missing a using directive or an assembly reference?) + // i.M(); + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "i.M").WithArguments("I", "M").WithLocation(2, 1)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "i.M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["System.Action E.<>E__0.M { get; }", "System.String E.<>E__1.M()"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + } + + [Fact] + public void PropertyOrMethod_RemoveWorseMembers_04() + { + var src = """ +I i = null; +i.M(); + +interface I { } + +static class E1 +{ + extension(I i) + { + public System.Action M => throw null; + } +} + +static class E2 +{ + extension(I i) + { + public string M() => throw null; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (2,1): error CS9286: 'I' does not contain a definition for 'M' and no accessible extension member 'M' for receiver of type 'I' could be found (are you missing a using directive or an assembly reference?) + // i.M(); + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "i.M").WithArguments("I", "M").WithLocation(2, 1)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "i.M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["System.Action E1.<>E__0.M { get; }", "System.String E2.<>E__0.M()"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + Assert.Empty(model.GetMemberGroup(memberAccess)); + } + + [Fact] + public void Dynamic_01() + { + var src = """ +dynamic d = new object(); +object.M(d); +new object().M(d); + +static class E +{ + extension(U) + { + public static int M(T t) => throw null; + } + public static int M2(this U u, T t) => throw null; +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (2,1): error CS1929: 'object' does not contain a definition for 'M' and the best extension method overload 'E.extension(U).M(T)' requires a receiver of type 'U' + // object.M(d); + Diagnostic(ErrorCode.ERR_BadInstanceArgType, "object").WithArguments("object", "M", "E.extension(U).M(T)", "U").WithLocation(2, 1), + // (3,1): error CS1929: 'object' does not contain a definition for 'M' and the best extension method overload 'E.extension(U).M(T)' requires a receiver of type 'U' + // new object().M(d); + Diagnostic(ErrorCode.ERR_BadInstanceArgType, "new object()").WithArguments("object", "M", "E.extension(U).M(T)", "U").WithLocation(3, 1)); + } + + [Fact] + public void Dynamic_02() + { + var src = """ +dynamic d = new object(); +object.M(d); +new object().M2(d); + +static class E +{ + extension(object) + { + public static int M(T t) => throw null; + } + public static int M2(this object o, T t) => throw null; +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (2,1): error CS1973: 'object' has no applicable method named 'M' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax. + // object.M(d); + Diagnostic(ErrorCode.ERR_BadArgTypeDynamicExtension, "object.M(d)").WithArguments("object", "M").WithLocation(2, 1), + // (3,1): error CS1973: 'object' has no applicable method named 'M2' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax. + // new object().M2(d); + Diagnostic(ErrorCode.ERR_BadArgTypeDynamicExtension, "new object().M2(d)").WithArguments("object", "M2").WithLocation(3, 1)); + } + + [Fact] + public void Dynamic_03() + { + var src = """ +dynamic d = new object(); +object.M(d); +new object().M2(d); + +static class E +{ + extension(U) + { + public static int M(object o) => throw null; + } + public static int M2(this U u, object o) => throw null; +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (2,1): error CS1929: 'object' does not contain a definition for 'M' and the best extension method overload 'E.extension(U).M(object)' requires a receiver of type 'U' + // object.M(d); + Diagnostic(ErrorCode.ERR_BadInstanceArgType, "object").WithArguments("object", "M", "E.extension(U).M(object)", "U").WithLocation(2, 1), + // (3,1): error CS1973: 'object' has no applicable method named 'M2' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax. + // new object().M2(d); + Diagnostic(ErrorCode.ERR_BadArgTypeDynamicExtension, "new object().M2(d)").WithArguments("object", "M2").WithLocation(3, 1)); + } + + [Fact] + public void Dynamic_04() + { + var src = """ +int i = 42; +i.M(i); +i.M2(i); + +static class E +{ + extension(object o) + { + public void M(dynamic d) { System.Console.Write(d); } + } + + public static void M2(this object o, dynamic d) { } +} +"""; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("42"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); + } + + [Fact] + public void Dynamic_05() + { + var src = """ +try +{ + dynamic d = 42; + _ = d.P; +} +catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException e) +{ + System.Console.Write(e.Message); +} + +static class E +{ + extension(object o) + { + public int P => 0; + } +} +"""; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); + comp.VerifyEmitDiagnostics(); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("'int' does not contain a definition for 'P'"), verify: Verification.FailsPEVerify); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "d.P"); + var dynamicType = model.GetTypeInfo(memberAccess.Expression).Type; + Assert.True(dynamicType.IsDynamic()); + AssertEqualAndNoDuplicates(["System.Int32 E.<>E__0.P { get; }"], model.LookupSymbols(position: 0, dynamicType, name: "P", includeReducedExtensionMethods: true).ToTestDisplayStrings()); + AssertEqualAndNoDuplicates(["System.Int32 E.<>E__0.P { get; }"], model.LookupSymbols(position: 0, dynamicType, name: null, includeReducedExtensionMethods: true).ToTestDisplayStrings()); + } + + [Fact] + public void Dynamic_06() + { + var src = """ +try +{ + dynamic d = 42; + d.M(); +} +catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException e) +{ + System.Console.Write(e.Message); +} + +static class E +{ + extension(object o) + { + public void M() { } + } +} +"""; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); + comp.VerifyEmitDiagnostics(); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("'int' does not contain a definition for 'M'"), verify: Verification.FailsPEVerify); + } + + [Fact] + public void ResolveExtension_01() + { + var src = """ +using N; + +System.Console.Write(object.M()); + +static class E1 +{ + extension(string) // inapplicable + { + public static System.Action M => null; + } +} + +namespace N +{ + static class E2 + { + extension(object) + { + public static int M() => 42; + } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("42")).VerifyDiagnostics(); + } + + [Fact] + public void ResolveExtension_02() + { + var src = """ +using N; + +object.M(); + +static class E1 +{ + extension(string) // inapplicable + { + public static System.Action M => null; + } +} + +namespace N +{ + static class E2 + { + extension(object) + { + public static System.Action M => () => { System.Console.Write("ran"); }; + } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("ran")).VerifyDiagnostics(); + } + + [Fact] + public void ResolveExtension_03() + { + var src = """ +using N; + +new object().M(); + +static class E1 +{ + public static void M(this string s) { } // inapplicable +} + +namespace N +{ + static class E2 + { + extension(object o) + { + public System.Action M => () => { System.Console.Write("ran"); }; + } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("ran")).VerifyDiagnostics(); + } + + [Fact] + public void ResolveExtension_04() + { + var src = """ +using N; + +new object().M(); + +static class E1 +{ + public static void M(this string s) { } // inapplicable +} + +namespace N +{ + static class E2 + { + extension(object o) + { + public void M() { System.Console.Write("ran"); } + } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("ran")).VerifyDiagnostics(); + } + + [Fact] + public void ResolveExtension_05() + { + var src = """ +using N; + +new object().M(); + +static class E1 +{ + extension(string s) // inapplicable + { + public void M() { } + } +} + +namespace N +{ + static class E2 + { + extension(object o) + { + public System.Action M => () => { System.Console.Write("ran"); }; + } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("ran")).VerifyDiagnostics(); + } + + [Fact] + public void ResolveExtension_06() + { + var src = """ +using N; + +new object().M(); + +static class E1 +{ + extension(string s) // inapplicable + { + public void M() { } + } +} + +namespace N +{ + static class E2 + { + extension(object o) + { + public void M() { System.Console.Write("ran"); } + } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("ran")).VerifyDiagnostics(); + } + + [Fact] + public void PropertyAccess_ByValueReceiverForRefReadonlyParameter_01() + { + var src = """ +_ = 42.P; + +static class E +{ + extension(ref readonly int i) + { + public int P { get { System.Console.Write(i); return 0; } } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,5): warning CS9193: Argument 0 should be a variable because it is passed to a 'ref readonly' parameter + // _ = 42.P; + Diagnostic(ErrorCode.WRN_RefReadonlyNotVariable, "42").WithArguments("0").WithLocation(1, 5)); + + CompileAndVerify(comp, expectedOutput: "42"); + } + + [Fact] + public void PropertyAccess_ByValueReceiverForRefReadonlyParameter_02() + { + var src = """ +int i = 42; +_ = i.P; + +static class E +{ + extension(ref readonly int i) + { + public int P { get { System.Console.Write(i); return 0; } } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + } + + [Fact] + public void PropertyAccess_ByValueReceiverForRefReadonlyParameter_03() + { + var src = """ +var f = (ref readonly int i) => i.P; +int i = 42; +f(ref i); + +static class E +{ + extension(ref readonly int i) + { + public int P { get { System.Console.Write(i); return 0; } } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); + } + + [Fact] + public void PropertyAccess_AmbiguityWithNoArguments() + { + var src = """ +int x = new object().M; + +public static class E1 +{ + extension(object o) + { + public int M => 42; + } +} + +public static class E2 +{ + public static void M(this object o) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,9): error CS9286: 'object' does not contain a definition for 'M' and no accessible extension member 'M' for receiver of type 'object' could be found (are you missing a using directive or an assembly reference?) + // int x = new object().M; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "new object().M").WithArguments("object", "M").WithLocation(1, 9)); + } + + [Fact] + public void ConstAccess() + { + var src = """ +_ = int.Const; + +static class E +{ + extension(int) + { + public const int Const = 42; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,9): error CS0117: 'int' does not contain a definition for 'Const' + // _ = int.Const; + Diagnostic(ErrorCode.ERR_NoSuchMember, "Const").WithArguments("int", "Const").WithLocation(1, 9), + // (7,26): error CS9282: Extension declarations can include only methods or properties + // public const int Const = 42; + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "Const").WithLocation(7, 26)); + } + + [Fact] + public void ParamsReceiver_01() + { + // extension(params int[] i) + var ilSrc = """ +.class public auto ansi abstract sealed beforefieldinit E + extends System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + .class nested public auto ansi sealed beforefieldinit '<>E__0' + extends System.Object + { + // Methods + .method private hidebysig specialname static void '$' ( int32[] i ) cil managed + { + .param [1] + .custom instance void [mscorlib]System.ParamArrayAttribute::.ctor() = ( 01 00 00 00) + + IL_0000: ret + } + .method public hidebysig instance void M () cil managed + { + IL_0000: ldnull + IL_0001: throw + } + } + .method public hidebysig specialname static void 'M' ( int32[] i ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + .param [1] + .custom instance void [mscorlib]System.ParamArrayAttribute::.ctor() = ( 01 00 00 00) + + IL_0000: ldstr "ran" + IL_0005: call void [mscorlib]System.Console::Write(string) + IL_000a: ret + } +} +"""; + var src = """ +int[] i = null; +i.M(); +"""; + var comp = CreateCompilationWithIL(src, ilSrc); + comp.VerifyEmitDiagnostics(); + CompileAndVerify(comp, expectedOutput: "ran"); + + src = """ +int i = 0; +i.M(); +"""; + comp = CreateCompilationWithIL(src, ilSrc); + comp.VerifyEmitDiagnostics( + // (2,1): error CS1929: 'int' does not contain a definition for 'M' and the best extension method overload 'E.extension(params int[]).M()' requires a receiver of type 'params int[]' + // i.M(); + Diagnostic(ErrorCode.ERR_BadInstanceArgType, "i").WithArguments("int", "M", "E.extension(params int[]).M()", "params int[]").WithLocation(2, 1)); + + src = """ +int i = 0; +i.M(2); +"""; + comp = CreateCompilationWithIL(src, ilSrc); + comp.VerifyEmitDiagnostics( + // (2,3): error CS1501: No overload for method 'M' takes 1 arguments + // i.M(2); + Diagnostic(ErrorCode.ERR_BadArgCount, "M").WithArguments("M", "1").WithLocation(2, 3)); + } + + [Fact] + public void ParamsReceiver_02() + { + // extension(params int[] i) + var ilSrc = """ +.class public auto ansi abstract sealed beforefieldinit E + extends System.Object +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + .class nested public auto ansi sealed beforefieldinit '<>E__0' + extends System.Object + { + .method private hidebysig specialname static void '$' ( int32[] i ) cil managed + { + .param [1] + .custom instance void [mscorlib]System.ParamArrayAttribute::.ctor() = ( 01 00 00 00) + + IL_0000: ret + } + .method public hidebysig specialname instance int32 get_P () cil managed + { + IL_0000: ldnull + IL_0001: throw + } + .property instance int32 P() + { + .get instance int32 E/'<>E__0'::get_P() + } + } + .method public hidebysig specialname static int32 'get_P' ( int32[] i ) cil managed + { + .param [1] + .custom instance void [mscorlib]System.ParamArrayAttribute::.ctor() = ( 01 00 00 00) + + IL_0000: ldstr "ran" + IL_0005: call void [mscorlib]System.Console::Write(string) + IL_000a: ldc.i4.0 + IL_000b: ret + } +} +"""; + var src = """ +int[] i = null; +_ = i.P; +"""; + var comp = CreateCompilationWithIL(src, ilSrc); + comp.VerifyEmitDiagnostics(); + CompileAndVerify(comp, expectedOutput: "ran"); + + src = """ +int i = 0; +_ = i.P; +"""; + comp = CreateCompilationWithIL(src, ilSrc); + comp.VerifyEmitDiagnostics( + // (2,5): error CS9286: 'int' does not contain a definition for 'P' and no accessible extension member 'P' for receiver of type 'int' could be found (are you missing a using directive or an assembly reference?) + // _ = i.P; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "i.P").WithArguments("int", "P").WithLocation(2, 5)); + + src = """ +int i = 0; +_ = i.P(1); +"""; + comp = CreateCompilationWithIL(src, ilSrc); + comp.VerifyEmitDiagnostics( + // (2,7): error CS1061: 'int' does not contain a definition for 'P' and no accessible extension method 'P' accepting a first argument of type 'int' could be found (are you missing a using directive or an assembly reference?) + // _ = i.P(1); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "P").WithArguments("int", "P").WithLocation(2, 7)); + } + + [Fact] + public void ExplicitTypeArguments_01() + { + var src = """ +string s = "ran"; +s.M(); + +static class E +{ + extension(T t) + { + public void M() { System.Console.Write(t); } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var invocation = GetSyntax(tree, "s.M()"); + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetMemberGroup(invocation).ToTestDisplayStrings()); + + var memberAccess = GetSyntax(tree, "s.M"); + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void ExplicitTypeArguments_02() + { + var src = """ +42.M(); + +static class E +{ + extension(T t) where T : struct + { + public void M() { System.Console.Write(t); } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,4): error CS0453: The type 'object' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'E.extension(T)' + // 42.M(); + Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "M").WithArguments("E.extension(T)", "T", "object").WithLocation(1, 4)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var invocation = GetSyntax(tree, "42.M()"); + Assert.Null(model.GetSymbolInfo(invocation).Symbol); + Assert.Equal([], model.GetMemberGroup(invocation).ToTestDisplayStrings()); + + var memberAccess = GetSyntax(tree, "42.M"); + Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void ExplicitTypeArguments_03() + { + var src = """ +string s = "ran"; +_ = s.P; + +static class E +{ + extension(T t) + { + public int P => 0; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (2,7): error CS1061: 'string' does not contain a definition for 'P' and no accessible extension method 'P' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?) + // _ = s.P; + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "P").WithArguments("string", "P").WithLocation(2, 7)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "s.P"); + Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void ExplicitTypeArguments_04() + { + var src = """ +string s = "ran"; +s.M(); + +static class E +{ + extension(T t) + { + public void M() => throw null; + } + extension(string s) + { + public void M() { System.Console.Write(s); } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "s.M"); + Assert.Equal(["void E.<>E__0.M()", "void E.<>E__1.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void ExplicitTypeArguments_05() + { + var src = """ +string s = null; +s.M(); + +static class E +{ + extension(T t) + { + public void M() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (2,3): error CS1061: 'string' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?) + // s.M(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("string", "M").WithLocation(2, 3)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "s.M"); + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void ExplicitTypeArguments_06() + { + var src = """ +C.M(); + +class C { } +static class E +{ + extension(C t) + { + public static void M() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,19): error CS0117: 'C' does not contain a definition for 'M' + // C.M(); + Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("C", "M").WithLocation(1, 19)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "C.M"); + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void ExplicitTypeArguments_07() + { + var src = """ +string.M(42); + +static class E +{ + extension(T t) + { + public static void M(U u) { System.Console.Write("ran"); } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var invocation = GetSyntax(tree, "string.M(42)"); + Assert.Equal("void E.<>E__0.M(System.Int64 u)", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); + + var memberAccess = GetSyntax(tree, "string.M"); + Assert.Equal(["void E.<>E__0.M(System.Int64 u)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void ExplicitTypeArguments_08() + { + var src = """ +object.M(42); + +static class E +{ + extension(T t) + { + public static void M(U u) { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,1): error CS1929: 'object' does not contain a definition for 'M' and the best extension method overload 'E.extension(string).M(long)' requires a receiver of type 'string' + // object.M(42); + Diagnostic(ErrorCode.ERR_BadInstanceArgType, "object").WithArguments("object", "M", "E.extension(string).M(long)", "string").WithLocation(1, 1)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void ExplicitTypeArguments_09() + { + var src = """ +42.M(42); +42.M2(42); + +static class E +{ + extension(int i) + { + public void M(T t) where T : struct { } + } + + public static void M2(this int i, T t) where T : struct { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,4): error CS0453: The type 'object' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'E.extension(int).M(T)' + // 42.M(42); + Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "M").WithArguments("E.extension(int).M(T)", "T", "object").WithLocation(1, 4), + // (2,4): error CS0453: The type 'object' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'E.M2(int, T)' + // 42.M2(42); + Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "M2").WithArguments("E.M2(int, T)", "T", "object").WithLocation(2, 4)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "42.M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + + memberAccess = GetSyntax(tree, "42.M2"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void GetDeclaredSymbol_01() + { + var src = """ +static class E +{ + extension(int i) + { + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var extensionParameter = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(extensionParameter); + Assert.Equal(SymbolKind.Parameter, symbol.Kind); + Assert.Equal("System.Int32 i", symbol.ToTestDisplayString()); + } + + readonly string[] _objectMembers = [ + "System.String System.Object.ToString()", + "System.Boolean System.Object.Equals(System.Object obj)", + "System.Boolean System.Object.Equals(System.Object objA, System.Object objB)", + "System.Int32 System.Object.GetHashCode()", + "System.Type System.Object.GetType()", + "System.Boolean System.Object.ReferenceEquals(System.Object objA, System.Object objB)"]; + + [Fact] + public void LookupSymbols_Simple() + { + var src = """ +object.M(); +_ = object.Property; + +public static class E +{ + extension(object) + { + public static void M() => throw null; + public static int Property => throw null; + } +} +"""; + + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var invocation = GetSyntax(tree, "object.M()"); + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); + + var property = GetSyntax(tree, "object.Property"); + Assert.Equal("System.Int32 E.<>E__0.Property { get; }", model.GetSymbolInfo(property).Symbol.ToTestDisplayString()); + + var e = ((Compilation)comp).GlobalNamespace.GetTypeMember("E"); + AssertEqualAndNoDuplicates(["void E.M()"], model.LookupSymbols(position: 0, e, name: "M").ToTestDisplayStrings()); + AssertEqualAndNoDuplicates(["void E.M()", "void E.<>E__0.M()"], model.LookupSymbols(position: 0, e, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings()); + + AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, e, name: "Property").ToTestDisplayStrings()); + AssertEqualAndNoDuplicates(["System.Int32 E.<>E__0.Property { get; }"], model.LookupSymbols(position: 0, e, name: "Property", includeReducedExtensionMethods: true).ToTestDisplayStrings()); + + AssertEqualAndNoDuplicates(["System.Int32 E.get_Property()"], model.LookupSymbols(position: 0, e, name: "get_Property").ToTestDisplayStrings()); + + AssertEqualAndNoDuplicates(["System.Int32 E.get_Property()"], + model.LookupSymbols(position: 0, e, name: "get_Property", includeReducedExtensionMethods: true).ToTestDisplayStrings()); + + var o = ((Compilation)comp).GetSpecialType(SpecialType.System_Object); + AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, o, name: "M").ToTestDisplayStrings()); + AssertEqualAndNoDuplicates(["void E.<>E__0.M()"], model.LookupSymbols(position: 0, o, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings()); + + AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, o, name: "Property").ToTestDisplayStrings()); + AssertEqualAndNoDuplicates(["System.Int32 E.<>E__0.Property { get; }"], model.LookupSymbols(position: 0, o, name: "Property", includeReducedExtensionMethods: true).ToTestDisplayStrings()); + + AssertEqualAndNoDuplicates(["void E.<>E__0.M()", "System.Int32 E.<>E__0.Property { get; }", .. _objectMembers], + model.LookupSymbols(position: 0, o, name: null, includeReducedExtensionMethods: true).ToTestDisplayStrings()); + + Assert.Equal([ + "System.Boolean System.Object.Equals(System.Object objA, System.Object objB)", + "System.Boolean System.Object.ReferenceEquals(System.Object objA, System.Object objB)"], + model.LookupStaticMembers(position: 0, o, name: null).ToTestDisplayStrings()); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : should we include extension static members? + + Assert.Empty(model.LookupNamespacesAndTypes(position: 0, o, name: null)); + } + + [Fact] + public void LookupSymbols_Inapplicable() + { + var src = """ +object.M(); +_ = object.Property; + +public static class E +{ + extension(string) + { + public static void M() => throw null; + public static int Property => throw null; + } +} +"""; + + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,1): error CS1929: 'object' does not contain a definition for 'M' and the best extension method overload 'E.extension(string).M()' requires a receiver of type 'string' + // object.M(); + Diagnostic(ErrorCode.ERR_BadInstanceArgType, "object").WithArguments("object", "M", "E.extension(string).M()", "string").WithLocation(1, 1), + // (2,5): error CS9286: 'object' does not contain a definition for 'Property' and no accessible extension member 'Property' for receiver of type 'object' could be found (are you missing a using directive or an assembly reference?) + // _ = object.Property; + Diagnostic(ErrorCode.ERR_ExtensionResolutionFailed, "object.Property").WithArguments("object", "Property").WithLocation(2, 5)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var o = ((Compilation)comp).GetSpecialType(SpecialType.System_Object); + AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, o, name: "M").ToTestDisplayStrings()); + AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, o, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings()); + + AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, o, name: "Property").ToTestDisplayStrings()); + AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, o, name: "Property", includeReducedExtensionMethods: true).ToTestDisplayStrings()); + + AssertEqualAndNoDuplicates(_objectMembers, model.LookupSymbols(position: 0, o, name: null, includeReducedExtensionMethods: true).ToTestDisplayStrings()); + } + + [Fact] + public void LookupSymbols_Substituted_01() + { + var src = """ +string.M(); +_ = string.Property; + +public static class E +{ + extension(T) + { + public static void M() => throw null; + public static int Property => throw null; + } +} +"""; + + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var o = ((Compilation)comp).GetSpecialType(SpecialType.System_Object); + AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, o, name: "M").ToTestDisplayStrings()); + AssertEqualAndNoDuplicates(["void E.<>E__0.M()"], model.LookupSymbols(position: 0, o, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings()); + + AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, o, name: "Property").ToTestDisplayStrings()); + AssertEqualAndNoDuplicates(["System.Int32 E.<>E__0.Property { get; }"], model.LookupSymbols(position: 0, o, name: "Property", includeReducedExtensionMethods: true).ToTestDisplayStrings()); + + AssertEqualAndNoDuplicates(["void E.<>E__0.M()", "System.Int32 E.<>E__0.Property { get; }", .. _objectMembers], + model.LookupSymbols(position: 0, o, name: null, includeReducedExtensionMethods: true).ToTestDisplayStrings()); + + var s = ((Compilation)comp).GetSpecialType(SpecialType.System_String); + AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, s, name: "M").ToTestDisplayStrings()); + AssertEqualAndNoDuplicates(["void E.<>E__0.M()"], model.LookupSymbols(position: 0, s, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings()); + + AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, s, name: "Property").ToTestDisplayStrings()); + AssertEqualAndNoDuplicates(["System.Int32 E.<>E__0.Property { get; }"], model.LookupSymbols(position: 0, s, name: "Property", includeReducedExtensionMethods: true).ToTestDisplayStrings()); + } + + [Fact] + public void LookupSymbols_Substituted_02() + { + var src = """ +string.M(42); + +public static class E +{ + extension(T) + { + public static void M(U u) => throw null; + } +} +"""; + + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var s = ((Compilation)comp).GetSpecialType(SpecialType.System_String); + AssertEqualAndNoDuplicates(["void E.<>E__0.M(U u)"], model.LookupSymbols(position: 0, s, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings()); + } + + [Fact] + public void LookupSymbols_StaticAndInstance() + { + var src = """ +public static class E1 +{ + extension(object) + { + public static void M() => throw null; + public static int Property => throw null; + } +} +public static class E2 +{ + extension(object) + { + public void M() => throw null; + public int Property => throw null; + } +} +"""; + + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var o = ((Compilation)comp).GetSpecialType(SpecialType.System_Object); + AssertEqualAndNoDuplicates(["void E1.<>E__0.M()", "void E2.<>E__0.M()"], + model.LookupSymbols(position: 0, o, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings()); + + AssertEqualAndNoDuplicates(["System.Int32 E1.<>E__0.Property { get; }", "System.Int32 E2.<>E__0.Property { get; }"], + model.LookupSymbols(position: 0, o, name: "Property", includeReducedExtensionMethods: true).ToTestDisplayStrings()); + + AssertEqualAndNoDuplicates([ + "void E1.<>E__0.M()", + "System.Int32 E1.<>E__0.Property { get; }", + "void E2.<>E__0.M()", + "System.Int32 E2.<>E__0.Property { get; }", + .. _objectMembers], model.LookupSymbols(position: 0, o, name: null, includeReducedExtensionMethods: true).ToTestDisplayStrings()); + } + + [Fact] + public void LookupSymbols_MethodAndProperty() + { + var src = """ +public static class E1 +{ + extension(object) + { + public static void MP() => throw null; + } +} +public static class E2 +{ + extension(object) + { + public int MP => throw null; + } +} +"""; + + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var o = ((Compilation)comp).GetSpecialType(SpecialType.System_Object); + AssertEqualAndNoDuplicates(["void E1.<>E__0.MP()", "System.Int32 E2.<>E__0.MP { get; }"], + model.LookupSymbols(position: 0, o, name: "MP", includeReducedExtensionMethods: true).ToTestDisplayStrings()); + + AssertEqualAndNoDuplicates(["void E1.<>E__0.MP()", "System.Int32 E2.<>E__0.MP { get; }", .. _objectMembers], + model.LookupSymbols(position: 0, o, name: null, includeReducedExtensionMethods: true).ToTestDisplayStrings()); + } + + [Fact] + public void LookupSymbols_ClassicAndNew() + { + var src = """ + +public static class E +{ + extension(object) + { + public static void M() => throw null; + public void M(string s) => throw null; + } + + public static void M(this object o, int i) { } +} +"""; + + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var o = ((Compilation)comp).GetSpecialType(SpecialType.System_Object); + AssertEqualAndNoDuplicates(["void E.<>E__0.M()", "void E.<>E__0.M(System.String s)", "void System.Object.M(System.Int32 i)"], + model.LookupSymbols(position: 0, o, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings()); + + AssertEqualAndNoDuplicates(["void E.<>E__0.M()", "void E.<>E__0.M(System.String s)", "void System.Object.M(System.Int32 i)", .. _objectMembers], + model.LookupSymbols(position: 0, o, name: null, includeReducedExtensionMethods: true).ToTestDisplayStrings()); + } + + [Fact] + public void LookupSymbols_NestedType() + { + var src = """ + +public static class E +{ + extension(object) + { + static class Nested { } + } +} +"""; + + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (6,22): error CS9282: Extension declarations can include only methods or properties + // static class Nested { } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "Nested").WithLocation(6, 22)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var o = ((Compilation)comp).GetSpecialType(SpecialType.System_Object); + AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, o, name: "Nested", includeReducedExtensionMethods: true).ToTestDisplayStrings()); + AssertEqualAndNoDuplicates([.. _objectMembers], model.LookupSymbols(position: 0, o, name: null, includeReducedExtensionMethods: true).ToTestDisplayStrings()); + + Assert.Empty(model.LookupNamespacesAndTypes(position: 0, o, name: null)); + } + + [Fact] + public void LookupSymbols_ExtensionParameter() + { + var src = """ +public static class E +{ + extension(object o) + { + } +} +"""; + + var comp = CreateCompilation(src); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + int position = extension.OpenBraceToken.EndPosition; + AssertEqualAndNoDuplicates(["System.Object o"], model.LookupSymbols(position, null, name: "o").ToTestDisplayStrings()); + AssertEx.Equal("System.Object o", model.LookupSymbols(position, null, name: null).OfType().Single().ToTestDisplayString()); + Assert.Empty(model.LookupNamespacesAndTypes(position, null, name: "o")); + + position = extension.OpenBraceToken.Position; + Assert.Empty(model.LookupSymbols(position, null, name: "o")); + Assert.Empty(model.LookupSymbols(position, null, name: null).OfType()); + } + + [Fact] + public void GetMemberGroup_01() + { + var src = """ +object.M(); +new object().M2(); + +static class E +{ + extension(object) + { + public static void M() where U : class { } + } + + public static void M2(this object o) where U : class { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,8): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'U' in the generic type or method 'E.extension(object).M()' + // object.M(); + Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "M").WithArguments("E.extension(object).M()", "U", "int").WithLocation(1, 8), + // (2,14): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'U' in the generic type or method 'E.M2(object)' + // new object().M2(); + Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "M2").WithArguments("E.M2(object)", "U", "int").WithLocation(2, 14)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var memberAccess1 = GetSyntax(tree, "object.M"); + Assert.Equal([], model.GetMemberGroup(memberAccess1).ToTestDisplayStrings()); + + var memberAccess2 = GetSyntax(tree, "new object().M2"); + Assert.Equal([], model.GetMemberGroup(memberAccess2).ToTestDisplayStrings()); + } + + [Fact] + public void GetMemberGroup_02() + { + var src = """ +object.M(42); +new object().M2(42); + +static class E +{ + extension(object) + { + public static void M(U u) where U : class { } + } + + public static void M2(this object o, U u) where U : class { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,8): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'U' in the generic type or method 'E.extension(object).M(U)' + // object.M(42); + Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "M").WithArguments("E.extension(object).M(U)", "U", "int").WithLocation(1, 8), + // (2,14): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'U' in the generic type or method 'E.M2(object, U)' + // new object().M2(42); + Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "M2").WithArguments("E.M2(object, U)", "U", "int").WithLocation(2, 14)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var memberAccess1 = GetSyntax(tree, "object.M"); + Assert.Equal(["void E.<>E__0.M(U u)"], model.GetMemberGroup(memberAccess1).ToTestDisplayStrings()); + + var memberAccess2 = GetSyntax(tree, "new object().M2"); + Assert.Equal(["void System.Object.M2(U u)"], model.GetMemberGroup(memberAccess2).ToTestDisplayStrings()); + } + + [Fact] + public void GetMemberGroup_03() + { + var src = """ +int.M(); +42.M2(); + +static class E +{ + extension(T) where T : class + { + public static void M() { } + } + + public static void M2(this T t) where T : class { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,5): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T' in the generic type or method 'E.extension(T)' + // int.M(); + Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "M").WithArguments("E.extension(T)", "T", "int").WithLocation(1, 5), + // (2,4): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T' in the generic type or method 'E.M2(T)' + // 42.M2(); + Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "M2").WithArguments("E.M2(T)", "T", "int").WithLocation(2, 4)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var memberAccess1 = GetSyntax(tree, "int.M"); + Assert.Equal([], model.GetMemberGroup(memberAccess1).ToTestDisplayStrings()); + + var memberAccess2 = GetSyntax(tree, "42.M2"); + Assert.Equal([], model.GetMemberGroup(memberAccess2).ToTestDisplayStrings()); + } + + [Fact] + public void GetMemberGroup_04() + { + var src = """ +int.M(); +42.M2(); + +static class E +{ + extension(T) where T : class + { + public static void M() { } + } + + public static void M2(this T t) where T : class { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,5): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T' in the generic type or method 'E.extension(T)' + // int.M(); + Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "M").WithArguments("E.extension(T)", "T", "int").WithLocation(1, 5), + // (2,4): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T' in the generic type or method 'E.M2(T)' + // 42.M2(); + Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "M2").WithArguments("E.M2(T)", "T", "int").WithLocation(2, 4)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var memberAccess1 = GetSyntax(tree, "int.M"); + Assert.Equal([], model.GetMemberGroup(memberAccess1).ToTestDisplayStrings()); + + var memberAccess2 = GetSyntax(tree, "42.M2"); + Assert.Equal([], model.GetMemberGroup(memberAccess2).ToTestDisplayStrings()); + } + + [Fact] + public void GetMemberGroup_05() + { + var src = """ +object.M(); + +static class E +{ + extension(object) + { + public static void M() { } + public static void M(int i) { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Equal(["void E.<>E__0.M()", "void E.<>E__0.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void GetMemberGroup_06() + { + var src = """ +_ = object.P; + +static class E +{ + extension(object) + { + public static int P => 0; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var memberAccess = GetSyntax(tree, "object.P"); + Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : handle GetMemberGroup on a property access + } + + [Fact] + public void GetMemberGroup_07() + { + var src = """ +object.M(); + +static class E1 +{ + extension(object) + { + public static int M => 0; + } +} +static class E2 +{ + extension(object) + { + public static void M() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Equal(["System.Int32 E1.<>E__0.M { get; }", "void E2.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void GetMemberGroup_08() + { + var src = """ +string.M(); + +static class E1 +{ + extension(T) + { + public static int M => 0; + } +} +static class E2 +{ + extension(T) + { + public static void M() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "string.M"); + Assert.Equal("void E2.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["System.Int32 E1.<>E__0.M { get; }", "void E2.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + + var invocation = GetSyntax(tree, "string.M()"); + Assert.Equal("void E2.<>E__0.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); + } + + [Fact] + public void GetMemberGroup_09() + { + var src = """ +string.M(); + +static class E1 +{ + extension(T) + { + public static void M() { } + } +} +static class E2 +{ + extension(T) + { + public static void M() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,8): error CS0121: The call is ambiguous between the following methods or properties: 'E1.extension(T).M()' and 'E2.extension(T).M()' + // string.M(); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("E1.extension(T).M()", "E2.extension(T).M()").WithLocation(1, 8)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "string.M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["void E1.<>E__0.M()", "void E2.<>E__0.M()"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(["void E1.<>E__0.M()", "void E2.<>E__0.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void GetMemberGroup_10() + { + var src = """ +System.Action a = new System.Action(object.M); + +static class E +{ + extension(object) + { + public static void M() { } + public static void M(int i) { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M()", "void E.<>E__0.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void GetMemberGroup_11() + { + var src = """ +System.Action a = new System.Action(object.M); + +static class E +{ + extension(T) + { + public static void M() { } + public static void M(int i) { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(["void E.<>E__0.M()", "void E.<>E__0.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void GetMemberGroup_12() + { + var src = """ +System.Action a = (System.Action)object.M; + +static class E +{ + extension(T) + { + public static void M() { } + public static void M(int i) { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.M"); + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(["void E.<>E__0.M()", "void E.<>E__0.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + + var cast = GetSyntax(tree, "(System.Action)object.M"); + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(cast).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetSymbolInfo(cast).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal([], model.GetMemberGroup(cast).ToTestDisplayStrings()); + } + + [Fact] + public void ToBadExpression_01() + { + var source = """ +class A +{ + void F() { } +} + +class C +{ + static void M(A a) + { + a.F(); + M(a.F); + } + static void M(System.Action a) { } +} + +static class E1 +{ + static void F(this T t) { } +} + +static class E2 +{ + extension(T) + { + static void F() { } + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (10,11): error CS0122: 'A.F()' is inaccessible due to its protection level + // a.F(); + Diagnostic(ErrorCode.ERR_BadAccess, "F").WithArguments("A.F()").WithLocation(10, 11), + // (11,13): error CS0122: 'A.F()' is inaccessible due to its protection level + // M(a.F); + Diagnostic(ErrorCode.ERR_BadAccess, "F").WithArguments("A.F()").WithLocation(11, 13)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntaxes(tree, "a.F").ToArray(); + Assert.Null(model.GetSymbolInfo(memberAccess[0]).Symbol); + Assert.Equal(["void A.F()"], model.GetSymbolInfo(memberAccess[0]).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(["void A.F()", "void E2.<>E__0.F()", "void A.F()"], model.GetMemberGroup(memberAccess[0]).ToTestDisplayStrings()); + + Assert.Null(model.GetSymbolInfo(memberAccess[1]).Symbol); + Assert.Equal(["void A.F()", "void E2.<>E__0.F()", "void A.F()"], model.GetSymbolInfo(memberAccess[1]).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal(["void A.F()", "void E2.<>E__0.F()", "void A.F()"], model.GetMemberGroup(memberAccess[1]).ToTestDisplayStrings()); + } + + [Fact] + public void PropertyAccess_NotAmbiguousWithInapplicableMethod() + { + var src = """ +int i = object.P; +System.Console.Write(i); + +static class E1 +{ + extension(T) where T : struct + { + public static void P() { } + } +} + +static class E2 +{ + extension(T) where T : class + { + public static int P => 42; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "object.P"); + Assert.Equal("System.Int32 E2.<>E__0.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); + Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); + Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); // Tracked by https://github.com/dotnet/roslyn/issues/76130 : handle GetMemberGroup on a property access + } + + [Fact] + public void GetSymbolInfo_GenericMethodInGenericType_01() + { + var src = """ +class C +{ + public static void M(T2 x) { } + public static void M(int x) { } +} + +class D +{ + public void Test() + { + C.M(1); + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var genericName = GetSyntax(tree, "M"); + Assert.Equal("void C.M(System.Int32 x)", model.GetSymbolInfo(genericName).Symbol.ToTestDisplayString()); + Assert.Equal(["void C.M(System.Int32 x)"], model.GetMemberGroup(genericName).ToTestDisplayStrings()); + } + + [Fact] + public void GetSymbolInfo_GenericMethodInGenericType_02() + { + var src = """ +class C +{ + public static void M(T2 x) where T2 : class { } +} + +class D +{ + public void Test() + { + C.M(1); + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (10,16): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T2' in the generic type or method 'C.M(T2)' + // C.M(1); + Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "M").WithArguments("C.M(T2)", "T2", "int").WithLocation(10, 16)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var genericName = GetSyntax(tree, "M"); + Assert.Null(model.GetSymbolInfo(genericName).Symbol); + Assert.Equal([], model.GetMemberGroup(genericName).ToTestDisplayStrings()); + } + + [Fact] + public void GetSymbolInfo_GenericMethodInGenericType_03() + { + var src = """ +class C +{ + public static void M(T2 x) where T2 : class { } +} + +class D +{ + public void Test() + { + C.M(1); + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (10,16): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T2' in the generic type or method 'C.M(T2)' + // C.M(1); + Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "M").WithArguments("C.M(T2)", "T2", "int").WithLocation(10, 16)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var memberAccess = GetSyntax(tree, "C.M"); + Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); + Assert.Equal(["void C.M(T2 x)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + } + + [Fact] + public void GetSymbolInfo_04() + { + var src = """ +class C +{ + private static void M() + { + M(); + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var genericName = GetSyntax(tree, "M()").Expression; + Assert.Equal("void C.M()", model.GetSymbolInfo(genericName).Symbol.ToTestDisplayString()); + Assert.Equal(["void C.M()"], model.GetMemberGroup(genericName).ToTestDisplayStrings()); + } + + [Fact] + public void GetSymbolInfo_05() + { + var src = """ +public static class E +{ + extension(T t) + { + static void M() + { + T.M(); + T.M(); + E.M(); + } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (7,13): error CS0704: Cannot do non-virtual member lookup in 'T' because it is a type parameter + // T.M(); + Diagnostic(ErrorCode.ERR_LookupInTypeVariable, "T").WithArguments("T").WithLocation(7, 13), + // (8,13): error CS0704: Cannot do non-virtual member lookup in 'T' because it is a type parameter + // T.M(); + Diagnostic(ErrorCode.ERR_LookupInTypeVariable, "T").WithArguments("T").WithLocation(8, 13)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var expr = GetSyntax(tree, "T.M()").Expression; + Assert.Null(model.GetSymbolInfo(expr).Symbol); + Assert.Equal([], model.GetMemberGroup(expr).ToTestDisplayStrings()); + + expr = GetSyntax(tree, "T.M()").Expression; + Assert.Null(model.GetSymbolInfo(expr).Symbol); + Assert.Equal([], model.GetMemberGroup(expr).ToTestDisplayStrings()); + + expr = GetSyntax(tree, "E.M()").Expression; + Assert.Equal("void E.M()", model.GetSymbolInfo(expr).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.M()"], model.GetMemberGroup(expr).ToTestDisplayStrings()); + } + + [Fact] + public void GetSymbolInfo_06() + { + var src = """ +public static class E +{ + extension(T t) + { + void M() + { + t.M(); + t.M(); + } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var expr = GetSyntax(tree, "t.M()").Expression; + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(expr).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(expr).ToTestDisplayStrings()); + + expr = GetSyntax(tree, "t.M()").Expression; + Assert.Equal("void E.<>E__0.M()", model.GetSymbolInfo(expr).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M()"], model.GetMemberGroup(expr).ToTestDisplayStrings()); + } + + [Fact] + public void GetSymbolInfo_07() + { + var src = """ +public static class E +{ + extension(T t) + { + void M(U u) + { + t.M(u); + t.M(u); + + t.M(42); + 42.M(u); + } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var extensionParameterSyntax = tree.GetRoot().DescendantNodes().OfType().First(); + IParameterSymbol extensionParameter = model.GetDeclaredSymbol(extensionParameterSyntax); + Assert.Equal("T t", extensionParameter.ToTestDisplayString()); + var t = extensionParameter.Type; + + var expr = GetSyntax(tree, "t.M(u)").Expression; + Assert.Equal("void E.<>E__0.M(U u)", model.GetSymbolInfo(expr).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M(U u)"], model.GetMemberGroup(expr).ToTestDisplayStrings()); + + AssertEqualAndNoDuplicates(["void E.<>E__0.M(U u)"], model.LookupSymbols(position: expr.SpanStart, t, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings()); + + expr = GetSyntax(tree, "t.M(u)").Expression; + Assert.Equal("void E.<>E__0.M(U u)", model.GetSymbolInfo(expr).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M(U u)"], model.GetMemberGroup(expr).ToTestDisplayStrings()); + + expr = GetSyntax(tree, "t.M(42)").Expression; + Assert.Equal("void E.<>E__0.M(System.Int32 u)", model.GetSymbolInfo(expr).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M(U u)"], model.GetMemberGroup(expr).ToTestDisplayStrings()); + + expr = GetSyntax(tree, "42.M(u)").Expression; + Assert.Equal("void E.<>E__0.M(U u)", model.GetSymbolInfo(expr).Symbol.ToTestDisplayString()); + Assert.Equal(["void E.<>E__0.M(U u)"], model.GetMemberGroup(expr).ToTestDisplayStrings()); + } + + [Fact] + public void GetSymbolInfo_08() + { + var src = """ +public static class E +{ + public static void M(this T t) + { + t.M(); + t.M(); + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var extensionParameterSyntax = tree.GetRoot().DescendantNodes().OfType().First(); + IParameterSymbol extensionParameter = model.GetDeclaredSymbol(extensionParameterSyntax); + Assert.Equal("T t", extensionParameter.ToTestDisplayString()); + var t = extensionParameter.Type; + + var expr = GetSyntax(tree, "t.M()").Expression; + Assert.Equal("void T.M()", model.GetSymbolInfo(expr).Symbol.ToTestDisplayString()); + Assert.Equal(["void T.M()"], model.GetMemberGroup(expr).ToTestDisplayStrings()); + + AssertEqualAndNoDuplicates(["void T.M()"], model.LookupSymbols(position: expr.SpanStart, t, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings()); + + expr = GetSyntax(tree, "t.M()").Expression; + Assert.Equal("void T.M()", model.GetSymbolInfo(expr).Symbol.ToTestDisplayString()); + Assert.Equal(["void T.M()"], model.GetMemberGroup(expr).ToTestDisplayStrings()); + } + + [Fact] + public void LangVer_01() + { + var libSrc = """ +public static class E +{ + extension(object) + { + public void M() { } + public static void M2() { } + public static int P => 0; + } +} + +"""; + var libComp = CreateCompilation(libSrc, parseOptions: TestOptions.RegularNext); + libComp.VerifyEmitDiagnostics(); + var libRef = libComp.EmitToImageReference(); + + var srcCompat = """ +new object().M(); +System.Action a = new object().M; +var x = new object().M; + +E.M(new object()); +E.get_P(); +E.M2(); +"""; + var comp = CreateCompilation(srcCompat, references: [libRef], parseOptions: TestOptions.Regular13); + comp.VerifyEmitDiagnostics(); + + comp = CreateCompilation(srcCompat, references: [libRef], parseOptions: TestOptions.RegularNext); + comp.VerifyEmitDiagnostics(); + + comp = CreateCompilation(srcCompat, references: [libRef]); + comp.VerifyEmitDiagnostics(); + + var src = """ +object.M2(); +System.Action a = object.M2; +var x = object.M2; + +_ = object.P; +"""; + comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular13); + comp.VerifyEmitDiagnostics( + // (1,8): error CS0117: 'object' does not contain a definition for 'M2' + // object.M2(); + Diagnostic(ErrorCode.ERR_NoSuchMember, "M2").WithArguments("object", "M2").WithLocation(1, 8), + // (2,26): error CS0117: 'object' does not contain a definition for 'M2' + // System.Action a = object.M2; + Diagnostic(ErrorCode.ERR_NoSuchMember, "M2").WithArguments("object", "M2").WithLocation(2, 26), + // (3,16): error CS0117: 'object' does not contain a definition for 'M2' + // var x = object.M2; + Diagnostic(ErrorCode.ERR_NoSuchMember, "M2").WithArguments("object", "M2").WithLocation(3, 16), + // (5,12): error CS0117: 'object' does not contain a definition for 'P' + // _ = object.P; + Diagnostic(ErrorCode.ERR_NoSuchMember, "P").WithArguments("object", "P").WithLocation(5, 12)); + verifySymbolInfo(comp, newLangVer: false); + + comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.RegularNext); + comp.VerifyEmitDiagnostics(); + verifySymbolInfo(comp, newLangVer: true); + + comp = CreateCompilation(src, references: [libRef]); + comp.VerifyEmitDiagnostics(); + verifySymbolInfo(comp, newLangVer: true); + + static void verifySymbolInfo(CSharpCompilation comp, bool newLangVer) + { + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var o = ((Compilation)comp).GetSpecialType(SpecialType.System_Object); + + if (newLangVer) + { + AssertEqualAndNoDuplicates(["void E.<>E__0.M()"], model.LookupSymbols(position: 0, o, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings()); + AssertEqualAndNoDuplicates(["void E.<>E__0.M2()"], model.LookupSymbols(position: 0, o, name: "M2", includeReducedExtensionMethods: true).ToTestDisplayStrings()); + AssertEqualAndNoDuplicates(["System.Int32 E.<>E__0.P { get; }"], model.LookupSymbols(position: 0, o, name: "P", includeReducedExtensionMethods: true).ToTestDisplayStrings()); + } + else + { + AssertEqualAndNoDuplicates(["void System.Object.M()"], model.LookupSymbols(position: 0, o, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings()); + AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, o, name: "M2", includeReducedExtensionMethods: true).ToTestDisplayStrings()); + AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, o, name: "P", includeReducedExtensionMethods: true).ToTestDisplayStrings()); + } + } + } + + [Fact] + public void This_01() + { + var src = """ +static class E +{ + extension(object) + { + public void M() + { + var x = this; + this.ToString(); + local(); + + void local() + { + var y = this; + } + } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (7,21): error CS0027: Keyword 'this' is not available in the current context + // var x = this; + Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(7, 21), + // (8,13): error CS0027: Keyword 'this' is not available in the current context + // this.ToString(); + Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(8, 13), + // (13,25): error CS0027: Keyword 'this' is not available in the current context + // var y = this; + Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(13, 25)); + } + + [Fact] + public void This_02() + { + var src = """ +static class E +{ + extension(object o) + { + public void M() + { + M2(); + this.M2(); + M2(new object()); + } + public void M2() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (7,13): error CS7036: There is no argument given that corresponds to the required parameter 'o' of 'E.M2(object)' + // M2(); + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "M2").WithArguments("o", "E.M2(object)").WithLocation(7, 13), + // (8,13): error CS0027: Keyword 'this' is not available in the current context + // this.M2(); + Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(8, 13)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var invocation = GetSyntax(tree, "M2()"); + Assert.Null(model.GetSymbolInfo(invocation).Symbol); + + invocation = GetSyntax(tree, "this.M2()"); + Assert.Equal("void E.<>E__0.M2()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); + + invocation = GetSyntax(tree, "M2(new object())"); + Assert.Equal("void E.M2(this System.Object o)", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); + } + + [Fact] + public void This_03() + { + var src = """ +static class E +{ + extension(object o) + { + public static void M() + { + M2(); + } + public void M2() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (7,13): error CS7036: There is no argument given that corresponds to the required parameter 'o' of 'E.M2(object)' + // M2(); + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "M2").WithArguments("o", "E.M2(object)").WithLocation(7, 13)); + } + + [Fact] + public void This_04() + { + var src = """ +static class E +{ + extension(object o) + { + public void M() + { + M2(); + } + public static void M2() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var invocation = GetSyntax(tree, "M2()"); + Assert.Equal("void E.M2()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); + } + + [Fact] + public void ReceiverParameter_Access_01() + { + var src = """ +static class E +{ + extension(object o) + { + public void M() + { + o.M2(); + } + public void M2() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void ReceiverParameter_Access_02() + { + var src = """ +static class E +{ + extension(object o) + { + public void M() + { + o.M2(); + } + public static void M2() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (7,13): error CS0176: Member 'E.extension(object).M2()' cannot be accessed with an instance reference; qualify it with a type name instead + // o.M2(); + Diagnostic(ErrorCode.ERR_ObjectProhibited, "o.M2").WithArguments("E.extension(object).M2()").WithLocation(7, 13)); + } + + [Fact] + public void ReceiverParameter_Access_03() + { + var src = """ +static class E +{ + extension(object o) + { + public static void M() + { + o.M2(); + } + public void M2() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (7,13): error CS9293: Cannot use extension parameter 'object o' in this context. + // o.M2(); + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "o").WithArguments("object o").WithLocation(7, 13)); + } + + [Fact] + public void ReceiverParameter_Access_04() + { + var src = """ +static class E +{ + extension(object o) + { + public void M() + { + local(); + void local() + { + o.M2(); + } + } + public void M2() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void ReceiverParameter_Access_05() + { + var src = """ +static class E +{ + extension(object o, object o2) + { + public void M() + { + o2.ToString(); + } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,25): error CS9285: An extension container can have only one receiver parameter + // extension(object o, object o2) + Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "object o2").WithLocation(3, 25), + // (7,13): error CS0103: The name 'o2' does not exist in the current context + // o2.ToString(); + Diagnostic(ErrorCode.ERR_NameNotInContext, "o2").WithArguments("o2").WithLocation(7, 13)); + } + + [Fact] + public void ReceiverParameter_Access_06() + { + var src = """ +static class E +{ + extension(System.Span s) + { + public async void M() + { + s.ToString(); + await System.Threading.Tasks.Task.Yield(); + s.ToString(); + } + } +} +"""; + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : we should produce this error instead: + // error CS4012: Parameters of type 'Span' cannot be declared in async methods or async lambda expressions. + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); + comp.VerifyEmitDiagnostics( + // (7,13): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // s.ToString(); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s").WithArguments("System.Span").WithLocation(7, 13), + // (9,13): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // s.ToString(); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s").WithArguments("System.Span").WithLocation(9, 13)); + } + + [Fact] + public void ReceiverParameter_TypeParametersMustBeUsed() + { + var src = """ +int i = C.P; + +class C { } + +static class E +{ + extension(C) + { + static int P => 0; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,11): error CS0117: 'C' does not contain a definition for 'P' + // int i = C.P; + Diagnostic(ErrorCode.ERR_NoSuchMember, "P").WithArguments("C", "P").WithLocation(1, 11), + // (7,21): error CS9295: The extended type 'C' must reference all the type parameters declared by the extension, but type parameter 'T' is not referenced. + // extension(C) + Diagnostic(ErrorCode.ERR_UnderspecifiedExtension, "C").WithArguments("C", "T").WithLocation(7, 21), + // (7,21): error CS9295: The extended type 'C' must reference all the type parameters declared by the extension, but type parameter 'U' is not referenced. + // extension(C) + Diagnostic(ErrorCode.ERR_UnderspecifiedExtension, "C").WithArguments("C", "U").WithLocation(7, 21)); + } + + public partial class RegionAnalysisTests : FlowTestBase + { + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : consider removing `this` from the region analysis tests + [Fact] + public void RegionAnalysis_01() + { + var analysisResults = CompileAndAnalyzeDataFlowExpression(""" +static class E +{ + extension(int i) + { + public void M(int i2) + { + _ = /**/i + i2/**/; + } + } +} +"""); + VerifyDataFlowAnalysis(""" +VariablesDeclared: +AlwaysAssigned: +Captured: +CapturedInside: +CapturedOutside: +DataFlowsIn: i, i2 +DataFlowsOut: +DefinitelyAssignedOnEntry: i, this, i2 +DefinitelyAssignedOnExit: i, this, i2 +ReadInside: i, i2 +ReadOutside: +WrittenInside: +WrittenOutside: i, this, i2 +""", analysisResults); + } + + [Fact] + public void RegionAnalysis_02() + { + var analysisResults = CompileAndAnalyzeDataFlowExpression(""" +static class E +{ + extension(int i) + { + public void M(int i2) + { + /**/this.ToString()/**/; + } + } +} +"""); + VerifyDataFlowAnalysis(""" +VariablesDeclared: +AlwaysAssigned: +Captured: +CapturedInside: +CapturedOutside: +DataFlowsIn: this +DataFlowsOut: +DefinitelyAssignedOnEntry: i, this, i2 +DefinitelyAssignedOnExit: i, this, i2 +ReadInside: this +ReadOutside: +WrittenInside: +WrittenOutside: i, this, i2 +""", analysisResults); + } + + [Fact] + public void RegionAnalysis_03() + { + var analysisResults = CompileAndAnalyzeDataFlowExpression(""" +static class E +{ + extension(int i) + { + public void M(int i2) + { + int i3 = 0; +/**/ + System.Action = () => i + i2 + i3; +/**/ + } + } +} +"""); + VerifyDataFlowAnalysis(""" +VariablesDeclared: +AlwaysAssigned: +Captured: i, i2, i3 +CapturedInside: i, i2, i3 +CapturedOutside: +DataFlowsIn: i, i2, i3 +DataFlowsOut: +DefinitelyAssignedOnEntry: i, this, i2, i3 +DefinitelyAssignedOnExit: i, this, i2, i3 +ReadInside: i, i2, i3 +ReadOutside: +WrittenInside: +WrittenOutside: i, this, i2, i3 +""", analysisResults); + } + + [Fact] + public void RegionAnalysis_04() + { + var analysisResults = CompileAndAnalyzeDataFlowExpression(""" +static class E +{ + extension(ref int i) + { + public void M(ref int i2) + { + _ = /**/i + i2/**/; + } + } +} +"""); + VerifyDataFlowAnalysis(""" +VariablesDeclared: +AlwaysAssigned: +Captured: +CapturedInside: +CapturedOutside: +DataFlowsIn: i, i2 +DataFlowsOut: +DefinitelyAssignedOnEntry: i, this, i2 +DefinitelyAssignedOnExit: i, this, i2 +ReadInside: i, i2 +ReadOutside: i, i2 +WrittenInside: +WrittenOutside: i, this, i2 +""", analysisResults); + } + + [Fact] + public void RegionAnalysis_05() + { + var analysisResults = CompileAndAnalyzeDataFlowExpression(""" +static class E +{ + extension(out int i) + { + public void M(out int i2) + { + /**/i = i2 = 0;/**/ + } + } +} +"""); + VerifyDataFlowAnalysis(""" +VariablesDeclared: +AlwaysAssigned: i, i2 +Captured: +CapturedInside: +CapturedOutside: +DataFlowsIn: +DataFlowsOut: i, i2 +DefinitelyAssignedOnEntry: this +DefinitelyAssignedOnExit: i, this, i2 +ReadInside: +ReadOutside: i, i2 +WrittenInside: i, i2 +WrittenOutside: this +""", analysisResults); + } + + [Fact] + public void RegionAnalysis_06() + { + var analysisResults = CompileAndAnalyzeDataFlowExpression(""" +static class E +{ + extension(int i) + { + public void M(int i2) + { + /**/i = i2 = 0;/**/ + } + } +} +"""); + VerifyDataFlowAnalysis(""" +VariablesDeclared: +AlwaysAssigned: i, i2 +Captured: +CapturedInside: +CapturedOutside: +DataFlowsIn: +DataFlowsOut: +DefinitelyAssignedOnEntry: i, this, i2 +DefinitelyAssignedOnExit: i, this, i2 +ReadInside: +ReadOutside: +WrittenInside: i, i2 +WrittenOutside: i, this, i2 +""", analysisResults); + } + + [Fact] + public void RegionAnalysis_07() + { + var analysisResults = CompileAndAnalyzeDataFlowExpression(""" +static class E +{ + extension(ref int i) + { + public void M(ref int i2) + { + /**/i = ref i2;/**/ + } + } +} +"""); + VerifyDataFlowAnalysis(""" +VariablesDeclared: +AlwaysAssigned: i +Captured: +CapturedInside: +CapturedOutside: +DataFlowsIn: i2 +DataFlowsOut: i, i2 +DefinitelyAssignedOnEntry: i, this, i2 +DefinitelyAssignedOnExit: i, this, i2 +ReadInside: i2 +ReadOutside: i, i2 +WrittenInside: i, i2 +WrittenOutside: i, this, i2 +""", analysisResults); + } + + [Fact] + public void RegionAnalysis_08() + { + var analysisResults = CompileAndAnalyzeDataFlowExpression(""" +static class E +{ + extension(int i) + { + public void M(int i2) + { + void local(int i3) + { + _ = /**/i + i2 + i3/**/; + } + } + } +} +"""); + VerifyDataFlowAnalysis(""" +VariablesDeclared: +AlwaysAssigned: +Captured: i, i2 +CapturedInside: i, i2 +CapturedOutside: +DataFlowsIn: i3 +DataFlowsOut: +DefinitelyAssignedOnEntry: i, this, i2, i3 +DefinitelyAssignedOnExit: i, this, i2, i3 +ReadInside: i, i2, i3 +ReadOutside: +WrittenInside: +WrittenOutside: i, this, i2, i3 +""", analysisResults); + } + + [Fact] + public void RegionAnalysis_09() + { + var analysisResults = CompileAndAnalyzeDataFlowExpression(""" +static class E +{ + extension(out int i) + { + public void M(out int i2) + { + void local(out int i3) + { + /**/i = i2 = i3 = 0;/**/ + } + } + } +} +"""); + VerifyDataFlowAnalysis(""" +VariablesDeclared: +AlwaysAssigned: i, i2, i3 +Captured: i, i2 +CapturedInside: i, i2 +CapturedOutside: +DataFlowsIn: +DataFlowsOut: i, i2, i3 +DefinitelyAssignedOnEntry: this +DefinitelyAssignedOnExit: i, this, i2, i3 +ReadInside: +ReadOutside: i, i2, i3 +WrittenInside: i, i2, i3 +WrittenOutside: this +""", analysisResults); + } + } + + [Fact] + public void Base_01() + { + var src = """ +static class E +{ + extension(object) + { + public void M() + { + base.ToString(); + } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (7,13): error CS1512: Keyword 'base' is not available in the current context + // base.ToString(); + Diagnostic(ErrorCode.ERR_BaseInBadContext, "base").WithLocation(7, 13)); + } + + [Fact] + public void FunctionType_TypeReceiver_01() + { + var src = """ +var x = int.M; +x(); + +public static class E +{ + extension(T t) + { + public static void M() { System.Console.Write("ran"); } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var localDeclaration = GetSyntax(tree, "var x = int.M"); + Assert.Equal("System.Action", model.GetTypeInfo(localDeclaration.Type).Type.ToTestDisplayString()); + } + + [Fact] + public void FunctionType_TypeReceiver_02() + { + var src = """ +var x = int.M; + +public static class E +{ + extension(T t) + { + public void M() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,9): error CS8917: The delegate type could not be inferred. + // var x = int.M; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "int.M").WithLocation(1, 9)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var localDeclaration = GetSyntax(tree, "var x = int.M"); + Assert.True(model.GetTypeInfo(localDeclaration.Type).Type.IsErrorType()); + } + + [Fact] + public void FunctionType_TypeReceiver_03() + { + var src = """ +var x = int.M; + +public static class E +{ + public static void M(this T t) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,9): error CS8917: The delegate type could not be inferred. + // var x = int.M; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "int.M").WithLocation(1, 9)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var localDeclaration = GetSyntax(tree, "var x = int.M"); + Assert.True(model.GetTypeInfo(localDeclaration.Type).Type.IsErrorType()); + } + + [Fact] + public void FunctionType_InstanceReceiver_01() + { + var src = """ +var x = 42.M; + +public static class E +{ + extension(T t) + { + public void M() { System.Console.Write(t); } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,9): error CS1113: Extension method 'E.extension(int).M()' defined on value type 'int' cannot be used to create delegates + // var x = 42.M; + Diagnostic(ErrorCode.ERR_ValueTypeExtDelegate, "42.M").WithArguments("E.extension(int).M()", "int").WithLocation(1, 9)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var localDeclaration = GetSyntax(tree, "var x = 42.M"); + Assert.Equal("System.Action", model.GetTypeInfo(localDeclaration.Type).Type.ToTestDisplayString()); + } + + [Fact] + public void FunctionType_InstanceReceiver_02() + { + var src = """ +var x = "ran".M; +x(); + +public static class E +{ + extension(T t) + { + public void M() { System.Console.Write(t); } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var localDeclaration = GetSyntax(tree, """var x = "ran".M"""); + Assert.Equal("System.Action", model.GetTypeInfo(localDeclaration.Type).Type.ToTestDisplayString()); + } + + [Fact] + public void FunctionType_InstanceReceiver_03() + { + var src = """ +var x = 42.M; + +public static class E +{ + extension(T t) + { + public static void M() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,9): error CS8917: The delegate type could not be inferred. + // var x = 42.M; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "42.M").WithLocation(1, 9)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var localDeclaration = GetSyntax(tree, "var x = 42.M"); + Assert.True(model.GetTypeInfo(localDeclaration.Type).Type.IsErrorType()); + } + + [Fact] + public void FunctionType_InstanceReceiver_04() + { + var src = """ +var x = 42.M; + +public static class E +{ + extension(int) + { + public void M() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,9): error CS8917: The delegate type could not be inferred. + // var x = 42.M; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "42.M").WithLocation(1, 9)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var localDeclaration = GetSyntax(tree, "var x = 42.M"); + Assert.True(model.GetTypeInfo(localDeclaration.Type).Type.IsErrorType()); + } + + [Fact] + public void FunctionType_InstanceReceiver_05() + { + var src = """ +var x = "ran".M; +x(); + +public static class E +{ + extension(string s) + { + public void M() { System.Console.Write(s); } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var localDeclaration = GetSyntax(tree, """var x = "ran".M"""); + Assert.Equal("System.Action", model.GetTypeInfo(localDeclaration.Type).Type.ToTestDisplayString()); + } + + [Fact] + public void FunctionType_InstanceReceiver_06() + { + var src = """ +var x = "ran".M; +x(); + +public static class E +{ + extension(string s) + { + public void M() { System.Console.Write(s); } + public void M(T t) { } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var localDeclaration = GetSyntax(tree, """var x = "ran".M"""); + Assert.Equal("System.Action", model.GetTypeInfo(localDeclaration.Type).Type.ToTestDisplayString()); + } + + [Fact] + public void FunctionType_InstanceReceiver_07() + { + var src = """ +namespace N +{ + public class C + { + public static void Main() + { + var x = "".M; + System.Console.Write(x); + } + } + + public static class E1 + { + extension(string s) + { + public void M() { } + } + } +} + +public static class E2 +{ + extension(string s) + { + public int M => 42; + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + comp.VerifyEmitDiagnostics( + // (7,21): error CS8917: The delegate type could not be inferred. + // var x = "".M; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, @""""".M").WithLocation(7, 21)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var localDeclaration = GetSyntax(tree, """var x = "".M"""); + Assert.True(model.GetTypeInfo(localDeclaration.Type).Type.IsErrorType()); + } + + [Fact] + public void FunctionType_InstanceReceiver_08() + { + var src = """ +namespace N +{ + public class C + { + public static void Main() + { + var x = "ran".M; + x(42); + } + } + + public static class E1 + { + extension(string s) + { + public void M() { } + } + } +} + +public static class E2 +{ + extension(string s) + { + public void M(int i) { System.Console.Write((s, i)); } + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: "(ran, 42)").VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var localDeclaration = GetSyntax(tree, """var x = "ran".M"""); + Assert.Equal("System.Action", model.GetTypeInfo(localDeclaration.Type).Type.ToTestDisplayString()); + } + + [Fact] + public void FunctionType_InstanceReceiver_09() + { + var src = """ +var x = "ran".M; + +public static class E1 +{ + extension(string s) + { + public void M() { } + } +} + +public static class E2 +{ + extension(string s) + { + public void M(int i) { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,9): error CS8917: The delegate type could not be inferred. + // var x = "ran".M; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, @"""ran"".M").WithLocation(1, 9)); + } + + [Fact] + public void FunctionType_InstanceReceiver_10() + { + var src = """ +System.Delegate x = "ran".M; +x.DynamicInvoke(); + +id("ran".M)(); + +T id(T t) => t; + +public static class E +{ + extension(string s) + { + public void M() { System.Console.Write("ran "); } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "ran ran").VerifyDiagnostics(); + } + + [Fact] + public void FunctionType_InstanceReceiver_11() + { + var src = """ +using N; + +var x = "ran".M; + +public static class E1 +{ + extension(T t) where T : struct + { + public void M() { } + } +} + +namespace N +{ + public static class E2 + { + extension(T t) + { + public void M() { } + } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyDiagnostics(); + } + + [Fact] + public void FunctionType_ColorColorReceiver_01() + { + var src = """ +Color.M2(new Color()); + +public class Color +{ + public static void M2(Color Color) + { + var x = Color.M; + x(); + } +} + +public static class E +{ + extension(T t) + { + public void M() { System.Console.Write("ran"); } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + } + + [Fact] + public void FunctionType_ColorColorReceiver_02() + { + var src = """ +Color.M2(null); + +public class Color +{ + public static void M2(Color Color) + { + var x = Color.M; + x(); + } +} + +public static class E +{ + extension(T) + { + public static void M() { System.Console.Write("ran"); } + } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + } + + [Fact] + public void FunctionType_ColorColorReceiver_03() + { + var src = """ +Color.M2(new Color()); + +public class Color +{ + public static void M2(Color Color) + { + var x = Color.M; + x(); + } + public void M() { System.Console.Write("ran"); } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + } + + [Fact] + public void FunctionType_ColorColorReceiver_04() + { + var src = """ +Color.M2(null); + +public class Color +{ + public static void M2(Color Color) + { + var x = Color.M; + x(); + } + public static void M() { System.Console.Write("ran"); } +} +"""; + var comp = CreateCompilation(src); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + } + + [Fact] + public void FunctionType_ColorColorReceiver_05() + { + var src = """ +public class Color +{ + public static void M2(Color Color) + { + var x = Color.M; + } +} + +public static class E1 +{ + extension(T) + { + public static void M() { } + } +} + +public static class E2 +{ + extension(T) + { + public void M() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (5,17): error CS0121: The call is ambiguous between the following methods or properties: 'E1.extension(T).M()' and 'E2.extension(T).M()' + // var x = Color.M; + Diagnostic(ErrorCode.ERR_AmbigCall, "Color.M").WithArguments("E1.extension(T).M()", "E2.extension(T).M()").WithLocation(5, 17)); + } + + [Fact] + public void Params_ExtensionScopes_01() + { + var source = """ +static class E1 +{ + extension(N.C c) + { + public void M(int[] x) => System.Console.Write(3); + } +} + +namespace N +{ + static class E2 + { + extension(C c) + { + public void M(params int[] x) => System.Console.Write(2); + } + } + + class C + { + public void M(params int[] x) => System.Console.Write(1); + public static void Main() + { + var d = new C().M; + System.Console.WriteLine(d.GetType()); + d(); + } + } +} +"""; + + var expectedOutput = """ +<>f__AnonymousDelegate0`1[System.Int32] +1 +"""; + + CompileAndVerify(source, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + + static void validateSymbols(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + Assert.Equal("void <>f__AnonymousDelegate0.Invoke(params T1[] arg)", m.ToTestDisplayString()); + } + } + + [Fact] + public void Params_ExtensionScopes_02() + { + var source = """ +static class E1 +{ + extension(N.C c) + { + public void M(params int[] x) => System.Console.Write(3); + } +} + +namespace N +{ + static class E2 + { + extension(C c) + { + public void M(params int[] x) => System.Console.Write(2); + } + } + + class C + { + public void M(params int[] x) => System.Console.Write(1); + public static void Main() + { + var d = new C().M; + System.Console.WriteLine(d.GetType()); + d(); + } + } +} +"""; + + var expectedOutput = """ +<>f__AnonymousDelegate0`1[System.Int32] +1 +"""; + + CompileAndVerify(source, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + + static void validateSymbols(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + Assert.Equal("void <>f__AnonymousDelegate0.Invoke(params T1[] arg)", m.ToTestDisplayString()); + } + } + [Fact] + public void Params_ExtensionScopes_07() + { + var source = """ +static class E1 +{ + extension(N.C c) + { + public void M(params int[] x) => System.Console.Write(1); + } +} + +namespace N +{ + static class E2 + { + extension(C) + { + public void M(int[] x) => System.Console.Write(2); + } + } + + class C + { + public static void Main() + { + var d = new C().M; + System.Console.WriteLine(d.GetType()); + d(default); + } + } +} +"""; + + var expectedOutput = """ +System.Action`1[System.Int32[]] +2 +"""; + + CompileAndVerify(source, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void Params_ExtensionScopes_08() + { + var source = """ +static class E1 +{ + extension(N.C c) + { + public void M(int[] x) => System.Console.Write(1); + } +} + +namespace N +{ + static class E2 + { + extension(C c) + { + public void M(params int[] x) => System.Console.Write(2); + } + } + + class C + { + public static void Main() + { + var d = new C().M; + System.Console.WriteLine(d.GetType()); + d(); + } + } +} +"""; + + var expectedOutput = """ +<>f__AnonymousDelegate0`1[System.Int32] +2 +"""; + + CreateCompilation(source).VerifyDiagnostics(); + CompileAndVerify(source, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + + static void validateSymbols(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + Assert.Equal("void <>f__AnonymousDelegate0.Invoke(params T1[] arg)", m.ToTestDisplayString()); + } + } + + [Fact] + public void ImplementsIEnumerableT_21_AddIsNotAnExtension() + { + var src = """ +using System.Collections; +using System.Collections.Generic; + +class MyCollection : IEnumerable +{ + IEnumerator IEnumerable.GetEnumerator() => throw null; + IEnumerator IEnumerable.GetEnumerator() => throw null; +} + +static class Ext +{ + extension(MyCollection c) + { + public void Add(long l) {} + } +} + +class Program +{ + static void Main() + { + Test(); + Test(1); + Test(2, 3); + } +#line 24 + static void Test(params MyCollection a) + { + } + + static void Test2() + { + Test([2, 3]); + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.ReleaseExe); + + comp.VerifyDiagnostics( + // (24,22): error CS9227: 'MyCollection' does not contain a definition for a suitable instance 'Add' method + // static void Test(params MyCollection a) + Diagnostic(ErrorCode.ERR_ParamsCollectionExtensionAddMethod, "params MyCollection a").WithArguments("MyCollection").WithLocation(24, 22) + ); + } + + [Fact] + public void TestGetEnumeratorPatternViaExtensionWithOptionalParameter() + { + var source = @" +using System; +public class C +{ + public static void Main() + /**/ + { + foreach (var i in new C()) + { + Console.Write(i); + } + } + /**/ + + public sealed class Enumerator + { + public Enumerator(int start) => Current = start; + public int Current { get; private set; } + public bool MoveNext() => Current++ != 3; + } +} +public static class Extensions +{ + extension(C self) + { + public C.Enumerator GetEnumerator(int x = 1) => new C.Enumerator(x); + } +}"; + var verifier = CompileAndVerify(source, expectedOutput: "23"); + + VerifyFlowGraphAndDiagnosticsForTest((CSharpCompilation)verifier.Compilation, +@" +Block[B0] - Entry + Statements (0) + Next (Regular) Block[B1] + Entering: {R1} +.locals {R1} +{ + CaptureIds: [0] + Block[B1] - Block + Predecessors: [B0] + Statements (1) + IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'new C()') + Value: + IInvocationOperation ( C.Enumerator Extensions.<>E__0.GetEnumerator([System.Int32 x = 1])) (OperationKind.Invocation, Type: C.Enumerator, IsImplicit) (Syntax: 'new C()') + Instance Receiver: + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: C, IsImplicit) (Syntax: 'new C()') + Conversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + (Identity) + Operand: + IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C) (Syntax: 'new C()') + Arguments(0) + Initializer: + null + Arguments(1): + IArgumentOperation (ArgumentKind.DefaultValue, Matching Parameter: x) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'new C()') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsImplicit) (Syntax: 'new C()') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Next (Regular) Block[B2] + Block[B2] - Block + Predecessors: [B1] [B3] + Statements (0) + Jump if False (Regular) to Block[B4] + IInvocationOperation ( System.Boolean C.Enumerator.MoveNext()) (OperationKind.Invocation, Type: System.Boolean, IsImplicit) (Syntax: 'new C()') + Instance Receiver: + IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: C.Enumerator, IsImplicit) (Syntax: 'new C()') + Arguments(0) + Leaving: {R1} + Next (Regular) Block[B3] + Entering: {R2} + .locals {R2} + { + Locals: [System.Int32 i] + Block[B3] - Block + Predecessors: [B2] + Statements (2) + ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: null, IsImplicit) (Syntax: 'var') + Left: + ILocalReferenceOperation: i (IsDeclaration: True) (OperationKind.LocalReference, Type: System.Int32, IsImplicit) (Syntax: 'var') + Right: + IPropertyReferenceOperation: System.Int32 C.Enumerator.Current { get; private set; } (OperationKind.PropertyReference, Type: System.Int32, IsImplicit) (Syntax: 'var') + Instance Receiver: + IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: C.Enumerator, IsImplicit) (Syntax: 'new C()') + IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Write(i);') + Expression: + IInvocationOperation (void System.Console.Write(System.Int32 value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Write(i)') + Instance Receiver: + null + Arguments(1): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: 'i') + ILocalReferenceOperation: i (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Next (Regular) Block[B2] + Leaving: {R2} + } +} +Block[B4] - Exit + Predecessors: [B2] + Statements (0) +", []); + } + + [Fact] + public void TestGetEnumeratorPatternViaExtensionWithOptionalParameter_02() + { + var source = @" +using System; +public struct C +{ + public static void Main() + /**/ + { + foreach (var i in new C()) + { + Console.Write(i); + } + } + /**/ + + public sealed class Enumerator + { + public Enumerator(int start) => Current = start; + public int Current { get; private set; } + public bool MoveNext() => Current++ != 3; + } +} +public static class Extensions +{ + extension(object self) + { + public C.Enumerator GetEnumerator(int x = 1) => new C.Enumerator(x); + } +}"; + var verifier = CompileAndVerify(source, expectedOutput: "23", parseOptions: TestOptions.RegularPreview.WithFeature("run-nullable-analysis", "never")); // Tracked by https://github.com/dotnet/roslyn/issues/76130: Nullable analysis asserts + + VerifyFlowGraphAndDiagnosticsForTest((CSharpCompilation)verifier.Compilation, +@" +Block[B0] - Entry + Statements (0) + Next (Regular) Block[B1] + Entering: {R1} +.locals {R1} +{ + CaptureIds: [0] + Block[B1] - Block + Predecessors: [B0] + Statements (1) + IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'new C()') + Value: + IInvocationOperation ( C.Enumerator Extensions.<>E__0.GetEnumerator([System.Int32 x = 1])) (OperationKind.Invocation, Type: C.Enumerator, IsImplicit) (Syntax: 'new C()') + Instance Receiver: + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'new C()') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + (Boxing) + Operand: + IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C) (Syntax: 'new C()') + Arguments(0) + Initializer: + null + Arguments(1): + IArgumentOperation (ArgumentKind.DefaultValue, Matching Parameter: x) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'new C()') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsImplicit) (Syntax: 'new C()') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Next (Regular) Block[B2] + Block[B2] - Block + Predecessors: [B1] [B3] + Statements (0) + Jump if False (Regular) to Block[B4] + IInvocationOperation ( System.Boolean C.Enumerator.MoveNext()) (OperationKind.Invocation, Type: System.Boolean, IsImplicit) (Syntax: 'new C()') + Instance Receiver: + IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: C.Enumerator, IsImplicit) (Syntax: 'new C()') + Arguments(0) + Leaving: {R1} + Next (Regular) Block[B3] + Entering: {R2} + .locals {R2} + { + Locals: [System.Int32 i] + Block[B3] - Block + Predecessors: [B2] + Statements (2) + ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: null, IsImplicit) (Syntax: 'var') + Left: + ILocalReferenceOperation: i (IsDeclaration: True) (OperationKind.LocalReference, Type: System.Int32, IsImplicit) (Syntax: 'var') + Right: + IPropertyReferenceOperation: System.Int32 C.Enumerator.Current { get; private set; } (OperationKind.PropertyReference, Type: System.Int32, IsImplicit) (Syntax: 'var') + Instance Receiver: + IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: C.Enumerator, IsImplicit) (Syntax: 'new C()') + IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Write(i);') + Expression: + IInvocationOperation (void System.Console.Write(System.Int32 value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Write(i)') + Instance Receiver: + null + Arguments(1): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: 'i') + ILocalReferenceOperation: i (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Next (Regular) Block[B2] + Leaving: {R2} + } +} +Block[B4] - Exit + Predecessors: [B2] + Statements (0) +", []); + } + + [Fact] + public void TestMoveNextPatternViaExtensions_OnInstanceGetEnumerator() + { + var source = @" +using System; +public class C +{ + public static void Main() + { + foreach (var i in new C()) + { + Console.Write(i); + } + } + public sealed class Enumerator + { + public int Current { get; private set; } + } + + public C.Enumerator GetEnumerator() => new C.Enumerator(); +} +public static class Extensions +{ + extension(C.Enumerator e) + { + public bool MoveNext() => false; + } +}"; + CreateCompilation(source) + .VerifyDiagnostics( + // (7,27): error CS0117: 'C.Enumerator' does not contain a definition for 'MoveNext' + // foreach (var i in new C()) + Diagnostic(ErrorCode.ERR_NoSuchMember, "new C()").WithArguments("C.Enumerator", "MoveNext").WithLocation(7, 27), + // (7,27): error CS0202: foreach requires that the return type 'C.Enumerator' of 'C.GetEnumerator()' must have a suitable public 'MoveNext' method and public 'Current' property + // foreach (var i in new C()) + Diagnostic(ErrorCode.ERR_BadGetEnumerator, "new C()").WithArguments("C.Enumerator", "C.GetEnumerator()").WithLocation(7, 27) + ); + } + + [Fact] + public void TestGetEnumeratorPatternViaRefExtensionOnNonAssignableVariable() + { + var source = @" +using System; +public struct C +{ + public static void Main() + { + foreach (var i in new C()) + { + Console.Write(i); + } + } + public struct Enumerator + { + public int Current { get; private set; } + public bool MoveNext() => Current++ != 3; + } +} +public static class Extensions +{ + extension(ref C self) + { + public C.Enumerator GetEnumerator() => new C.Enumerator(); + } +}"; + CreateCompilation(source) + .VerifyDiagnostics( + // (7,27): error CS1510: A ref or out value must be an assignable variable + // foreach (var i in new C()) + Diagnostic(ErrorCode.ERR_RefLvalueExpected, "new C()").WithLocation(7, 27)); + } + + [Fact] + public void ExpressionTrees_01_InstanceMethod() + { + var src = """ +using System; +using System.Linq.Expressions; + +public static class Extensions +{ + extension(object o) + { + public string M(string s) => o + s; + } +} + +class Program +{ + static void Main() + { + var e = Test(); + System.Console.Write(e.Compile().Invoke("1", "2")); + System.Console.Write(": "); + System.Console.Write(e); + } + + static Expression> Test() + { + return (o, s) => o.M(s); + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: @"12: (o, s) => o.M(s)").VerifyDiagnostics(); + } + + [Fact] + public void ExpressionTrees_02_StaticMethod() + { + var src = """ +using System; +using System.Linq.Expressions; + +public static class Extensions +{ + extension(object o) + { + public static string M(string s) => s; + } +} + +class Program +{ + static void Main() + { + var e = Test(); + System.Console.Write(e.Compile().Invoke("1")); + System.Console.Write(": "); + System.Console.Write(e); + } + + static Expression> Test() + { + return (s) => object.M(s); + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: @"1: s => M(s)").VerifyDiagnostics(); + } + + [Fact] + public void ExpressionTrees_03_InstanceIndexer() + { + var src = """ +using System; +using System.Linq.Expressions; + +public static class Extensions +{ + extension(object o) + { + public string this[string s] => o + s; + } +} + +class Program +{ + static void Main() + { + var e = Test(); + System.Console.Write(e.Compile().Invoke("1", "2")); + System.Console.Write(": "); + System.Console.Write(e); + } + + static Expression> Test() + { + return (o, s) => o[s]; + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + comp.VerifyDiagnostics( + // (24,26): error CS0021: Cannot apply indexing with [] to an expression of type 'object' + // return (o, s) => o[s]; + Diagnostic(ErrorCode.ERR_BadIndexLHS, "o[s]").WithArguments("object").WithLocation(24, 26) + ); + } + + [Fact] + public void ExpressionTrees_04_InstanceProperty() + { + var src = """ +using System; +using System.Linq.Expressions; + +public static class Extensions +{ + extension(object o) + { + public string P => (string)o; + } +} + +class Program +{ + static void Main() + { + var e = Test(); + System.Console.Write(e.Compile().Invoke("1")); + System.Console.Write(": "); + System.Console.Write(e); + } + + static Expression> Test() + { + return (o) => o.P; + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + comp.VerifyDiagnostics( + // (24,23): error CS9296: An expression tree may not contain an extension property access + // return (o) => o.P; + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsExtensionPropertyAccess, "o.P").WithLocation(24, 23) + ); + } + + [Fact] + public void ExpressionTrees_05_InstanceProperty() + { + var src = """ +using System; +using System.Linq.Expressions; + +public static class Extensions +{ + extension(object o) + { + public string P { get => (string)o; set {}} + } +} + +class Program +{ + static void Main() + { + var e = Test(); + System.Console.Write(e.Compile().Invoke("1")); + System.Console.Write(": "); + System.Console.Write(e); + } + + static Expression> Test() + { + return (s) => new object() { P = s }; + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + comp.VerifyDiagnostics( + // (24,38): error CS9296: An expression tree may not contain an extension property access + // return (s) => new object() { P = s }; + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsExtensionPropertyAccess, "P").WithLocation(24, 38) + ); + } + + [Fact] + public void ExpressionTrees_06_InstanceProperty() + { + var src = """ +using System; +using System.Linq.Expressions; + +public static class Extensions +{ + extension(object o) + { + public C P { get => default; } + } +} + +public class C +{ + public string F; +} + +class Program +{ + static void Main() + { + var e = Test(); + System.Console.Write(e.Compile().Invoke("1")); + System.Console.Write(": "); + System.Console.Write(e); + } + + static Expression> Test() + { + return (s) => new object() { P = { F = s } }; + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + comp.VerifyDiagnostics( + // (29,38): error CS9296: An expression tree may not contain an extension property access + // return (s) => new object() { P = { F = s } }; + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsExtensionPropertyAccess, "P").WithLocation(29, 38) + ); + } + + [Fact] + public void ExpressionTrees_07_InstanceProperty() + { + var src = """ +using System; +using System.Linq.Expressions; + +public static class Extensions +{ + extension(object o) + { + public string P { get => default; } + } +} + +class Program +{ + static void Main() + { + } + + static Expression> Test() + { + return (o) => o is object { P: "s" }; + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + comp.VerifyDiagnostics( + // (20,23): error CS8122: An expression tree may not contain an 'is' pattern-matching operator. + // return (o) => o is object { P: "s" }; + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsIsMatch, @"o is object { P: ""s"" }").WithLocation(20, 23) + ); + } + + [Fact] + public void ExpressionTrees_08_StaticProperty() + { + var src = """ +using System; +using System.Linq.Expressions; + +public static class Extensions +{ + extension(object o) + { + public static string P => "o"; + } +} + +class Program +{ + static void Main() + { + var e = Test(); + System.Console.Write(e.Compile().Invoke()); + System.Console.Write(": "); + System.Console.Write(e); + } + + static Expression> Test() + { + return () => object.P; + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + comp.VerifyDiagnostics( + // (24,22): error CS9296: An expression tree may not contain an extension property access + // return () => object.P; + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsExtensionPropertyAccess, "object.P").WithLocation(24, 22) + ); + } + + [Fact] + public void ExpressionTrees_09_DelegateCreation_InstanceMethod() + { + var src = """ +using System; +using System.Linq.Expressions; + +public static class Extensions +{ + extension(object o) + { + public string M(string s) => o + s; + } +} + +class Program +{ + static void Main() + { + var e = Test(); + System.Console.Write(e.Compile().Invoke("1").Invoke("2")); + System.Console.Write(": "); + System.Console.Write(e); + } + + static Expression>> Test() + { + return (o) => o.M; + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: @"12: o => Convert(System.String M(System.Object, System.String).CreateDelegate(System.Func`2[System.String,System.String], o)" + (ExecutionConditionUtil.IsMonoOrCoreClr ? ", Func`2)" : ")")).VerifyDiagnostics(); + } + + [Fact] + public void ExpressionTrees_10_DelegateCreation_StaticMethod() + { + var src = """ +using System; +using System.Linq.Expressions; + +public static class Extensions +{ + extension(object o) + { + public static string M(string s) => s; + } +} + +class Program +{ + static void Main() + { + var e = Test(); + System.Console.Write(e.Compile().Invoke().Invoke("1")); + System.Console.Write(": "); + System.Console.Write(e); + } + + static Expression>> Test() + { + return () => object.M; + } +} +"""; + var comp = CreateCompilation(src, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: @"1: () => Convert(System.String M(System.String).CreateDelegate(System.Func`2[System.String,System.String], null)" + (ExecutionConditionUtil.IsMonoOrCoreClr ? ", Func`2)" : ")")).VerifyDiagnostics(); + } +} diff --git a/src/Compilers/CSharp/Test/Emit3/Semantics/ParamsCollectionTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/ParamsCollectionTests.cs index e6efe39d327e3..2a80d5a0d1968 100644 --- a/src/Compilers/CSharp/Test/Emit3/Semantics/ParamsCollectionTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/ParamsCollectionTests.cs @@ -3193,7 +3193,7 @@ static int GetC() // Note, the collection is created after the lexically previous argument is evaluated, // but before the lexically following argument is evaluated. This differs from params - // array case, which is created right before the target methos is invoked, after all + // array case, which is created right before the target method is invoked, after all // arguments are evaluated in their lexical order, which can be observed in a unit-test // Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen.CodeGenTests.NamedParamsOptimizationAndParams002​ verifier.VerifyIL("Program.Main", @" diff --git a/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests.cs index 9b892c7ea73c6..6ba97279d29d0 100644 --- a/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests.cs @@ -12284,7 +12284,7 @@ public void Test2(G x2) [Fact] [WorkItem(63476, "https://github.com/dotnet/roslyn/issues/63476")] - public void PatternNonConstant_UserDefinedImplicit_ConvertionToInputType() + public void PatternNonConstant_UserDefinedImplicit_ConversionToInputType() { var source = @" @@ -12306,7 +12306,7 @@ class C [Fact] [WorkItem(63476, "https://github.com/dotnet/roslyn/issues/63476")] - public void PatternNonConstant_UserDefinedExplicit_ConvertionToInputType() + public void PatternNonConstant_UserDefinedExplicit_ConversionToInputType() { var source = @" @@ -12327,7 +12327,7 @@ class C } [Fact] - public void PatternReadOnlySpan_ImplicitBuiltInConvertion_ToString() + public void PatternReadOnlySpan_ImplicitBuiltInConversion_ToString() { var source = @" @@ -12341,7 +12341,7 @@ class C } [Fact] - public void PatternNoImplicitConvertionToInputType() + public void PatternNoImplicitConversionToInputType() { // Cannot implicitly cast long to byte.. var source = diff --git a/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests5.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests5.cs index 0120dc6e33d29..1d4e2f1a64c85 100644 --- a/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests5.cs +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests5.cs @@ -1981,10 +1981,10 @@ void M(T t) where T : INumberBase var comp = CreateCompilation(new[] { source, INumberBaseDefinition }); comp.VerifyDiagnostics( - // (8,9): error CS9060: Cannot use a numeric constant or relational pattern on 'T' because it inherits from or extends 'INumberBase'. Consider using a type pattern to narrow to a specifc numeric type. + // (8,9): error CS9060: Cannot use a numeric constant or relational pattern on 'T' because it inherits from or extends 'INumberBase'. Consider using a type pattern to narrow to a specific numeric type. // 1 => 1, // 1 Diagnostic(ErrorCode.ERR_CannotMatchOnINumberBase, "1").WithArguments("T").WithLocation(8, 9), - // (9,9): error CS9060: Cannot use a numeric constant or relational pattern on 'T' because it inherits from or extends 'INumberBase'. Consider using a type pattern to narrow to a specifc numeric type. + // (9,9): error CS9060: Cannot use a numeric constant or relational pattern on 'T' because it inherits from or extends 'INumberBase'. Consider using a type pattern to narrow to a specific numeric type. // > 1 => 2, // 2 Diagnostic(ErrorCode.ERR_CannotMatchOnINumberBase, "> 1").WithArguments("T").WithLocation(9, 9), // (11,9): error CS8985: List patterns may not be used for a value of type 'T'. No suitable 'Length' or 'Count' property was found. @@ -2025,10 +2025,10 @@ void M(T t) where T : struct, INumberBase var comp = CreateCompilation(new[] { source, INumberBaseDefinition }); comp.VerifyDiagnostics( - // (8,9): error CS9060: Cannot use a numeric constant or relational pattern on 'T' because it inherits from or extends 'INumberBase'. Consider using a type pattern to narrow to a specifc numeric type. + // (8,9): error CS9060: Cannot use a numeric constant or relational pattern on 'T' because it inherits from or extends 'INumberBase'. Consider using a type pattern to narrow to a specific numeric type. // 1 => 1, // 1 Diagnostic(ErrorCode.ERR_CannotMatchOnINumberBase, "1").WithArguments("T").WithLocation(8, 9), - // (9,9): error CS9060: Cannot use a numeric constant or relational pattern on 'T' because it inherits from or extends 'INumberBase'. Consider using a type pattern to narrow to a specifc numeric type. + // (9,9): error CS9060: Cannot use a numeric constant or relational pattern on 'T' because it inherits from or extends 'INumberBase'. Consider using a type pattern to narrow to a specific numeric type. // > 1 => 2, // 2 Diagnostic(ErrorCode.ERR_CannotMatchOnINumberBase, "> 1").WithArguments("T").WithLocation(9, 9), // (11,9): error CS8985: List patterns may not be used for a value of type 'T'. No suitable 'Length' or 'Count' property was found. @@ -2122,10 +2122,10 @@ void M(T t) where T : struct, A::System.Numerics.INumberBase var comp = CreateCompilation(new[] { source }, references: new[] { ref1, ref2 }); comp.VerifyDiagnostics( - // (8,9): error CS9060: Cannot use a numeric constant or relational pattern on 'T' because it inherits from or extends 'INumberBase'. Consider using a type pattern to narrow to a specifc numeric type. + // (8,9): error CS9060: Cannot use a numeric constant or relational pattern on 'T' because it inherits from or extends 'INumberBase'. Consider using a type pattern to narrow to a specific numeric type. // 1 => 1, // 1 Diagnostic(ErrorCode.ERR_CannotMatchOnINumberBase, "1").WithArguments("T").WithLocation(8, 9), - // (9,9): error CS9060: Cannot use a numeric constant or relational pattern on 'T' because it inherits from or extends 'INumberBase'. Consider using a type pattern to narrow to a specifc numeric type. + // (9,9): error CS9060: Cannot use a numeric constant or relational pattern on 'T' because it inherits from or extends 'INumberBase'. Consider using a type pattern to narrow to a specific numeric type. // > 1 => 2, // 2 Diagnostic(ErrorCode.ERR_CannotMatchOnINumberBase, "> 1").WithArguments("T").WithLocation(9, 9), // (11,9): error CS8985: List patterns may not be used for a value of type 'T'. No suitable 'Length' or 'Count' property was found. @@ -2431,10 +2431,10 @@ public void MatchingOnConstantConversionsWithINumberBaseIsDisallowed_TypePattern var comp = CreateEmptyCompilation(new[] { source, INumberBaseBCL, INumberBaseDefinition }); comp.VerifyDiagnostics( - // (5,5): error CS9060: Cannot use a numeric constant or relational pattern on 'INumberBase' because it inherits from or extends 'INumberBase'. Consider using a type pattern to narrow to a specifc numeric type. + // (5,5): error CS9060: Cannot use a numeric constant or relational pattern on 'INumberBase' because it inherits from or extends 'INumberBase'. Consider using a type pattern to narrow to a specific numeric type. // 1 => 1, Diagnostic(ErrorCode.ERR_CannotMatchOnINumberBase, "1").WithArguments("System.Numerics.INumberBase").WithLocation(5, 5), - // (6,5): error CS9060: Cannot use a numeric constant or relational pattern on 'INumberBase' because it inherits from or extends 'INumberBase'. Consider using a type pattern to narrow to a specifc numeric type. + // (6,5): error CS9060: Cannot use a numeric constant or relational pattern on 'INumberBase' because it inherits from or extends 'INumberBase'. Consider using a type pattern to narrow to a specific numeric type. // > 1 => 2, Diagnostic(ErrorCode.ERR_CannotMatchOnINumberBase, "> 1").WithArguments("System.Numerics.INumberBase").WithLocation(6, 5) ); diff --git a/src/Compilers/CSharp/Test/Emit3/Semantics/RecordTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/RecordTests.cs index 0ab3cc6b650cf..0b8fa5baa41b0 100644 --- a/src/Compilers/CSharp/Test/Emit3/Semantics/RecordTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/RecordTests.cs @@ -306,6 +306,8 @@ record R(R x); record R2(R2? x) { } record R3([System.Diagnostics.CodeAnalysis.NotNull] R3 x); + +record R4(in R4 x); "; var comp = CreateCompilation(new[] { src, NotNullAttributeDefinition }); comp.VerifyEmitDiagnostics( @@ -317,11 +319,14 @@ record R3([System.Diagnostics.CodeAnalysis.NotNull] R3 x); Diagnostic(ErrorCode.ERR_RecordAmbigCtor, "R2").WithLocation(5, 8), // (7,8): error CS8909: The primary constructor conflicts with the synthesized copy constructor. // record R3([System.Diagnostics.CodeAnalysis.NotNull] R3 x); - Diagnostic(ErrorCode.ERR_RecordAmbigCtor, "R3").WithLocation(7, 8) + Diagnostic(ErrorCode.ERR_RecordAmbigCtor, "R3").WithLocation(7, 8), + // 0.cs(9,8): error CS8910: The primary constructor conflicts with the synthesized copy constructor. + // record R4(in R4 x); + Diagnostic(ErrorCode.ERR_RecordAmbigCtor, "R4").WithLocation(9, 8) ); var r = comp.GlobalNamespace.GetTypeMember("R"); - Assert.Equal(new[] { "R..ctor(R x)", "R..ctor(R original)" }, r.GetMembers(".ctor").ToTestDisplayStrings()); + Assert.Equal(new[] { "R..ctor(R x)" }, r.GetMembers(".ctor").ToTestDisplayStrings()); } [Fact, WorkItem(49628, "https://github.com/dotnet/roslyn/issues/49628")] @@ -394,27 +399,12 @@ record R3(R3 x) : Base // (4,8): error CS8909: The primary constructor conflicts with the synthesized copy constructor. // record R(R x) : Base; // 1 Diagnostic(ErrorCode.ERR_RecordAmbigCtor, "R").WithLocation(4, 8), - // (6,30): error CS0121: The call is ambiguous between the following methods or properties: 'R.R(R)' and 'R.R(R)' - // record Derived(Derived y) : R(y) // 2 - Diagnostic(ErrorCode.ERR_AmbigCall, "(y)").WithArguments("R.R(R)", "R.R(R)").WithLocation(6, 30), // (8,12): error CS0111: Type 'Derived' already defines a member called 'Derived' with the same parameter types // public Derived(Derived y) : base(y) => throw null; // 3, 4, 5 Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "Derived").WithArguments("Derived", "Derived").WithLocation(8, 12), - // (8,33): error CS0121: The call is ambiguous between the following methods or properties: 'R.R(R)' and 'R.R(R)' - // public Derived(Derived y) : base(y) => throw null; // 3, 4, 5 - Diagnostic(ErrorCode.ERR_AmbigCall, "base").WithArguments("R.R(R)", "R.R(R)").WithLocation(8, 33), - // (8,33): error CS8868: A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object. - // public Derived(Derived y) : base(y) => throw null; // 3, 4, 5 - Diagnostic(ErrorCode.ERR_CopyConstructorMustInvokeBaseCopyConstructor, "base").WithLocation(8, 33), // (11,8): error CS8909: The primary constructor conflicts with the synthesized copy constructor. // record Derived2(Derived2 y) : R(y); // 6, 7, 8 Diagnostic(ErrorCode.ERR_RecordAmbigCtor, "Derived2").WithLocation(11, 8), - // (11,8): error CS8867: No accessible copy constructor found in base type 'R'. - // record Derived2(Derived2 y) : R(y); // 6, 7, 8 - Diagnostic(ErrorCode.ERR_NoCopyConstructorInBaseType, "Derived2").WithArguments("R").WithLocation(11, 8), - // (11,32): error CS0121: The call is ambiguous between the following methods or properties: 'R.R(R)' and 'R.R(R)' - // record Derived2(Derived2 y) : R(y); // 6, 7, 8 - Diagnostic(ErrorCode.ERR_AmbigCall, "(y)").WithArguments("R.R(R)", "R.R(R)").WithLocation(11, 32), // (15,12): error CS0111: Type 'R2' already defines a member called 'R2' with the same parameter types // public R2(R2 x) => throw null; // 9, 10 Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "R2").WithArguments("R2", "R2").WithLocation(15, 12), @@ -601,7 +591,7 @@ public record A(int i, int ) { } var ctor = comp.GetMember("A").Constructors[0]; Assert.Equal("A..ctor(System.Int32 i, System.Int32)", ctor.ToTestDisplayString()); Assert.IsType(ctor.Parameters[1].DeclaringSyntaxReferences.Single().GetSyntax()); - Assert.Equal(0, ctor.Parameters[1].Locations.Single().SourceSpan.Length); + Assert.Equal(3, ctor.Parameters[1].Locations.Single().SourceSpan.Length); } [Fact, WorkItem(46123, "https://github.com/dotnet/roslyn/issues/46123")] @@ -615,12 +605,12 @@ public record A(int, string ) { } // (2,20): error CS1001: Identifier expected // public record A(int, string ) { } Diagnostic(ErrorCode.ERR_IdentifierExpected, ",").WithLocation(2, 20), - // (2,29): error CS1001: Identifier expected + // (2,22): error CS0102: The type 'A' already contains a definition for '' // public record A(int, string ) { } - Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(2, 29), - // (2,29): error CS0102: The type 'A' already contains a definition for '' + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "string").WithArguments("A", "").WithLocation(2, 22), + // (2,29): error CS1001: Identifier expected // public record A(int, string ) { } - Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "").WithArguments("A", "").WithLocation(2, 29) + Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(2, 29) ); var expectedMembers = new[] @@ -649,12 +639,12 @@ public record A(int, int ) { } // (2,20): error CS1001: Identifier expected // public record A(int, int ) { } Diagnostic(ErrorCode.ERR_IdentifierExpected, ",").WithLocation(2, 20), - // (2,26): error CS1001: Identifier expected + // (2,22): error CS0102: The type 'A' already contains a definition for '' // public record A(int, int ) { } - Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(2, 26), - // (2,26): error CS0102: The type 'A' already contains a definition for '' + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "int").WithArguments("A", "").WithLocation(2, 22), + // (2,26): error CS1001: Identifier expected // public record A(int, int ) { } - Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "").WithArguments("A", "").WithLocation(2, 26) + Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(2, 26) ); var expectedMembers = new[] @@ -685,12 +675,12 @@ public record A(int // A // (2,20): error CS1001: Identifier expected // public record A(int // A Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(2, 20), - // (4,18): error CS1001: Identifier expected + // (4,7): error CS0102: The type 'A' already contains a definition for '' // , int /* C */) { } - Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(4, 18), - // (4,18): error CS0102: The type 'A' already contains a definition for '' + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "int").WithArguments("A", "").WithLocation(4, 7), + // (4,18): error CS1001: Identifier expected // , int /* C */) { } - Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "").WithArguments("A", "").WithLocation(4, 18) + Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(4, 18) ); var ctor = comp.GetMember("A").Constructors[0]; @@ -30379,7 +30369,7 @@ class C3 } [Fact, WorkItem(62051, "https://github.com/dotnet/roslyn/issues/62051")] - public void MisingBaseType() + public void MissingBaseType() { var src = @" record R : // 1 diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_InvalidExpression.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_InvalidExpression.cs index 4e10cee0ee03b..0192b30fbbcae 100644 --- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_InvalidExpression.cs +++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_InvalidExpression.cs @@ -33,9 +33,7 @@ static void Main(string[] args) string expectedOperationTree = @" IInvalidOperation (OperationKind.Invalid, Type: ?, IsInvalid) (Syntax: 'Console.WriteLine2()') Children(1): - IInvalidOperation (OperationKind.Invalid, Type: ?, IsInvalid) (Syntax: 'Console.WriteLine2') - Children(1): - IOperation: (OperationKind.None, Type: System.Console) (Syntax: 'Console') + IOperation: (OperationKind.None, Type: System.Console) (Syntax: 'Console') "; var expectedDiagnostics = new DiagnosticDescription[] { // CS0117: 'Console' does not contain a definition for 'WriteLine2' diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs index d8e9be5af9aa0..c9eff6dfe013d 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs @@ -2400,7 +2400,7 @@ public static void M(this C c) var typeInfo = model.GetTypeInfo(memberAccess); Assert.Null(typeInfo.Type); Assert.Equal("System.Action", typeInfo.ConvertedType!.ToTestDisplayString()); - // https://github.com/dotnet/roslyn/issues/52870: GetSymbolInfo() should return resolved method from method group. + // https://github.com/dotnet/roslyn/issues/52870 GetSymbolInfo() should return resolved method from method group. Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.Equal(["void C.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } @@ -2423,37 +2423,139 @@ public void M(C c) { } // ignored public static class E { - public static void M(this C c) { } + public static void M(this C c) { } // ignored } """; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular12); - comp.VerifyDiagnostics( - // (1,21): error CS0123: No overload for 'M' matches delegate 'Action' - // System.Action x = C.M; - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "M").WithArguments("M", "System.Action").WithLocation(1, 21), - // (4,9): error CS8917: The delegate type could not be inferred. - // var z = C.M; - Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "C.M").WithLocation(4, 9) - ); + { + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular12); + comp.VerifyDiagnostics( + // (1,19): error CS0120: An object reference is required for the non-static field, method, or property 'E.M(C)' + // System.Action x = C.M; + Diagnostic(ErrorCode.ERR_ObjectRequired, "C.M").WithArguments("E.M(C)").WithLocation(1, 19), + // (4,9): error CS8917: The delegate type could not be inferred. + // var z = C.M; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "C.M").WithLocation(4, 9)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var memberAccess1 = GetSyntaxes(tree, "C.M").First(); + var typeInfo1 = model.GetTypeInfo(memberAccess1); + Assert.Null(typeInfo1.Type); + Assert.Equal("System.Action", typeInfo1.ConvertedType!.ToTestDisplayString()); + Assert.Equal("void C.M()", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); + Assert.Equal(["void C.M(C c)", "void C.M()"], model.GetMemberGroup(memberAccess1).ToTestDisplayStrings()); + + var memberAccess2 = GetSyntaxes(tree, "C.M").Last(); + var typeInfo2 = model.GetTypeInfo(memberAccess2); + Assert.Null(typeInfo2.Type); + Assert.True(typeInfo2.ConvertedType!.IsErrorType()); + Assert.Null(model.GetSymbolInfo(memberAccess2).Symbol); + Assert.Equal(["void C.M(C c)", "void C.M()"], model.GetMemberGroup(memberAccess2).ToTestDisplayStrings()); + } - comp = CreateCompilation(source, parseOptions: useCSharp13 ? TestOptions.Regular13 : TestOptions.RegularPreview); - comp.VerifyDiagnostics( - // (1,21): error CS0123: No overload for 'M' matches delegate 'Action' - // System.Action x = C.M; - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "M").WithArguments("M", "System.Action").WithLocation(1, 21), - // (4,9): error CS8917: The delegate type could not be inferred. - // var z = C.M; - Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "C.M").WithLocation(4, 9) - ); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : instead of finding the extension method and reporting an error on its receiver, + // we should instead discard it as a candidate early like we do for instance methods in OverloadResolution.RemoveStaticInstanceMismatches + { + var comp = CreateCompilation(source, parseOptions: useCSharp13 ? TestOptions.Regular13 : TestOptions.RegularPreview); + comp.VerifyDiagnostics( + // (1,19): error CS0120: An object reference is required for the non-static field, method, or property 'E.M(C)' + // System.Action x = C.M; + Diagnostic(ErrorCode.ERR_ObjectRequired, "C.M").WithArguments("E.M(C)").WithLocation(1, 19), + // (4,9): error CS8917: The delegate type could not be inferred. + // var z = C.M; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "C.M").WithLocation(4, 9)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var memberAccess1 = GetSyntaxes(tree, "C.M").First(); + var typeInfo1 = model.GetTypeInfo(memberAccess1); + Assert.Null(typeInfo1.Type); + Assert.Equal("System.Action", typeInfo1.ConvertedType!.ToTestDisplayString()); + Assert.Equal("void C.M()", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); + Assert.Equal(["void C.M(C c)", "void C.M()"], model.GetMemberGroup(memberAccess1).ToTestDisplayStrings()); + + var memberAccess2 = GetSyntaxes(tree, "C.M").Last(); + var typeInfo2 = model.GetTypeInfo(memberAccess2); + Assert.Null(typeInfo2.Type); + Assert.True(typeInfo2.ConvertedType!.IsErrorType()); + Assert.Null(model.GetSymbolInfo(memberAccess2).Symbol); + Assert.Equal(["void C.M(C c)", "void C.M()"], model.GetMemberGroup(memberAccess2).ToTestDisplayStrings()); + } + } - var tree = comp.SyntaxTrees[0]; - var model = comp.GetSemanticModel(tree); - var memberAccess = GetSyntaxes(tree, "C.M").Last(); - var typeInfo = model.GetTypeInfo(memberAccess); - Assert.Null(typeInfo.Type); - Assert.True(typeInfo.ConvertedType!.IsErrorType()); - Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); - AssertEx.Equal(["void C.M(C c)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/csharplang/issues/7364")] + public void MethodGroup_ScopeByScope_TypeReceiver_2(bool useCSharp13) + { + // Extension methods are ignored on type receiver + var source = """ +System.Action x = C.M; +x(); + +var z = C.M; +z(); + +public class C { } + +public static class E +{ + public static void M(this C c) { } // ignored +} +"""; + { + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular12); + comp.VerifyDiagnostics( + // (1,19): error CS0120: An object reference is required for the non-static field, method, or property 'E.M(C)' + // System.Action x = C.M; + Diagnostic(ErrorCode.ERR_ObjectRequired, "C.M").WithArguments("E.M(C)").WithLocation(1, 19), + // (4,9): error CS8917: The delegate type could not be inferred. + // var z = C.M; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "C.M").WithLocation(4, 9)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var memberAccess1 = GetSyntaxes(tree, "C.M").First(); + var typeInfo1 = model.GetTypeInfo(memberAccess1); + Assert.Null(typeInfo1.Type); + Assert.Equal("System.Action", typeInfo1.ConvertedType!.ToTestDisplayString()); + Assert.Equal("void C.M()", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); + Assert.Equal(["void C.M()"], model.GetMemberGroup(memberAccess1).ToTestDisplayStrings()); + + var memberAccess2 = GetSyntaxes(tree, "C.M").Last(); + var typeInfo2 = model.GetTypeInfo(memberAccess2); + Assert.Null(typeInfo2.Type); + Assert.True(typeInfo2.ConvertedType!.IsErrorType()); + Assert.Null(model.GetSymbolInfo(memberAccess2).Symbol); + Assert.Equal(["void C.M()"], model.GetMemberGroup(memberAccess2).ToTestDisplayStrings()); + } + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : instead of finding the extension method and reporting an error on its receiver, + // we should instead discard it as a candidate early like we do for instance methods in OverloadResolution.RemoveStaticInstanceMismatches + { + var comp = CreateCompilation(source, parseOptions: useCSharp13 ? TestOptions.RegularNext : TestOptions.RegularPreview); + comp.VerifyDiagnostics( + // (1,19): error CS0120: An object reference is required for the non-static field, method, or property 'E.M(C)' + // System.Action x = C.M; + Diagnostic(ErrorCode.ERR_ObjectRequired, "C.M").WithArguments("E.M(C)").WithLocation(1, 19), + // (4,9): error CS8917: The delegate type could not be inferred. + // var z = C.M; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "C.M").WithLocation(4, 9)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var memberAccess1 = GetSyntaxes(tree, "C.M").First(); + var typeInfo1 = model.GetTypeInfo(memberAccess1); + Assert.Null(typeInfo1.Type); + Assert.Equal("System.Action", typeInfo1.ConvertedType!.ToTestDisplayString()); + Assert.Equal("void C.M()", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); + Assert.Equal(["void C.M()"], model.GetMemberGroup(memberAccess1).ToTestDisplayStrings()); + + var memberAccess2 = GetSyntaxes(tree, "C.M").Last(); + var typeInfo2 = model.GetTypeInfo(memberAccess2); + Assert.Null(typeInfo2.Type); + Assert.True(typeInfo2.ConvertedType!.IsErrorType()); + Assert.Null(model.GetSymbolInfo(memberAccess2).Symbol); + Assert.Equal(["void C.M()"], model.GetMemberGroup(memberAccess2).ToTestDisplayStrings()); + } } [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/csharplang/issues/7364")] @@ -2916,9 +3018,7 @@ public void M(object o) where T : class { } var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax(tree, "new C().M"); Assert.Equal("void C.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); - - AssertEx.Equal(["void C.M()", "void C.M(System.Object o)"], - model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + AssertEx.Equal(["void C.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69222")] @@ -3042,9 +3142,7 @@ public static void M(this T t, object ignored) where T : struct { } var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax(tree, "new object().M"); Assert.Equal("void System.Object.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); - - AssertEx.Equal(["void System.Object.M()", "void System.Object.M(System.Object ignored)"], - model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + AssertEx.Equal(["void System.Object.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Theory, CombinatorialData] @@ -16121,7 +16219,7 @@ public static void Main() } [Fact] - public void LambdWithDefaultNamedDelegateConversion_LambdaMissingOptional() + public void LambdaWithDefaultNamedDelegateConversion_LambdaMissingOptional() { var source = """ class Program diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/InheritanceBindingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/InheritanceBindingTests.cs index 2d7ff0cb065f0..d03737a24fc77 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/InheritanceBindingTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/InheritanceBindingTests.cs @@ -7320,9 +7320,9 @@ public static void Main() // (27,27): warning CS0693: Type parameter 'T' has the same name as the type parameter from outer type 'Derived1' // public class Derived2 : Outer>>.Inner>>.Interface> Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, "T").WithArguments("T", "Derived1").WithLocation(27, 27), - // (37,28): warning CS0693: Type parameter 'T' has the same name as the type parameter from outer type 'Derived1' + // (37,28): warning CS0693: Type parameter 'T' has the same name as the type parameter from outer type 'Derived1.Derived2' // public void Method(List> A, List>[] B, List C, Outer>>.Inner>>.Interface, T> D) - Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, "T").WithArguments("T", "Derived1").WithLocation(37, 28), + Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, "T").WithArguments("T", "Derived1.Derived2").WithLocation(37, 28), // (27,32): error CS0535: 'Derived1.Derived2' does not implement interface member 'Outer>>.Inner>>.Interface>.Method(System.Collections.Generic.List>, System.Collections.Generic.List>[], System.Collections.Generic.List, Outer>>.Inner>>.Interface, K>)' // public class Derived2 : Outer>>.Inner>>.Interface> Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "Outer>>.Inner>>.Interface>").WithArguments("Derived1.Derived2", "Outer>>.Inner>>.Interface>.Method(System.Collections.Generic.List>, System.Collections.Generic.List>[], System.Collections.Generic.List, Outer>>.Inner>>.Interface, K>)").WithLocation(27, 32), diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/IteratorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/IteratorTests.cs index 379986f86a708..69f12e7e3d7e2 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/IteratorTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/IteratorTests.cs @@ -447,10 +447,7 @@ public void TopLevelYieldReturn() // (1,18): error CS1002: ; expected // yield return int. Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 18), - // (1,18): error CS0117: 'int' does not contain a definition for '' - // yield return int. - Diagnostic(ErrorCode.ERR_NoSuchMember, "").WithArguments("int", "").WithLocation(1, 18), - // (1,1): error CS7020: You cannot use 'yield' in top-level script code + // (1,1): error CS7020: Cannot use 'yield' in top-level script code // yield return int. Diagnostic(ErrorCode.ERR_YieldNotAllowedInScript, "yield").WithLocation(1, 1)); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs index 9226f1e71e1e3..54d7002e47a40 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs @@ -507,7 +507,8 @@ End Module var vbProject = VisualBasic.VisualBasicCompilation.Create( "VBProject", references: new[] { MscorlibRef }, - syntaxTrees: new[] { VisualBasic.VisualBasicSyntaxTree.ParseText(vbSource) }); + syntaxTrees: new[] { VisualBasic.VisualBasicSyntaxTree.ParseText(vbSource) }, + options: new VisualBasic.VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); var csSource = @" class Program @@ -557,7 +558,8 @@ End Module var vbProject = VisualBasic.VisualBasicCompilation.Create( "VBProject", references: new[] { MscorlibRef }, - syntaxTrees: new[] { VisualBasic.VisualBasicSyntaxTree.ParseText(vbSource) }); + syntaxTrees: new[] { VisualBasic.VisualBasicSyntaxTree.ParseText(vbSource) }, + options: new VisualBasic.VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); var csSource = @" class Program diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs index 44125b156e1d4..a5b2d45978332 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs @@ -10588,5 +10588,126 @@ void M() // [A(p)] void F() { } Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "F").WithArguments("F").WithLocation(13, 21)); } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/76528")] + [InlineData("")] + [InlineData("static ")] + public void Repro76528(string modifiers) + { + var source = $$""" + #nullable enable + + using System; + using System.Diagnostics.CodeAnalysis; + + public class C + { + public static string? _field; + + public Action Prop1 { get; } = () => + { + init(); + Console.WriteLine(_field.Length); + + [MemberNotNull(nameof(_field))] + {{modifiers}}void init() => _field ??= ""; + }; + } + """; + var comp = CreateCompilation([source, MemberNotNullAttributeDefinition]); + comp.VerifyEmitDiagnostics(); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/76528")] + [InlineData("")] + [InlineData("static ")] + public void Repro76528_FieldInitializer(string modifiers) + { + var source = $$""" + #nullable enable + + using System; + using System.Diagnostics.CodeAnalysis; + + public class C + { + public static string? _field; + + public Action _field2 = () => + { + init(); + Console.WriteLine(_field.Length); + + [MemberNotNull(nameof(_field))] + {{modifiers}}void init() => _field ??= ""; + }; + } + """; + var comp = CreateCompilation([source, MemberNotNullAttributeDefinition]); + comp.VerifyEmitDiagnostics(); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/76528")] + [InlineData("")] + [InlineData("static ")] + public void Repro76528_StaticLambda(string modifiers) + { + var source = $$""" + #nullable enable + + using System; + using System.Diagnostics.CodeAnalysis; + + public class C + { + public static string? _field; + + public Action Prop1 { get; } = static () => + { + init(); + Console.WriteLine(_field.Length); + + [MemberNotNull(nameof(_field))] + {{modifiers}}void init() => _field ??= ""; + }; + } + """; + var comp = CreateCompilation([source, MemberNotNullAttributeDefinition]); + comp.VerifyEmitDiagnostics(); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/76528")] + [CombinatorialData] + public void Repro76528_FieldInitializer_PrimaryConstructor(bool isStatic) + { + var source = $$""" + #nullable enable + + using System; + using System.Diagnostics.CodeAnalysis; + + public class C(string p) + { + public static string? _field; + + public Action _field2 = () => + { + init(); + Console.WriteLine(_field.Length); + + [MemberNotNull(nameof(_field))] + {{(isStatic ? "static " : "")}}void init() => _field ??= p; + }; + + string M() => p; + } + """; + var comp = CreateCompilation([source, MemberNotNullAttributeDefinition]); + comp.VerifyEmitDiagnostics(isStatic ? [ + // (16,42): error CS8421: A static local function cannot contain a reference to 'p'. + // static void init() => _field ??= p; + Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureVariable, "p").WithArguments("p").WithLocation(16, 42) + ] : []); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LookupPositionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LookupPositionTests.cs index 948e31354dbfb..c1f39092873b6 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LookupPositionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LookupPositionTests.cs @@ -2430,7 +2430,7 @@ record C(int X) : Base`(X`) members), Remove( "System.Int32 C.X { get; init; }"), - Add( // paremeters + Add( // parameters "System.Int32 X")), Combine(s_pop, s_pop, s_pop), Add( // Members @@ -2514,7 +2514,7 @@ class C(int X) : Base`(X`) members), Remove( "System.Int32 C.X { get; }"), - Add( // paremeters + Add( // parameters "System.Int32 X")), Combine(s_pop, s_pop, s_pop), Add( // Members diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/OperatorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/OperatorTests.cs index 74966d84778a6..e22052dedc114 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/OperatorTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/OperatorTests.cs @@ -8789,7 +8789,7 @@ struct TestStr Assert.Null(info1.Symbol); break; default: - throw Roslyn.Utilities.ExceptionUtilities.UnexpectedValue(i); + throw ExceptionUtilities.UnexpectedValue(i); } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionPerfTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionPerfTests.cs index 1ed435e9df270..addea1aa9099b 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionPerfTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionPerfTests.cs @@ -1061,5 +1061,33 @@ static void M(object o) var containingTypes = exprs.SelectAsArray(e => model.GetSymbolInfo(e).Symbol.ContainingSymbol).ToTestDisplayStrings(); Assert.Equal(new[] { "A", "B", "B", "A", "B", "B" }, containingTypes); } + + [ConditionalFact(typeof(IsRelease))] + [WorkItem("https://github.com/dotnet/roslyn/issues/76568")] + public void NullableAnalysis_ObjectCreationExpression() + { + const int n = 200000; + var builder = new StringBuilder(); + builder.AppendLine(""" + #nullable enable + class A { } + class B + { + static void Main() + { + A a; + """); + for (int i = 0; i < n; i++) + { + builder.AppendLine(" a = new A();"); + } + builder.AppendLine(""" + } + } + """); + var source = builder.ToString(); + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs index a87a177952896..e3f3aef9e1dac 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs @@ -390,14 +390,14 @@ static void Test5() { var sp = MayWrap(default); - // returnable. - var spR = MayWrap(Test1(ref sp)); + // returnable. + var spR = MayWrap(Test1(ref sp)); Span local = stackalloc int[1]; var sp1 = MayWrap(local); // not returnable by value. (since it refers to a local data) - var spNr = MayWrap(Test1(ref sp1)); + var spNr = MayWrap(Test1(ref sp1)); // error spR = spNr; @@ -547,7 +547,7 @@ static void Main() // valid x = MayWrap(outer); - + // error x = MayWrap(inner); } @@ -631,7 +631,7 @@ class Program static void Main() { - } + } static ref int ReturnsRef() { @@ -653,7 +653,7 @@ static ref int ReturnsRef1(__arglist) static ref int ReturnsRefSpan() { Span local = stackalloc int[1]; - + // error here; return ref ReturnsRefSpan1(__arglist(ref local)); } @@ -692,7 +692,7 @@ class Program static void Main() { - } + } static ref int M1() => throw null; @@ -865,7 +865,7 @@ static void Main() } static ref int ReturnsRefTest1() - { + { return ref ReturnsRef(out var z); } @@ -1517,7 +1517,7 @@ static void F2() } static R F() => default; } -ref struct R +ref struct R { public void Deconstruct(out R x, out R y) => throw null; } @@ -1775,7 +1775,7 @@ static void Main() // valid x = MayWrap(ref outer); - + // error x = MayWrap(ref inner); } @@ -1841,7 +1841,7 @@ static void Main() // valid x = MayWrap(ref outer).Slice(1); - + // error x = MayWrap(ref inner).Slice(1); } @@ -1892,12 +1892,12 @@ static void Main() // valid x[0] = MayWrap(ref outer).Slice(1)[0]; - // error, technically rules for this case can be relaxed, + // error, technically rules for this case can be relaxed, // but ref-like typed ref-returning properties are nearly impossible to implement in a useful way // x[0] = MayWrap(ref inner).Slice(1)[0]; - // error, technically rules for this case can be relaxed, + // error, technically rules for this case can be relaxed, // but ref-like typed ref-returning properties are nearly impossible to implement in a useful way // x[x] = MayWrap(ref inner).Slice(1)[0]; @@ -2020,7 +2020,7 @@ void Test1(int x) // valid. parameter scope and the top local scope are the same. rx = ry; - + bool condition = true; rx = condition ? rx: ry; } @@ -3004,12 +3004,12 @@ static void Test() _ = local[heapSpan, heapSpan]; _ = local[heapSpan, stackSpan]; // 7 - _ = local[stackSpan, heapSpan]; + _ = local[stackSpan, heapSpan]; _ = local[stackSpan, stackSpan]; // 8 local[heapSpan, heapSpan] = 42; local[heapSpan, stackSpan] = 42; // 9 - local[stackSpan, heapSpan] = 42; + local[stackSpan, heapSpan] = 42; local[stackSpan, stackSpan] = 42; // 10 } } @@ -3032,7 +3032,7 @@ static void Test() local[heapSpan, heapSpan] = 42; local[heapSpan, stackSpan] = 42; - local[stackSpan, heapSpan] = 42; + local[stackSpan, heapSpan] = 42; local[stackSpan, stackSpan] = 42; } } @@ -3110,61 +3110,61 @@ public void RefLikeEscapeMixingIndexer5() using System; Console.WriteLine(); - ref struct S1 where T : new(), allows ref struct - { - int this[T t] { get => 0; set {} } - - static void Test() - { - scoped T x = default; - T y = default; - S1 local = default; - _ = local[x]; // 1 - _ = local[y]; - local[x] = 42; // 2 - local[y] = 42; - local[x]++; // 3 - local[y]++; - } - } - - ref struct S2 where T : new(), allows ref struct - { - T this[int index] { get => default; set {} } - - static void Test() - { - scoped T x = default; - T y = default; - S2 local = default; - local[0] = x; // 4 - local[1] = y; - } - } + ref struct S1 where T : new(), allows ref struct + { + int this[T t] { get => 0; set {} } + + static void Test() + { + scoped T x = default; + T y = default; + S1 local = default; + _ = local[x]; // 1 + _ = local[y]; + local[x] = 42; // 2 + local[y] = 42; + local[x]++; // 3 + local[y]++; + } + } + + ref struct S2 where T : new(), allows ref struct + { + T this[int index] { get => default; set {} } + + static void Test() + { + scoped T x = default; + T y = default; + S2 local = default; + local[0] = x; // 4 + local[1] = y; + } + } """; var comp = CreateCompilation([code], targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (13,13): error CS8350: This combination of arguments to 'S1.this[T]' is disallowed because it may expose variables referenced by parameter 't' outside of their declaration scope - // _ = local[x]; // 1 + // _ = local[x]; // 1 Diagnostic(ErrorCode.ERR_CallArgMixing, "local[x]").WithArguments("S1.this[T]", "t").WithLocation(13, 13), // (13,19): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope - // _ = local[x]; // 1 + // _ = local[x]; // 1 Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(13, 19), // (15,9): error CS8350: This combination of arguments to 'S1.this[T]' is disallowed because it may expose variables referenced by parameter 't' outside of their declaration scope - // local[x] = 42; // 2 + // local[x] = 42; // 2 Diagnostic(ErrorCode.ERR_CallArgMixing, "local[x]").WithArguments("S1.this[T]", "t").WithLocation(15, 9), // (15,15): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope - // local[x] = 42; // 2 + // local[x] = 42; // 2 Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(15, 15), // (17,9): error CS8350: This combination of arguments to 'S1.this[T]' is disallowed because it may expose variables referenced by parameter 't' outside of their declaration scope - // local[x]++; // 3 + // local[x]++; // 3 Diagnostic(ErrorCode.ERR_CallArgMixing, "local[x]").WithArguments("S1.this[T]", "t").WithLocation(17, 9), // (17,15): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope - // local[x]++; // 3 + // local[x]++; // 3 Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(17, 15), // (31,20): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope - // local[0] = x; // 4 + // local[0] = x; // 4 Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(31, 20) ); } @@ -3868,16 +3868,16 @@ static void Test() } } - public ref struct S3 where T : new(), allows ref struct + public ref struct S3 where T : new(), allows ref struct { - T this[int index] { get => default; set {} } + T this[int index] { get => default; set {} } - static void Test() - { - scoped T stackT = default; - T heapT = default; + static void Test() + { + scoped T stackT = default; + T heapT = default; S3 local; - local = new S3 { [0] = stackT }; // 2 + local = new S3 { [0] = stackT }; // 2 local = new S3 { [0] = heapT }; } } @@ -3889,7 +3889,7 @@ static void Test() // local = new S1() { [0] = stackSpan }; // 1 Diagnostic(ErrorCode.ERR_EscapeVariable, "{ [0] = stackSpan }").WithArguments("[0] = stackSpan").WithLocation(15, 26), // (44,27): error CS8352: Cannot use variable '[0] = stackT' in this context because it may expose referenced variables outside of their declaration scope - // local = new S3 { [0] = stackT }; // 2 + // local = new S3 { [0] = stackT }; // 2 Diagnostic(ErrorCode.ERR_EscapeVariable, "{ [0] = stackT }").WithArguments("[0] = stackT").WithLocation(44, 27) ); } @@ -3949,7 +3949,7 @@ static void Test() S3 local; local = new S3(stackSpan) { [0] = stackSpan }; // 6 local = new S3(stackSpan) { [0] = heapSpan }; // 7 - local = new S3(heapSpan) { [0] = stackSpan }; + local = new S3(heapSpan) { [0] = stackSpan }; local = new S3(heapSpan) { [0] = heapSpan }; } } @@ -4346,7 +4346,7 @@ public ref struct S1 // (33,25): error CS8352: Cannot use variable 'Field2 = {[outer] = inner}' in this context because it may expose referenced variables outside of their declaration scope // return new S2() { Field2 = {[outer] = inner} }; Diagnostic(ErrorCode.ERR_EscapeVariable, "{ Field2 = {[outer] = inner} }").WithArguments("Field2 = {[outer] = inner}").WithLocation(33, 25), - // (67,19): warning CS0649: Field 'Program.S3.Field2' is never assigned to, and will always have its default value + // (67,19): warning CS0649: Field 'Program.S3.Field2' is never assigned to, and will always have its default value // public S1 Field2; Diagnostic(ErrorCode.WRN_UnassignedInternalField, "Field2").WithArguments("Program.S3.Field2", "").WithLocation(67, 19)); } @@ -4535,7 +4535,7 @@ ref int Test1() { var local = 42; - if (flag) + if (flag) return ref true ? ref field : ref local; ref var lr = ref local; @@ -4543,7 +4543,7 @@ ref int Test1() ref var ternary1 = ref true ? ref lr : ref fr; - if (flag) + if (flag) return ref ternary1; } } @@ -4772,7 +4772,7 @@ Span Test3() Span local = stackalloc int[10]; return true? local : default(Span); } - + Span Test4(Span arg) { arg = stackalloc int[10]; @@ -4788,7 +4788,7 @@ Span Test6() } "; CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( - // (19,26): error CS8352: Cannot use variable 'local' in this context because it may expose referenced variables outside of their declaration scope + // (19,26): error CS8352: Cannot use variable 'local' in this context because it may expose referenced variables outside of their declaration scope // return true? local : default(Span); Diagnostic(ErrorCode.ERR_EscapeVariable, "local").WithArguments("local").WithLocation(19, 26), // (24,19): error CS8353: A result of a stackalloc expression of type 'Span' cannot be used in this context because it may be exposed outside of the containing method @@ -4817,7 +4817,7 @@ static void Main() // ok sp = default; - + Span local = stackalloc int[1]; // error @@ -4923,7 +4923,7 @@ public static void Main() Span value1 = stackalloc int[1]; new SR().TryGet(out value1); - // Ok, the new value can be copied into SW but not the + // Ok, the new value can be copied into SW but not the // ref to the value new SW().TryGet(out value1); @@ -5333,9 +5333,9 @@ public void M(ref Span global) ref var r2 = ref (flag2 ? ref global : ref local); // same as global = local; which would be an error. - // but we can’t fail here, since r1 and r2 are basically the same, + // but we can’t fail here, since r1 and r2 are basically the same, // so should fail when making r1 and r2 above. - r1 = r2; + r1 = r2; } public static void Main() @@ -6689,7 +6689,7 @@ public class C static ref readonly int F1(in int x) { - return ref x; + return ref x; } static ref readonly int Test1(in int x) @@ -6784,7 +6784,7 @@ public void PropertyEscape(LanguageVersion languageVersion) ref struct S1 { - internal Span Span + internal Span Span { get => default; set { } @@ -6803,7 +6803,7 @@ static void Test() ref struct S2 { - internal Span Span + internal Span Span { readonly get => default; set { } @@ -6822,7 +6822,7 @@ static void Test() ref struct S3 { - internal ref Span Span + internal ref Span Span { get => throw null!; } @@ -6840,7 +6840,7 @@ static void Test() ref struct S4 { - internal readonly ref Span Span + internal readonly ref Span Span { get => throw null!; } @@ -6992,7 +6992,7 @@ ref struct S { } class C { void M() - { + { _ = (S?)null ?? default; var a = (S?)null ?? default; @@ -7019,7 +7019,7 @@ ref struct S { } class C { void M() - { + { _ = ((S[])null)[0]; var a = ((S[])null)[0]; @@ -7046,13 +7046,13 @@ ref struct S { } class C { void M() - { + { _ = ((C)null)?.Test(); var a = ((C)null)?.Test(); } - - S Test() => default; + + S Test() => default; }", parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.ReleaseDll).VerifyDiagnostics( // (8,23): error CS8977: 'S' cannot be made nullable. // _ = ((C)null)?.Test(); @@ -7238,7 +7238,7 @@ public void CoalesceSpanReturn(LanguageVersion languageVersion) class C { Span M() - { + { return null ?? new Span(); } }", parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.ReleaseDll).VerifyDiagnostics(); @@ -7255,7 +7255,7 @@ public void CoalesceAssignSpanReturn(LanguageVersion languageVersion) class C { Span M() - { + { var x = null ?? new Span(); return x; } @@ -7273,7 +7273,7 @@ public void CoalesceRefSpanReturn(LanguageVersion languageVersion) class C { Span M() - { + { Span x = stackalloc byte[10]; return null ?? x; } @@ -7310,7 +7310,7 @@ public static PooledArrayHandle RentArray(this int length, out T[] array, public static IEnumerable Iterator() { // Verify that the ref struct is usable using var handle = RentArray(200, out var array); - + for (int i = 0; i < array.Length; i++) { yield return i; } @@ -8445,12 +8445,12 @@ int P get => 0; init { - var xyz1 = ReadOnlyVec.Self2(); + var xyz1 = ReadOnlyVec.Self2(); s = new S(xyz1); var d = () => { - var xyz2 = ReadOnlyVec.Self2(); + var xyz2 = ReadOnlyVec.Self2(); s = new S(xyz2); }; @@ -8458,7 +8458,7 @@ int P void local() { - var xyz3 = ReadOnlyVec.Self2(); + var xyz3 = ReadOnlyVec.Self2(); s = new S(xyz3); } } @@ -8931,7 +8931,7 @@ static RS M2(ref RS rs5) M0(ref rs5, out scoped RS rs6); return rs6; // 2 } - + static RS M12(ref RS rs3) { // RSTE of rs3 is ReturnOnly. @@ -8940,7 +8940,7 @@ static RS M12(ref RS rs3) M0(ref rs3, out rs4); return rs4; // 3 } - + static RS M22(ref RS rs5) { // RSTE of rs5 is ReturnOnly. @@ -9384,7 +9384,7 @@ S M6() S s = 300; return s; // 6 } - + void M7(in int x) { scoped S s; @@ -9743,7 +9743,7 @@ .size 1 .method public hidebysig specialname static valuetype S& modreq(System.Runtime.InteropServices.InAttribute) op_Implicit ( [in] int32& x - ) cil managed + ) cil managed { .param [1] .custom instance void System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = ( @@ -10321,7 +10321,7 @@ static void Test() stackLocal += stackLocal; stackLocal += heapLocal; heapLocal += heapLocal; - heapLocal += stackLocal; + heapLocal += stackLocal; } } @@ -10588,7 +10588,7 @@ static R F() { return new R(1) || new R(2); } - + static R F2() { return new R(1) | new R(2); @@ -10634,7 +10634,7 @@ static R F() { return new R(1) || new R(2); } - + static R F2() { return new R(1) | new R(2); @@ -10680,7 +10680,7 @@ static R F() { return new R(1) || new R(2); } - + static R F2() { return new R(1) | new R(2); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticAnalyzerTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticAnalyzerTests.cs index 93ad025784bbc..a0590ad3d72c5 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticAnalyzerTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticAnalyzerTests.cs @@ -450,16 +450,16 @@ static void M() } }"; CreateCompilationWithMscorlib40(source).VerifyDiagnostics( - // (69,28): error CS1110: Cannot define a new extension method because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? + // (69,28): error CS1110: Cannot define a new extension because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? // public static P Select(this P p, Func projection) Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "this").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(69, 28), - // (84,29): error CS1110: Cannot define a new extension method because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? + // (84,29): error CS1110: Cannot define a new extension because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? // public static void PExt(this P p) {} Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "this").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(84, 29), - // (80,33): error CS1110: Cannot define a new extension method because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? + // (80,33): error CS1110: Cannot define a new extension because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? // public static object Select(this Q q, object projection) Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "this").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(80, 33), - // (76,28): error CS1110: Cannot define a new extension method because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? + // (76,28): error CS1110: Cannot define a new extension because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? // public static P Select(this P p, Func projection) Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "this").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(76, 28), // (95,11): error CS0121: The call is ambiguous between the following methods or properties: 'P.Ambiguous(string, object)' and 'P.Ambiguous(object, string)' diff --git a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests_Attributes_SimpleName.cs b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests_Attributes_SimpleName.cs index b0882d7a80536..d588cfd967eca 100644 --- a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests_Attributes_SimpleName.cs +++ b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests_Attributes_SimpleName.cs @@ -549,7 +549,7 @@ class C { } [Fact] public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_OuterAliasReferencesInnerAlias() { - // note: this is not legal. it's ok if this ever stops working in the futuer. + // note: this is not legal. it's ok if this ever stops working in the future. var source = """ using BAttribute = AAttribute; namespace N diff --git a/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelGetSemanticInfoTests.cs b/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelGetSemanticInfoTests.cs index f4f2e6bcdee7b..e23a2130fd8f5 100644 --- a/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelGetSemanticInfoTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelGetSemanticInfoTests.cs @@ -268,21 +268,16 @@ class K "; var semanticInfo = GetSemanticInfoForTest(sourceCode); - Assert.Equal("System.Int32", semanticInfo.Type.ToTestDisplayString()); - Assert.Equal(TypeKind.Struct, semanticInfo.Type.TypeKind); - Assert.Equal("System.Int32", semanticInfo.ConvertedType.ToTestDisplayString()); - Assert.Equal(TypeKind.Struct, semanticInfo.ConvertedType.TypeKind); + Assert.Null(semanticInfo.Type); + Assert.Null(semanticInfo.ConvertedType); Assert.Equal(ConversionKind.Identity, semanticInfo.ImplicitConversion.Kind); Assert.Null(semanticInfo.Symbol); - Assert.Equal(CandidateReason.NotInvocable, semanticInfo.CandidateReason); - Assert.Equal(1, semanticInfo.CandidateSymbols.Length); - var sortedCandidates = semanticInfo.CandidateSymbols.OrderBy(s => s.ToTestDisplayString(), StringComparer.Ordinal).ToArray(); - Assert.Equal("System.Int32 K.f", sortedCandidates[0].ToTestDisplayString()); - Assert.Equal(SymbolKind.Field, sortedCandidates[0].Kind); + Assert.Equal(CandidateReason.None, semanticInfo.CandidateReason); + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : see if we can restore a behavior closer to previous (ie. returning the field as candidate symbol) + Assert.Empty(semanticInfo.CandidateSymbols); Assert.Equal(0, semanticInfo.MethodGroup.Length); - Assert.False(semanticInfo.IsCompileTimeConstant); } diff --git a/src/Compilers/CSharp/Test/Symbol/DocumentationComments/DocumentationCommentCompilerTests.cs b/src/Compilers/CSharp/Test/Symbol/DocumentationComments/DocumentationCommentCompilerTests.cs index a795619ee010d..596f54386b7a9 100644 --- a/src/Compilers/CSharp/Test/Symbol/DocumentationComments/DocumentationCommentCompilerTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/DocumentationComments/DocumentationCommentCompilerTests.cs @@ -1972,9 +1972,9 @@ void verify(CSharpTestSource source) Assert.Equal("p2", indexer.Parameters.Single().Name); }); verifier.VerifyDiagnostics( - // (5,24): warning CS9256: Partial property declarations 'int C.this[int p2]' and 'int C.this[int p1]' have signature differences. + // (5,24): warning CS9256: Partial member declarations 'int C.this[int p2]' and 'int C.this[int p1]' have signature differences. // public partial int this[int p1] => 42; - Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "this").WithArguments("int C.this[int p2]", "int C.this[int p1]").WithLocation(5, 24)); + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "this").WithArguments("int C.this[int p2]", "int C.this[int p1]").WithLocation(5, 24)); var actual = GetDocumentationCommentText(compilation); var expected = """ @@ -2033,9 +2033,9 @@ void verify(CSharpTestSource source) // (4,42): warning CS1734: XML comment on 'C.this[int]' has a paramref tag for 'p2', but there is no parameter by that name // /** Accepts . */ Diagnostic(ErrorCode.WRN_UnmatchedParamRefTag, "p2").WithArguments("p2", "C.this[int]").WithLocation(4, 42), - // (5,24): warning CS9256: Partial property declarations 'int C.this[int p2]' and 'int C.this[int p1]' have signature differences. + // (5,24): warning CS9256: Partial member declarations 'int C.this[int p2]' and 'int C.this[int p1]' have signature differences. // public partial int this[int p1] => 42; - Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "this").WithArguments("int C.this[int p2]", "int C.this[int p1]").WithLocation(5, 24)); + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "this").WithArguments("int C.this[int p2]", "int C.this[int p1]").WithLocation(5, 24)); var actual = GetDocumentationCommentText(compilation, // (4,42): warning CS1734: XML comment on 'C.this[int]' has a paramref tag for 'p2', but there is no parameter by that name @@ -2094,9 +2094,9 @@ void verify(CSharpTestSource source) Assert.Equal("p2", indexer.Parameters.Single().Name); }); verifier.VerifyDiagnostics( - // (4,24): warning CS9256: Partial property declarations 'int C.this[int p2]' and 'int C.this[int p1]' have signature differences. + // (4,24): warning CS9256: Partial member declarations 'int C.this[int p2]' and 'int C.this[int p1]' have signature differences. // public partial int this[int p1] => 42; - Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "this").WithArguments("int C.this[int p2]", "int C.this[int p1]").WithLocation(4, 24), + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "this").WithArguments("int C.this[int p2]", "int C.this[int p1]").WithLocation(4, 24), // (4,42): warning CS1734: XML comment on 'C.this[int]' has a paramref tag for 'p1', but there is no parameter by that name // /** Accepts . */ Diagnostic(ErrorCode.WRN_UnmatchedParamRefTag, "p1").WithArguments("p1", "C.this[int]").WithLocation(4, 42)); @@ -2158,9 +2158,9 @@ void verify(CSharpTestSource source) Assert.Equal("p2", indexer.Parameters.Single().Name); }); verifier.VerifyDiagnostics( - // (4,24): warning CS9256: Partial property declarations 'int C.this[int p2]' and 'int C.this[int p1]' have signature differences. + // (4,24): warning CS9256: Partial member declarations 'int C.this[int p2]' and 'int C.this[int p1]' have signature differences. // public partial int this[int p1] => 42; - Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "this").WithArguments("int C.this[int p2]", "int C.this[int p1]").WithLocation(4, 24)); + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "this").WithArguments("int C.this[int p2]", "int C.this[int p1]").WithLocation(4, 24)); var actual = GetDocumentationCommentText(compilation); var expected = """ @@ -2180,6 +2180,1061 @@ void verify(CSharpTestSource source) } } + [Fact] + public void PartialEvent_NoImplementation() + { + var source = """ + public partial class C + { + /** Summary 1 */ + public partial event System.Action E; + } + """; + var comp = CreateCompilation(source, + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics( + // (1,22): warning CS1591: Missing XML comment for publicly visible type or member 'C' + // public partial class C + Diagnostic(ErrorCode.WRN_MissingXMLComment, "C").WithArguments("C").WithLocation(1, 22), + // (4,40): error CS9275: Partial member 'C.E' must have an implementation part. + // public partial event System.Action E; + Diagnostic(ErrorCode.ERR_PartialMemberMissingImplementation, "E").WithArguments("C.E").WithLocation(4, 40)); + var e = comp.GlobalNamespace.GetMember("C.E"); + + AssertEx.AssertEqualToleratingWhitespaceDifferences(""" + + + + Test + + + + + """, GetDocumentationCommentText(comp, + // (1,22): warning CS1591: Missing XML comment for publicly visible type or member 'C' + // public partial class C + Diagnostic(ErrorCode.WRN_MissingXMLComment, "C").WithArguments("C").WithLocation(1, 22))); + + AssertEx.AssertEqualToleratingWhitespaceDifferences(""" + + Summary 1 + + """, DocumentationCommentCompiler.GetDocumentationCommentXml(e, processIncludes: true, cancellationToken: default)); + } + + [Fact] + public void PartialConstructor_NoImplementation() + { + var source = """ + public partial class C + { + /** Summary 1 */ + public partial C(); + } + """; + var comp = CreateCompilation(source, + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics( + // (1,22): warning CS1591: Missing XML comment for publicly visible type or member 'C' + // public partial class C + Diagnostic(ErrorCode.WRN_MissingXMLComment, "C").WithArguments("C").WithLocation(1, 22), + // (4,20): error CS9275: Partial member 'C.C()' must have an implementation part. + // public partial C(); + Diagnostic(ErrorCode.ERR_PartialMemberMissingImplementation, "C").WithArguments("C.C()").WithLocation(4, 20)); + var ctor = comp.GlobalNamespace.GetMember("C..ctor"); + + AssertEx.AssertEqualToleratingWhitespaceDifferences(""" + + + + Test + + + + + """, GetDocumentationCommentText(comp, + // (1,22): warning CS1591: Missing XML comment for publicly visible type or member 'C' + // public partial class C + Diagnostic(ErrorCode.WRN_MissingXMLComment, "C").WithArguments("C").WithLocation(1, 22))); + + AssertEx.AssertEqualToleratingWhitespaceDifferences(""" + + Summary 1 + + """, DocumentationCommentCompiler.GetDocumentationCommentXml(ctor, processIncludes: true, cancellationToken: default)); + } + + [Fact] + public void PartialEvent_MultipleFiles() + { + var source1 = """ + /** Summary 0 */ + public partial class C + { + /** Summary 1 */ + public partial event System.Action E; + } + """; + var source2 = """ + public partial class C + { + /** Summary 2 */ + public partial event System.Action E { add { } remove { } } + } + """; + + var expected = """ + + + + Test + + + + Summary 0 + + + Summary 2 + + + + """; + + var comp = CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + comp = CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + } + + [Fact] + public void PartialEvent_MultipleFiles_ImplementationComment() + { + var source1 = """ + /** Summary 0 */ + public partial class C + { + public partial event System.Action E; + } + """; + var source2 = """ + public partial class C + { + /** Summary 2 */ + public partial event System.Action E { add { } remove { } } + } + """; + + var expected = """ + + + + Test + + + + Summary 0 + + + Summary 2 + + + + """; + + var comp = CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + comp = CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + } + + [Fact] + public void PartialEvent_MultipleFiles_DefinitionComment() + { + var source1 = """ + /** Summary 0 */ + public partial class C + { + /** Summary 1 */ + public partial event System.Action E; + } + """; + var source2 = """ + public partial class C + { + public partial event System.Action E { add { } remove { } } + } + """; + + var expected = """ + + + + Test + + + + Summary 0 + + + Summary 1 + + + + """; + + var comp = CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + comp = CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + } + + [Fact] + public void PartialConstructor_MultipleFiles() + { + var source1 = """ + /** Summary 0 */ + public partial class C + { + /** Summary 1 */ + public partial C(); + } + """; + var source2 = """ + public partial class C + { + /** Summary 2 */ + public partial C() { } + } + """; + + var expected = """ + + + + Test + + + + Summary 0 + + + Summary 2 + + + + """; + + var comp = CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + comp = CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + } + + [Fact] + public void PartialConstructor_MultipleFiles_ImplementationComment() + { + var source1 = """ + /** Summary 0 */ + public partial class C + { + public partial C(); + } + """; + var source2 = """ + public partial class C + { + /** Summary 2 */ + public partial C() { } + } + """; + + var expected = """ + + + + Test + + + + Summary 0 + + + Summary 2 + + + + """; + + var comp = CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + comp = CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + } + + [Fact] + public void PartialConstructor_MultipleFiles_DefinitionComment() + { + var source1 = """ + /** Summary 0 */ + public partial class C + { + /** Summary 1 */ + public partial C(); + } + """; + var source2 = """ + public partial class C + { + public partial C() { } + } + """; + + var expected = """ + + + + Test + + + + Summary 0 + + + Summary 1 + + + + """; + + var comp = CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + comp = CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + } + + [Fact] + public void PartialEvent_MultipleFiles_NoComment() + { + var source1 = """ + /** Summary 0 */ + public partial class C + { + public partial event System.Action E; + } + """; + var source2 = """ + public partial class C + { + public partial event System.Action E { add { } remove { } } + } + """; + + var expected = """ + + + + Test + + + + Summary 0 + + + + """; + + var expectedDiagnostics = new[] + { + // (4,40): warning CS1591: Missing XML comment for publicly visible type or member 'C.E' + // public partial event System.Action E; + Diagnostic(ErrorCode.WRN_MissingXMLComment, "E").WithArguments("C.E").WithLocation(4, 40) + }; + + var comp = CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(expectedDiagnostics); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp, expectedDiagnostics)); + + comp = CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(expectedDiagnostics); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp, expectedDiagnostics)); + } + + [Fact] + public void PartialConstructor_MultipleFiles_NoComment() + { + var source1 = """ + /** Summary 0 */ + public partial class C + { + public partial C(); + } + """; + var source2 = """ + public partial class C + { + public partial C() { } + } + """; + + var expected = """ + + + + Test + + + + Summary 0 + + + + """; + + var expectedDiagnostics = new[] + { + // (4,20): warning CS1591: Missing XML comment for publicly visible type or member 'C.C()' + // public partial C(); + Diagnostic(ErrorCode.WRN_MissingXMLComment, "C").WithArguments("C.C()").WithLocation(4, 20) + }; + + var comp = CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(expectedDiagnostics); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp, expectedDiagnostics)); + + comp = CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(expectedDiagnostics); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp, expectedDiagnostics)); + } + + [Fact] + public void PartialEvent_MultipleFiles_Overlap() + { + var source1 = """ + partial class C + { + /** Summary 1 */ + public partial event System.Action E; + } + """; + var source2 = """ + partial class C + { + /** Remarks 2 */ + public partial event System.Action E { add { } remove { } } + } + """; + + var expected = """ + + + + Test + + + + Remarks 2 + + + + """; + + var comp = CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + comp = CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + } + + [Fact] + public void PartialConstructor_MultipleFiles_Overlap() + { + var source1 = """ + partial class C + { + /// Summary 1 + /// Param 1 + public partial C(int x, int y); + } + """; + var source2 = """ + partial class C + { + /// Remarks 2 + /// Param 2 + public partial C(int x, int y) { } + } + """; + + var expected = """ + + + + Test + + + + Remarks 2 + Param 2 + + + + """; + + var expectedDiagnostics = new[] + { + // (5,26): warning CS1573: Parameter 'x' has no matching param tag in the XML comment for 'C.C(int, int)' (but other parameters do) + // public partial C(int x, int y) { } + Diagnostic(ErrorCode.WRN_MissingParamTag, "x").WithArguments("x", "C.C(int, int)").WithLocation(5, 26), + // (5,33): warning CS1573: Parameter 'y' has no matching param tag in the XML comment for 'C.C(int, int)' (but other parameters do) + // public partial C(int x, int y); + Diagnostic(ErrorCode.WRN_MissingParamTag, "y").WithArguments("y", "C.C(int, int)").WithLocation(5, 33) + }; + + var comp = CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(expectedDiagnostics); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp, expectedDiagnostics)); + + comp = CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(expectedDiagnostics); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp, expectedDiagnostics)); + } + + [Fact] + public void PartialEvent_MultipleFiles_InvalidImplComment() + { + var source1 = """ + partial class C + { + /** Summary 1 */ + public partial event System.Action E; + } + """; + var source2 = """ + partial class C + { + /** */ + public partial event System.Action E { add { } remove { } } + } + """; + + var expected = """ + + + + Test + + + + + + """; + + var expectedDiagnostics = new[] + { + // (3,20): warning CS1570: XML comment has badly formed XML -- 'End tag 'a' does not match the start tag 'summary'.' + // /** */ + Diagnostic(ErrorCode.WRN_XMLParseError, "a").WithArguments("a", "summary").WithLocation(3, 20), + // (3,22): warning CS1570: XML comment has badly formed XML -- 'End tag was not expected at this location.' + // /** */ + Diagnostic(ErrorCode.WRN_XMLParseError, "<").WithLocation(3, 22) + }; + + var comp = CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(expectedDiagnostics); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + comp = CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(expectedDiagnostics); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + } + + [Fact] + public void PartialConstructor_MultipleFiles_InvalidImplComment() + { + var source1 = """ + partial class C + { + /** Summary 1 */ + public partial C(); + } + """; + var source2 = """ + partial class C + { + /** */ + public partial C() { } + } + """; + + var expected = """ + + + + Test + + + + + + """; + + var expectedDiagnostics = new[] + { + // (3,20): warning CS1570: XML comment has badly formed XML -- 'End tag 'a' does not match the start tag 'summary'.' + // /** */ + Diagnostic(ErrorCode.WRN_XMLParseError, "a").WithArguments("a", "summary").WithLocation(3, 20), + // (3,22): warning CS1570: XML comment has badly formed XML -- 'End tag was not expected at this location.' + // /** */ + Diagnostic(ErrorCode.WRN_XMLParseError, "<").WithLocation(3, 22) + }; + + var comp = CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(expectedDiagnostics); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + comp = CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(expectedDiagnostics); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + } + + [Fact] + public void PartialEvent_MultipleFiles_InvalidDefComment() + { + var source1 = """ + partial class C + { + /** */ + public partial event System.Action E; + } + """; + var source2 = """ + partial class C + { + /** Summary 2 */ + public partial event System.Action E { add { } remove { } } + } + """; + + var expected = """ + + + + Test + + + + Summary 2 + + + + + """; + + var expectedDiagnostics = new[] + { + // (3,20): warning CS1570: XML comment has badly formed XML -- 'End tag 'a' does not match the start tag 'summary'.' + // /** */ + Diagnostic(ErrorCode.WRN_XMLParseError, "a").WithArguments("a", "summary").WithLocation(3, 20), + // (3,22): warning CS1570: XML comment has badly formed XML -- 'End tag was not expected at this location.' + // /** */ + Diagnostic(ErrorCode.WRN_XMLParseError, "<").WithLocation(3, 22) + }; + + var comp = CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(expectedDiagnostics); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + comp = CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(expectedDiagnostics); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + } + + [Fact] + public void PartialConstructor_MultipleFiles_InvalidDefComment() + { + var source1 = """ + partial class C + { + /** */ + public partial C(); + } + """; + var source2 = """ + partial class C + { + /** Summary 2 */ + public partial C() { } + } + """; + + var expected = """ + + + + Test + + + + Summary 2 + + + + + """; + + var expectedDiagnostics = new[] + { + // (3,20): warning CS1570: XML comment has badly formed XML -- 'End tag 'a' does not match the start tag 'summary'.' + // /** */ + Diagnostic(ErrorCode.WRN_XMLParseError, "a").WithArguments("a", "summary").WithLocation(3, 20), + // (3,22): warning CS1570: XML comment has badly formed XML -- 'End tag was not expected at this location.' + // /** */ + Diagnostic(ErrorCode.WRN_XMLParseError, "<").WithLocation(3, 22) + }; + + var comp = CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(expectedDiagnostics); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + comp = CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(expectedDiagnostics); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + } + + [Fact] + public void PartialConstructor_Paramref_01() + { + var source1 = """ + partial class C + { + /** Accepts . */ + public partial C(int p1) { } + } + """; + var source2 = """ + partial class C + { + public partial C(int p2); + } + """; + + var expected = """ + + + + Test + + + + Accepts . + + + + """; + + var expectedDiagnostics = new[] + { + // (4,20): warning CS9256: Partial member declarations 'C.C(int p2)' and 'C.C(int p1)' have signature differences. + // public partial C(int p1) { } + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "C").WithArguments("C.C(int p2)", "C.C(int p1)").WithLocation(4, 20) + }; + + var comp = (CSharpCompilation)CompileAndVerify(CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments), + sourceSymbolValidator: validate, + symbolValidator: validate) + .VerifyDiagnostics(expectedDiagnostics).Compilation; + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + comp = (CSharpCompilation)CompileAndVerify(CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments), + sourceSymbolValidator: validate, + symbolValidator: validate) + .VerifyDiagnostics(expectedDiagnostics).Compilation; + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + static void validate(ModuleSymbol module) + { + var ctor = module.GlobalNamespace.GetMember("C..ctor"); + Assert.Equal("p2", ctor.Parameters.Single().Name); + } + } + + [Fact] + public void PartialConstructor_Paramref_02() + { + var source1 = """ + partial class C + { + /** Accepts . */ + public partial C(int p1) { } + } + """; + var source2 = """ + partial class C + { + public partial C(int p2); + } + """; + + var expected = """ + + + + Test + + + + Accepts . + + + + """; + + var expectedXmlDiagnostic = + // (3,42): warning CS1734: XML comment on 'C.C(int)' has a paramref tag for 'p2', but there is no parameter by that name + // /** Accepts . */ + Diagnostic(ErrorCode.WRN_UnmatchedParamRefTag, "p2").WithArguments("p2", "C.C(int)").WithLocation(3, 42); + + var expectedDiagnostics = new[] + { + expectedXmlDiagnostic, + // (4,20): warning CS9256: Partial member declarations 'C.C(int p2)' and 'C.C(int p1)' have signature differences. + // public partial C(int p1) { } + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "C").WithArguments("C.C(int p2)", "C.C(int p1)").WithLocation(4, 20) + }; + + var comp = (CSharpCompilation)CompileAndVerify(CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments), + sourceSymbolValidator: validate, + symbolValidator: validate) + .VerifyDiagnostics(expectedDiagnostics).Compilation; + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp, expectedXmlDiagnostic)); + + comp = (CSharpCompilation)CompileAndVerify(CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments), + sourceSymbolValidator: validate, + symbolValidator: validate) + .VerifyDiagnostics(expectedDiagnostics).Compilation; + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp, expectedXmlDiagnostic)); + + static void validate(ModuleSymbol module) + { + var ctor = module.GlobalNamespace.GetMember("C..ctor"); + Assert.Equal("p2", ctor.Parameters.Single().Name); + } + } + + [Fact] + public void PartialConstructor_Paramref_03() + { + var source1 = """ + partial class C + { + public partial C(int p1) { } + } + """; + var source2 = """ + partial class C + { + /** Accepts . */ + public partial C(int p2); + } + """; + + var expected = """ + + + + Test + + + + Accepts . + + + + """; + + var expectedXmlDiagnostic = + // (3,42): warning CS1734: XML comment on 'C.C(int)' has a paramref tag for 'p1', but there is no parameter by that name + // /** Accepts . */ + Diagnostic(ErrorCode.WRN_UnmatchedParamRefTag, "p1").WithArguments("p1", "C.C(int)").WithLocation(3, 42); + + var expectedDiagnostics = new[] + { + // (3,20): warning CS9256: Partial member declarations 'C.C(int p2)' and 'C.C(int p1)' have signature differences. + // public partial C(int p1) { } + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "C").WithArguments("C.C(int p2)", "C.C(int p1)").WithLocation(3, 20), + expectedXmlDiagnostic + }; + + var comp = (CSharpCompilation)CompileAndVerify(CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments), + sourceSymbolValidator: validate, + symbolValidator: validate) + .VerifyDiagnostics(expectedDiagnostics).Compilation; + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp, expectedXmlDiagnostic)); + + comp = (CSharpCompilation)CompileAndVerify(CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments), + sourceSymbolValidator: validate, + symbolValidator: validate) + .VerifyDiagnostics(expectedDiagnostics).Compilation; + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp, expectedXmlDiagnostic)); + + static void validate(ModuleSymbol module) + { + var ctor = module.GlobalNamespace.GetMember("C..ctor"); + Assert.Equal("p2", ctor.Parameters.Single().Name); + } + } + + [Fact] + public void PartialConstructor_Paramref_04() + { + var source1 = """ + partial class C + { + public partial C(int p1) { } + } + """; + var source2 = """ + partial class C + { + /** Accepts . */ + public partial C(int p2); + } + """; + + var expected = """ + + + + Test + + + + Accepts . + + + + """; + + var expectedDiagnostics = new[] + { + // (3,20): warning CS9256: Partial member declarations 'C.C(int p2)' and 'C.C(int p1)' have signature differences. + // public partial C(int p1) { } + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "C").WithArguments("C.C(int p2)", "C.C(int p1)").WithLocation(3, 20) + }; + + var comp = (CSharpCompilation)CompileAndVerify(CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments), + sourceSymbolValidator: validate, + symbolValidator: validate) + .VerifyDiagnostics(expectedDiagnostics).Compilation; + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + comp = (CSharpCompilation)CompileAndVerify(CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments), + sourceSymbolValidator: validate, + symbolValidator: validate) + .VerifyDiagnostics(expectedDiagnostics).Compilation; + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + static void validate(ModuleSymbol module) + { + var ctor = module.GlobalNamespace.GetMember("C..ctor"); + Assert.Equal("p2", ctor.Parameters.Single().Name); + } + } + #endregion Partial methods #region Crefs diff --git a/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs b/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs index add91eb5d5684..a234d69049153 100644 --- a/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs @@ -2164,6 +2164,121 @@ class C { SymbolDisplayPartKind.Keyword); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/77219")] + public void TestPropertyBackingField_Minimal_01() + { + var text = @" +#nullable enable +class C { + string P { get; set; } } +"; + + Func findSymbol = global => + global.GetTypeMembers("C", 0).Single(). + GetMembers("

k__BackingField").Single(); + + var format = new SymbolDisplayFormat( + memberOptions: + SymbolDisplayMemberOptions.IncludeExplicitInterface); + + TestSymbolDescription( + text, + findSymbol, + format, + "P.field", + SymbolDisplayPartKind.PropertyName, + SymbolDisplayPartKind.Punctuation, + SymbolDisplayPartKind.Keyword); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/77219")] + public void TestPropertyBackingField_Minimal_02() + { + var text = @" +#nullable enable + +interface I { + string P { get; set; } +} + +class C : I { + string I.P { get; set; } } +"; + + Func findSymbol = global => + global.GetTypeMembers("C", 0).Single(). + GetMembers("k__BackingField").Single(); + + var format = new SymbolDisplayFormat( + memberOptions: + SymbolDisplayMemberOptions.IncludeExplicitInterface); + + TestSymbolDescription( + text, + findSymbol, + format, + "I.P.field", + SymbolDisplayPartKind.InterfaceName, + SymbolDisplayPartKind.Punctuation, + SymbolDisplayPartKind.PropertyName, + SymbolDisplayPartKind.Punctuation, + SymbolDisplayPartKind.Keyword); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/77219")] + public void TestPropertyBackingField_Minimal_03() + { + var text = @" +#nullable enable + +interface I { + string P { get; set; } +} + +class C : I { + string I.P { get; set; } } +"; + + Func findSymbol = global => + global.GetTypeMembers("C", 0).Single(). + GetMembers("k__BackingField").Single(); + + var format = new SymbolDisplayFormat(); + + TestSymbolDescription( + text, + findSymbol, + format, + "P.field", + SymbolDisplayPartKind.PropertyName, + SymbolDisplayPartKind.Punctuation, + SymbolDisplayPartKind.Keyword); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/77219")] + public void TestOrdinaryField_Minimal() + { + var text = @" +#nullable enable + +class C { + string F; +"; + + Func findSymbol = global => + global.GetTypeMembers("C", 0).Single(). + GetMembers("F").Single(); + + var format = new SymbolDisplayFormat(); + + TestSymbolDescription( + text, + findSymbol, + format, + "F", + SymbolDisplayPartKind.FieldName); + } + [Fact] public void TestPropertyBackingFieldFromCompilationReference() { diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/CheckedUserDefinedOperatorsTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/CheckedUserDefinedOperatorsTests.cs index 623e811368be4..94f09cc169da0 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/CheckedUserDefinedOperatorsTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/CheckedUserDefinedOperatorsTests.cs @@ -2016,7 +2016,7 @@ class C [InlineData("-")] [InlineData("*")] [InlineData("/")] - public void BinarOperator_Supported_CRef_TwoParameters_03(string op) + public void BinaryOperator_Supported_CRef_TwoParameters_03(string op) { var source = @" ///

diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/ConversionTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/ConversionTests.cs index ee425b79b53d3..9d38781e3e73e 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/ConversionTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/ConversionTests.cs @@ -525,7 +525,7 @@ public static implicit operator C(System.Func intDelegate) } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75833")] - public void GetSymbolInfo_ImplicitUserDefinedConversionOnMethodGroup_InAssignemnt() + public void GetSymbolInfo_ImplicitUserDefinedConversionOnMethodGroup_InAssignment() { var src = """ public class C diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs index 28b8ca9a92740..e27380e19f546 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs @@ -44585,30 +44585,36 @@ interface I19 // (62,20): error CS0106: The modifier 'virtual' is not valid for this item // virtual static I13() => throw null; Diagnostic(ErrorCode.ERR_BadMemberFlag, "I13").WithArguments("virtual").WithLocation(62, 20), - // (66,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // (66,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. // partial static I14(); Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(66, 5), - // (66,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // (66,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. // partial static I14(); Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(66, 5), // (70,12): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) // static partial I15(); Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(70, 12), + // (70,12): error CS8652: The feature 'partial events and constructors' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static partial I15(); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "partial").WithArguments("partial events and constructors").WithLocation(70, 12), // (70,20): error CS0501: 'I15.I15()' must declare a body because it is not marked abstract, extern, or partial // static partial I15(); Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "I15").WithArguments("I15.I15()").WithLocation(70, 20), // (70,20): error CS0542: 'I15': member names cannot be the same as their enclosing type // static partial I15(); Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "I15").WithArguments("I15").WithLocation(70, 20), - // (74,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // (74,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. // partial static I16() {} Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(74, 5), - // (74,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // (74,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. // partial static I16() {} Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(74, 5), // (78,12): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) // static partial I17() => throw null; Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(78, 12), + // (78,12): error CS8652: The feature 'partial events and constructors' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static partial I17() => throw null; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "partial").WithArguments("partial events and constructors").WithLocation(78, 12), // (78,20): error CS0542: 'I17': member names cannot be the same as their enclosing type // static partial I17() => throw null; Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "I17").WithArguments("I17").WithLocation(78, 20), diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/ExtensionMethodTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/ExtensionMethodTests.cs index 2efaa17455327..6ea09a1ce0553 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/ExtensionMethodTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/ExtensionMethodTests.cs @@ -432,9 +432,9 @@ static void Goo(this string x) { } // (9,18): error CS0837: The first operand of an 'is' or 'as' operator may not be a lambda expression, anonymous method, or method group. // bool x = s.Goo is Action; Diagnostic(ErrorCode.ERR_LambdaInIsAs, "s.Goo is Action").WithLocation(9, 18), - // (12,18): error CS0837: The first operand of an 'is' or 'as' operator may not be a lambda expression, anonymous method, or method group. + // (12,20): error CS1061: 'int' does not contain a definition for 'Goo' and no accessible extension method 'Goo' accepting a first argument of type 'int' could be found (are you missing a using directive or an assembly reference?) // bool y = i.Goo is Action; - Diagnostic(ErrorCode.ERR_LambdaInIsAs, "i.Goo is Action").WithLocation(12, 18), + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Goo").WithArguments("int", "Goo").WithLocation(12, 20), // (9,18): error CS0165: Use of unassigned local variable 's' // bool x = s.Goo is Action; Diagnostic(ErrorCode.ERR_UseDefViolation, "s").WithArguments("s").WithLocation(9, 18), @@ -2204,7 +2204,7 @@ private static void Main(string[] args) { } "; var compilation = CreateEmptyCompilation(source, new[] { Net40.References.mscorlib }); compilation.VerifyDiagnostics( - // (4,29): error CS1110: Cannot define a new extension method because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? + // (4,29): error CS1110: Cannot define a new extension because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "this").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(4, 29)); } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs index 2bbfa4d5d2c05..93d304d2e2f8a 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs @@ -126,7 +126,7 @@ public static void Extension(this string x) {} comp.MakeMemberMissing(WellKnownMember.System_Diagnostics_DebuggerHiddenAttribute__ctor); comp.VerifyEmitDiagnostics( - // (9,34): error CS1110: Cannot define a new extension method because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? + // (9,34): error CS1110: Cannot define a new extension because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? // public static void Extension(this string x) {} Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "this").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(9, 34) ); @@ -1668,7 +1668,7 @@ struct S private string str; public S(char chr) { this.str = chr.ToString(); } public S(string str) { this.str = str; } - public static S operator + (S x, S y) { return new S('(' + x.str + '+' + y.str + ')'); } + public static S operator + (S x, S y) { return new S('(' + x.str + '+' + y.str); } } class C diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/MockNamedTypeSymbol.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/MockNamedTypeSymbol.cs index 854eed416473e..924559fed5860 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/MockNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/MockNamedTypeSymbol.cs @@ -201,6 +201,9 @@ public sealed override bool IsRefLikeType } } + internal override string ExtensionName + => throw ExceptionUtilities.Unreachable(); + public sealed override bool IsReadOnly { get @@ -335,6 +338,7 @@ internal override AttributeUsageInfo GetAttributeUsageInfo() internal override bool IsRecordStruct => false; internal override bool HasPossibleWellKnownCloneMethod() => false; internal override bool IsInterpolatedStringHandlerType => false; + internal sealed override ParameterSymbol ExtensionParameter => null; internal sealed override IEnumerable<(MethodSymbol Body, MethodSymbol Implemented)> SynthesizedInterfaceMethodImpls() { diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/PartialPropertiesTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/PartialPropertiesTests.cs index 6673e386e5806..fe5ee45ce77a6 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/PartialPropertiesTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/PartialPropertiesTests.cs @@ -1552,15 +1552,15 @@ partial class C """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (6,20): error CS9255: Both partial property declarations must have the same type. + // (6,20): error CS9255: Both partial member declarations must have the same type. // partial string P1 { get => ""; set { } } - Diagnostic(ErrorCode.ERR_PartialPropertyTypeDifference, "P1").WithLocation(6, 20), - // (9,26): error CS9255: Both partial property declarations must have the same type. + Diagnostic(ErrorCode.ERR_PartialMemberTypeDifference, "P1").WithLocation(6, 20), + // (9,26): error CS9255: Both partial member declarations must have the same type. // partial List P2 { get => []; set { } } - Diagnostic(ErrorCode.ERR_PartialPropertyTypeDifference, "P2").WithLocation(9, 26), - // (12,33): error CS9255: Both partial property declarations must have the same type. + Diagnostic(ErrorCode.ERR_PartialMemberTypeDifference, "P2").WithLocation(9, 26), + // (12,33): error CS9255: Both partial member declarations must have the same type. // partial IEnumerable P3 { get => []; set { } } - Diagnostic(ErrorCode.ERR_PartialPropertyTypeDifference, "P3").WithLocation(12, 33)); + Diagnostic(ErrorCode.ERR_PartialMemberTypeDifference, "P3").WithLocation(12, 33)); } [Fact] @@ -1585,18 +1585,18 @@ partial class C """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (5,20): error CS9256: Partial property declarations 'string? C.P1' and 'string C.P1' have signature differences. + // (5,20): error CS9256: Partial member declarations 'string? C.P1' and 'string C.P1' have signature differences. // partial string P1 { get => ""; set { } } - Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "P1").WithArguments("string? C.P1", "string C.P1").WithLocation(5, 20), - // (8,21): error CS9256: Partial property declarations 'string C.P2' and 'string? C.P2' have signature differences. + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "P1").WithArguments("string? C.P1", "string C.P1").WithLocation(5, 20), + // (8,21): error CS9256: Partial member declarations 'string C.P2' and 'string? C.P2' have signature differences. // partial string? P2 { get => ""; set { } } - Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "P2").WithArguments("string C.P2", "string? C.P2").WithLocation(8, 21), - // (11,22): error CS9256: Partial property declarations 'string?[] C.P3' and 'string[] C.P3' have signature differences. + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "P2").WithArguments("string C.P2", "string? C.P2").WithLocation(8, 21), + // (11,22): error CS9256: Partial member declarations 'string?[] C.P3' and 'string[] C.P3' have signature differences. // partial string[] P3 { get => []; set { } } - Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "P3").WithArguments("string?[] C.P3", "string[] C.P3").WithLocation(11, 22), - // (14,23): error CS9256: Partial property declarations 'string[] C.P4' and 'string?[] C.P4' have signature differences. + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "P3").WithArguments("string?[] C.P3", "string[] C.P3").WithLocation(11, 22), + // (14,23): error CS9256: Partial member declarations 'string[] C.P4' and 'string?[] C.P4' have signature differences. // partial string?[] P4 { get => []; set { } } - Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "P4").WithArguments("string[] C.P4", "string?[] C.P4").WithLocation(14, 23)); + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "P4").WithArguments("string[] C.P4", "string?[] C.P4").WithLocation(14, 23)); } [Fact] @@ -1623,12 +1623,12 @@ partial class C var comp = CreateCompilation(source, options: TestOptions.DebugDll.WithNullableContextOptions(NullableContextOptions.Enable)); comp.VerifyEmitDiagnostics( - // (4,27): warning CS9256: Partial property declarations 'string? C.P1' and 'string C.P1' have signature differences. + // (4,27): warning CS9256: Partial member declarations 'string? C.P1' and 'string C.P1' have signature differences. // public partial string P1 { get => ""; set { } } - Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "P1").WithArguments("string? C.P1", "string C.P1").WithLocation(4, 27), - // (7,28): warning CS9256: Partial property declarations 'string C.P2' and 'string? C.P2' have signature differences. + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "P1").WithArguments("string? C.P1", "string C.P1").WithLocation(4, 27), + // (7,28): warning CS9256: Partial member declarations 'string C.P2' and 'string? C.P2' have signature differences. // public partial string? P2 { get => ""; set { } } - Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "P2").WithArguments("string C.P2", "string? C.P2").WithLocation(7, 28), + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "P2").WithArguments("string C.P2", "string? C.P2").WithLocation(7, 28), // (10,27): warning CS8826: Partial method declarations 'string? C.M1()' and 'string C.M1()' have signature differences. // public partial string M1() => ""; Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "M1").WithArguments("string? C.M1()", "string C.M1()").WithLocation(10, 27), @@ -1638,12 +1638,12 @@ partial class C comp = CreateCompilation(source, options: TestOptions.DebugDll.WithNullableContextOptions(NullableContextOptions.Annotations)); comp.VerifyEmitDiagnostics( - // (4,27): warning CS9256: Partial property declarations 'string? C.P1' and 'string C.P1' have signature differences. + // (4,27): warning CS9256: Partial member declarations 'string? C.P1' and 'string C.P1' have signature differences. // public partial string P1 { get => ""; set { } } - Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "P1").WithArguments("string? C.P1", "string C.P1").WithLocation(4, 27), - // (7,28): warning CS9256: Partial property declarations 'string C.P2' and 'string? C.P2' have signature differences. + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "P1").WithArguments("string? C.P1", "string C.P1").WithLocation(4, 27), + // (7,28): warning CS9256: Partial member declarations 'string C.P2' and 'string? C.P2' have signature differences. // public partial string? P2 { get => ""; set { } } - Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "P2").WithArguments("string C.P2", "string? C.P2").WithLocation(7, 28), + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "P2").WithArguments("string C.P2", "string? C.P2").WithLocation(7, 28), // (10,27): warning CS8826: Partial method declarations 'string? C.M1()' and 'string C.M1()' have signature differences. // public partial string M1() => ""; Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "M1").WithArguments("string? C.M1()", "string C.M1()").WithLocation(10, 27)); @@ -1734,24 +1734,24 @@ void Usage() var verifier = CompileAndVerify(source, symbolValidator: verify, sourceSymbolValidator: verify); verifier.VerifyDiagnostics( - // (5,28): warning CS9256: Partial property declarations 'string C.this[string? x]' and 'string? C.this[string x]' have signature differences. + // (5,28): warning CS9256: Partial member declarations 'string C.this[string? x]' and 'string? C.this[string x]' have signature differences. // public partial string? this[string x] // 1 - Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "this").WithArguments("string C.this[string? x]", "string? C.this[string x]").WithLocation(5, 28), - // (12,27): warning CS9256: Partial property declarations 'string? C.this[string x, bool ignored]' and 'string C.this[string? x, bool ignored]' have signature differences. + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "this").WithArguments("string C.this[string? x]", "string? C.this[string x]").WithLocation(5, 28), + // (12,27): warning CS9256: Partial member declarations 'string? C.this[string x, bool ignored]' and 'string C.this[string? x, bool ignored]' have signature differences. // public partial string this[string? x, bool ignored] // 2 - Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "this").WithArguments("string? C.this[string x, bool ignored]", "string C.this[string? x, bool ignored]").WithLocation(12, 27), + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "this").WithArguments("string? C.this[string x, bool ignored]", "string C.this[string? x, bool ignored]").WithLocation(12, 27), // (14,16): warning CS8602: Dereference of a possibly null reference. // get => x.ToString(); // 3 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(14, 16), // (15,16): warning CS8602: Dereference of a possibly null reference. // set => x.ToString(); // 4 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(15, 16), - // (19,28): warning CS9256: Partial property declarations 'string C.this[bool ignored]' and 'string? C.this[bool ignored]' have signature differences. + // (19,28): warning CS9256: Partial member declarations 'string C.this[bool ignored]' and 'string? C.this[bool ignored]' have signature differences. // public partial string? this[bool ignored] // 5 - Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "this").WithArguments("string C.this[bool ignored]", "string? C.this[bool ignored]").WithLocation(19, 28), - // (25,27): warning CS9256: Partial property declarations 'string? C.this[int ignored]' and 'string C.this[int ignored]' have signature differences. + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "this").WithArguments("string C.this[bool ignored]", "string? C.this[bool ignored]").WithLocation(19, 28), + // (25,27): warning CS9256: Partial member declarations 'string? C.this[int ignored]' and 'string C.this[int ignored]' have signature differences. // public partial string this[int ignored] // 6 - Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "this").WithArguments("string? C.this[int ignored]", "string C.this[int ignored]").WithLocation(25, 27), + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "this").WithArguments("string? C.this[int ignored]", "string C.this[int ignored]").WithLocation(25, 27), // (27,16): warning CS8603: Possible null reference return. // get => null; // 7 Diagnostic(ErrorCode.WRN_NullReferenceReturn, "null").WithLocation(27, 16), @@ -1913,9 +1913,9 @@ partial class C var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (6,52): error CS9255: Both partial property declarations must have the same type. + // (6,52): error CS9255: Both partial member declarations must have the same type. // public partial ref readonly (long x, string y) Prop => throw null!; - Diagnostic(ErrorCode.ERR_PartialPropertyTypeDifference, "Prop").WithLocation(6, 52), + Diagnostic(ErrorCode.ERR_PartialMemberTypeDifference, "Prop").WithLocation(6, 52), // (6,52): error CS8818: Partial member declarations must have matching ref return values. // public partial ref readonly (long x, string y) Prop => throw null!; Diagnostic(ErrorCode.ERR_PartialMemberRefReturnDifference, "Prop").WithLocation(6, 52)); @@ -2411,9 +2411,9 @@ partial class C var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (15,26): error CS9255: Both partial property declarations must have the same type. + // (15,26): error CS9255: Both partial member declarations must have the same type. // public partial MyInt P3 { get => 3; set { } } - Diagnostic(ErrorCode.ERR_PartialPropertyTypeDifference, "P3").WithLocation(15, 26)); + Diagnostic(ErrorCode.ERR_PartialMemberTypeDifference, "P3").WithLocation(15, 26)); } [Fact] @@ -2779,9 +2779,9 @@ partial class C var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (5,24): warning CS9256: Partial property declarations 'int C.this[string s]' and 'int C.this[string? s]' have signature differences. + // (5,24): warning CS9256: Partial member declarations 'int C.this[string s]' and 'int C.this[string? s]' have signature differences. // public partial int this[string? s] { get => 1; set { } } - Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "this").WithArguments("int C.this[string s]", "int C.this[string? s]").WithLocation(5, 24)); + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "this").WithArguments("int C.this[string s]", "int C.this[string? s]").WithLocation(5, 24)); } [Fact] @@ -2798,9 +2798,9 @@ partial class C var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (5,24): warning CS9256: Partial property declarations 'int C.this[dynamic[] s]' and 'int C.this[object[] s]' have signature differences. + // (5,24): warning CS9256: Partial member declarations 'int C.this[dynamic[] s]' and 'int C.this[object[] s]' have signature differences. // public partial int this[object[] s] { get => 1; set { } } - Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "this").WithArguments("int C.this[dynamic[] s]", "int C.this[object[] s]").WithLocation(5, 24)); + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "this").WithArguments("int C.this[dynamic[] s]", "int C.this[object[] s]").WithLocation(5, 24)); } [Fact] @@ -3253,9 +3253,9 @@ partial class C var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (4,29): error CS9255: Both partial property declarations must have the same type. + // (4,29): error CS9255: Both partial member declarations must have the same type. // public partial string[] this[int x] { get => []; set { } } - Diagnostic(ErrorCode.ERR_PartialPropertyTypeDifference, "this").WithLocation(4, 29)); + Diagnostic(ErrorCode.ERR_PartialMemberTypeDifference, "this").WithLocation(4, 29)); } [Fact] @@ -4689,9 +4689,9 @@ static void Main() var verifier = CompileAndVerify(source, expectedOutput: "1", symbolValidator: verify, sourceSymbolValidator: verify); verifier.VerifyDiagnostics( - // (6,24): warning CS9256: Partial property declarations 'int C.this[int p1]' and 'int C.this[int p2]' have signature differences. + // (6,24): warning CS9256: Partial member declarations 'int C.this[int p1]' and 'int C.this[int p2]' have signature differences. // public partial int this[int p2] { get => p2; set { } } - Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "this").WithArguments("int C.this[int p1]", "int C.this[int p2]").WithLocation(6, 24)); + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "this").WithArguments("int C.this[int p1]", "int C.this[int p2]").WithLocation(6, 24)); void verify(ModuleSymbol module) { @@ -4761,9 +4761,9 @@ public partial void M( // 9 // (20,18): error CS0103: The name 'p2' does not exist in the current context // [Attr(nameof(p2))] // 4 Diagnostic(ErrorCode.ERR_NameNotInContext, "p2").WithArguments("p2").WithLocation(20, 18), - // (21,24): warning CS9256: Partial property declarations 'int C.this[int p1]' and 'int C.this[int p2]' have signature differences. + // (21,24): warning CS9256: Partial member declarations 'int C.this[int p1]' and 'int C.this[int p2]' have signature differences. // public partial int this[int p2] // 5 - Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "this").WithArguments("int C.this[int p1]", "int C.this[int p2]").WithLocation(21, 24), + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "this").WithArguments("int C.this[int p1]", "int C.this[int p2]").WithLocation(21, 24), // (25,29): error CS0103: The name 'p1' does not exist in the current context // [param: Attr(nameof(p1))] // 6 Diagnostic(ErrorCode.ERR_NameNotInContext, "p1").WithArguments("p1").WithLocation(25, 29), @@ -5107,7 +5107,37 @@ partial struct S1 """; var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics(); + CompileAndVerify(comp).VerifyDiagnostics().VerifyTypeIL("S1", +""" +.class private sequential ansi sealed beforefieldinit S1 + extends [mscorlib]System.ValueType +{ + .custom instance void [mscorlib]System.Reflection.DefaultMemberAttribute::.ctor(string) = ( + 01 00 06 4d 79 4e 61 6d 65 00 00 + ) + .pack 0 + .size 1 + // Methods + .method public hidebysig specialname + instance int32 get_MyName ( + int32 x + ) cil managed + { + // Method begins at RVA 0x2067 + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldarg.1 + IL_0001: ret + } // end of method S1::get_MyName + // Properties + .property instance int32 MyName( + int32 x + ) + { + .get instance int32 S1::get_MyName(int32) + } +} // end of class S1 +""".Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76842")] @@ -5126,7 +5156,39 @@ partial struct S1 """; var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics(); + + // Note, the indexer name in metadata is "Item", expected "MyName" + CompileAndVerify(comp).VerifyDiagnostics().VerifyTypeIL("S1", +""" +.class private sequential ansi sealed beforefieldinit S1 + extends [mscorlib]System.ValueType +{ + .custom instance void [mscorlib]System.Reflection.DefaultMemberAttribute::.ctor(string) = ( + 01 00 04 49 74 65 6d 00 00 + ) + .pack 0 + .size 1 + // Methods + .method public hidebysig specialname + instance int32 get_Item ( + int32 x + ) cil managed + { + // Method begins at RVA 0x2067 + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldarg.1 + IL_0001: ret + } // end of method S1::get_Item + // Properties + .property instance int32 Item( + int32 x + ) + { + .get instance int32 S1::get_Item(int32) + } +} // end of class S1 +""".Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); } } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/RequiredMembersTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/RequiredMembersTests.cs index 996ecaa302bdd..b27624e0c3748 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/RequiredMembersTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/RequiredMembersTests.cs @@ -7584,7 +7584,7 @@ public void TupleWithRequiredFields(bool setsRequiredMembers) [Theory] [CombinatorialData] - public void TupleWithRequiredFields_TupleExpressonSyntax(bool setsRequiredMembers) + public void TupleWithRequiredFields_TupleExpressionSyntax(bool setsRequiredMembers) { var comp = CreateCompilation(new[] { """ #pragma warning disable CS0219 // Unused local diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/EventTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/EventTests.cs index 36851ee503cf4..c3966f42229d7 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/EventTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/EventTests.cs @@ -2765,5 +2765,123 @@ .event [netstandard]System.Action E1 } // end of class Test1 ".Replace("[netstandard]", ExecutionConditionUtil.IsDesktop ? "[mscorlib]" : "[netstandard]")); } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/77254")] + [InlineData(LanguageVersion.CSharp1)] + [InlineData(LanguageVersion.CSharp13)] + [InlineData(LanguageVersion.Preview)] + public void Attributes_Locations(LanguageVersion langVersion) + { + var source = """ + using System; + + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] + public class A : Attribute { public A(int i) { } } + + public class C + { + [A(1)] [method: A(2)] [param: A(3)] [return: A(4)] [event: A(5)] [field: A(6)] public event Action E; + + [A(1)] [method: A(2)] [param: A(3)] [return: A(4)] [event: A(5)] [field: A(6)] public extern event Action F; + + [A(1)] [method: A(2)] [param: A(3)] [return: A(4)] [event: A(5)] [field: A(6)] public event Action G + { + [A(21)] [method: A(22)] [param: A(23)] [return: A(24)] [event: A(25)] [field: A(26)] add { } + [A(31)] [method: A(32)] [param: A(33)] [return: A(34)] [event: A(35)] [field: A(36)] remove { } + } + } + """; + CompileAndVerify(source, + parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion), + options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All), + symbolValidator: validate, + sourceSymbolValidator: validate, + // PEVerify fails when extern methods lack an implementation + verify: Verification.FailsPEVerify with + { + PEVerifyMessage = """ + Error: Method marked Abstract, Runtime, InternalCall or Imported must have zero RVA, and vice versa. + Error: Method marked Abstract, Runtime, InternalCall or Imported must have zero RVA, and vice versa. + Type load failed. + """, + }) + .VerifyDiagnostics( + // (8,28): warning CS0657: 'param' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, field, event'. All attributes in this block will be ignored. + // [A(1)] [method: A(2)] [param: A(3)] [return: A(4)] [event: A(5)] [field: A(6)] public event Action E; + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "param").WithArguments("param", "method, field, event").WithLocation(8, 28), + // (8,42): warning CS0657: 'return' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, field, event'. All attributes in this block will be ignored. + // [A(1)] [method: A(2)] [param: A(3)] [return: A(4)] [event: A(5)] [field: A(6)] public event Action E; + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "return").WithArguments("return", "method, field, event").WithLocation(8, 42), + // (8,104): warning CS0067: The event 'C.E' is never used + // [A(1)] [method: A(2)] [param: A(3)] [return: A(4)] [event: A(5)] [field: A(6)] public event Action E; + Diagnostic(ErrorCode.WRN_UnreferencedEvent, "E").WithArguments("C.E").WithLocation(8, 104), + // (10,28): warning CS0657: 'param' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, event'. All attributes in this block will be ignored. + // [A(1)] [method: A(2)] [param: A(3)] [return: A(4)] [event: A(5)] [field: A(6)] public extern event Action F; + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "param").WithArguments("param", "method, event").WithLocation(10, 28), + // (10,42): warning CS0657: 'return' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, event'. All attributes in this block will be ignored. + // [A(1)] [method: A(2)] [param: A(3)] [return: A(4)] [event: A(5)] [field: A(6)] public extern event Action F; + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "return").WithArguments("return", "method, event").WithLocation(10, 42), + // (10,71): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, event'. All attributes in this block will be ignored. + // [A(1)] [method: A(2)] [param: A(3)] [return: A(4)] [event: A(5)] [field: A(6)] public extern event Action F; + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "method, event").WithLocation(10, 71), + // (12,13): warning CS0657: 'method' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'event'. All attributes in this block will be ignored. + // [A(1)] [method: A(2)] [param: A(3)] [return: A(4)] [event: A(5)] [field: A(6)] public event Action G + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "method").WithArguments("method", "event").WithLocation(12, 13), + // (12,28): warning CS0657: 'param' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'event'. All attributes in this block will be ignored. + // [A(1)] [method: A(2)] [param: A(3)] [return: A(4)] [event: A(5)] [field: A(6)] public event Action G + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "param").WithArguments("param", "event").WithLocation(12, 28), + // (12,42): warning CS0657: 'return' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'event'. All attributes in this block will be ignored. + // [A(1)] [method: A(2)] [param: A(3)] [return: A(4)] [event: A(5)] [field: A(6)] public event Action G + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "return").WithArguments("return", "event").WithLocation(12, 42), + // (12,71): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'event'. All attributes in this block will be ignored. + // [A(1)] [method: A(2)] [param: A(3)] [return: A(4)] [event: A(5)] [field: A(6)] public event Action G + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "event").WithLocation(12, 71), + // (14,65): warning CS0657: 'event' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, param, return'. All attributes in this block will be ignored. + // [A(21)] [method: A(22)] [param: A(23)] [return: A(24)] [event: A(25)] [field: A(26)] add { } + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "event").WithArguments("event", "method, param, return").WithLocation(14, 65), + // (14,80): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, param, return'. All attributes in this block will be ignored. + // [A(21)] [method: A(22)] [param: A(23)] [return: A(24)] [event: A(25)] [field: A(26)] add { } + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "method, param, return").WithLocation(14, 80), + // (15,65): warning CS0657: 'event' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, param, return'. All attributes in this block will be ignored. + // [A(31)] [method: A(32)] [param: A(33)] [return: A(34)] [event: A(35)] [field: A(36)] remove { } + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "event").WithArguments("event", "method, param, return").WithLocation(15, 65), + // (15,80): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, param, return'. All attributes in this block will be ignored. + // [A(31)] [method: A(32)] [param: A(33)] [return: A(34)] [event: A(35)] [field: A(36)] remove { } + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "method, param, return").WithLocation(15, 80)); + + static void validate(ModuleSymbol module) + { + var isSource = module is SourceModuleSymbol; + ReadOnlySpan compiledGeneratedAttr = isSource ? [] : ["System.Runtime.CompilerServices.CompilerGeneratedAttribute"]; + + var e = module.GlobalNamespace.GetMember("C.E"); + AssertEx.Equal(["A(1)", "A(5)"], e.GetAttributes().ToStrings()); + AssertEx.Equal([.. compiledGeneratedAttr, "A(2)"], e.AddMethod!.GetAttributes().ToStrings()); + AssertEx.Equal(["A(3)"], e.AddMethod.Parameters.Single().GetAttributes().ToStrings()); + AssertEx.Equal([], e.AddMethod.GetReturnTypeAttributes().ToStrings()); + AssertEx.Equal([.. compiledGeneratedAttr, "A(2)"], e.RemoveMethod!.GetAttributes().ToStrings()); + AssertEx.Equal(["A(3)"], e.RemoveMethod.Parameters.Single().GetAttributes().ToStrings()); + AssertEx.Equal([], e.RemoveMethod.GetReturnTypeAttributes().ToStrings()); + AssertEx.Equal([.. compiledGeneratedAttr, "A(6)"], e.AssociatedField.GetAttributes().ToStrings()); + + var f = module.GlobalNamespace.GetMember("C.F"); + AssertEx.Equal(["A(1)", "A(5)"], f.GetAttributes().ToStrings()); + AssertEx.Equal([.. compiledGeneratedAttr, "A(2)"], f.AddMethod!.GetAttributes().ToStrings()); + AssertEx.Equal(["A(3)"], f.AddMethod.Parameters.Single().GetAttributes().ToStrings()); + AssertEx.Equal([], f.AddMethod.GetReturnTypeAttributes().ToStrings()); + AssertEx.Equal([.. compiledGeneratedAttr, "A(2)"], f.RemoveMethod!.GetAttributes().ToStrings()); + AssertEx.Equal(["A(3)"], f.RemoveMethod.Parameters.Single().GetAttributes().ToStrings()); + AssertEx.Equal([], f.RemoveMethod.GetReturnTypeAttributes().ToStrings()); + + var g = module.GlobalNamespace.GetMember("C.G"); + AssertEx.Equal(["A(1)", "A(5)"], g.GetAttributes().ToStrings()); + AssertEx.Equal(["A(21)", "A(22)"], g.AddMethod!.GetAttributes().ToStrings()); + AssertEx.Equal(["A(23)"], g.AddMethod.Parameters.Single().GetAttributes().ToStrings()); + AssertEx.Equal(["A(24)"], g.AddMethod.GetReturnTypeAttributes().ToStrings()); + AssertEx.Equal(["A(31)", "A(32)"], g.RemoveMethod!.GetAttributes().ToStrings()); + AssertEx.Equal(["A(33)"], g.RemoveMethod.Parameters.Single().GetAttributes().ToStrings()); + AssertEx.Equal(["A(34)"], g.RemoveMethod.GetReturnTypeAttributes().ToStrings()); + } + } } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs index cb66cc59b071a..29d3a8330a5ca 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs @@ -819,34 +819,34 @@ partial sealed static I3() {} // (4,19): error CS0106: The modifier 'sealed' is not valid for this item // sealed static I1() {} Diagnostic(ErrorCode.ERR_BadMemberFlag, "I1").WithArguments("sealed").WithLocation(4, 19), - // (9,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // (9,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. // partial sealed static I2(); Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(9, 5), - // (9,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // (9,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. // partial sealed static I2(); Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(9, 5), // (9,27): error CS0106: The modifier 'sealed' is not valid for this item // partial sealed static I2(); Diagnostic(ErrorCode.ERR_BadMemberFlag, "I2").WithArguments("sealed").WithLocation(9, 27), - // (14,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // (14,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. // partial static I2() {} Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(14, 5), - // (14,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // (14,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. // partial static I2() {} Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(14, 5), // (14,20): error CS0111: Type 'I2' already defines a member called 'I2' with the same parameter types // partial static I2() {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "I2").WithArguments("I2", "I2").WithLocation(14, 20), - // (19,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // (19,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. // partial static I3(); Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(19, 5), - // (19,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // (19,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. // partial static I3(); Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(19, 5), - // (24,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // (24,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. // partial sealed static I3() {} Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(24, 5), - // (24,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // (24,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. // partial sealed static I3() {} Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(24, 5), // (24,27): error CS0106: The modifier 'sealed' is not valid for this item @@ -901,48 +901,30 @@ sealed static partial I3() {} targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (4,19): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) + // (4,19): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. // sealed static partial I2(); - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(4, 19), - // (4,27): error CS0501: 'I2.I2()' must declare a body because it is not marked abstract, extern, or partial + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(4, 19), + // (4,27): error CS0106: The modifier 'sealed' is not valid for this item // sealed static partial I2(); - Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "I2").WithArguments("I2.I2()").WithLocation(4, 27), - // (4,27): error CS0542: 'I2': member names cannot be the same as their enclosing type - // sealed static partial I2(); - Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "I2").WithArguments("I2").WithLocation(4, 27), - // (9,12): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) - // static partial I2() {} - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(9, 12), - // (9,20): error CS0542: 'I2': member names cannot be the same as their enclosing type + Diagnostic(ErrorCode.ERR_BadMemberFlag, "I2").WithArguments("sealed").WithLocation(4, 27), + // (9,12): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. // static partial I2() {} - Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "I2").WithArguments("I2").WithLocation(9, 20), + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(9, 12), // (9,20): error CS0111: Type 'I2' already defines a member called 'I2' with the same parameter types // static partial I2() {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "I2").WithArguments("I2", "I2").WithLocation(9, 20), - // (9,20): error CS0161: 'I2.I2()': not all code paths return a value - // static partial I2() {} - Diagnostic(ErrorCode.ERR_ReturnExpected, "I2").WithArguments("I2.I2()").WithLocation(9, 20), - // (14,12): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) + // (14,12): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. // static partial I3(); - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(14, 12), - // (14,20): error CS0501: 'I3.I3()' must declare a body because it is not marked abstract, extern, or partial - // static partial I3(); - Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "I3").WithArguments("I3.I3()").WithLocation(14, 20), - // (14,20): error CS0542: 'I3': member names cannot be the same as their enclosing type - // static partial I3(); - Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "I3").WithArguments("I3").WithLocation(14, 20), - // (19,19): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(14, 12), + // (19,19): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. // sealed static partial I3() {} - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(19, 19), - // (19,27): error CS0542: 'I3': member names cannot be the same as their enclosing type + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(19, 19), + // (19,27): error CS0106: The modifier 'sealed' is not valid for this item // sealed static partial I3() {} - Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "I3").WithArguments("I3").WithLocation(19, 27), + Diagnostic(ErrorCode.ERR_BadMemberFlag, "I3").WithArguments("sealed").WithLocation(19, 27), // (19,27): error CS0111: Type 'I3' already defines a member called 'I3' with the same parameter types // sealed static partial I3() {} - Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "I3").WithArguments("I3", "I3").WithLocation(19, 27), - // (19,27): error CS0161: 'I3.I3()': not all code paths return a value - // sealed static partial I3() {} - Diagnostic(ErrorCode.ERR_ReturnExpected, "I3").WithArguments("I3.I3()").WithLocation(19, 27) + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "I3").WithArguments("I3", "I3").WithLocation(19, 27) ); } @@ -6476,7 +6458,7 @@ class C6 : C5 else { compilation2.VerifyEmitDiagnostics( - // (43,7): error CS8920: The interface 'I1' cannot be used as type argumen. Member 'I1.M01()' does not have a most specific implementation in the interface. + // (43,7): error CS8920: The interface 'I1' cannot be used as type argument. Static member 'I1.M01()' does not have a most specific implementation in the interface. // class C6 : C5 Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedInterfaceWithStaticAbstractMembers, "C6").WithArguments("I1", "I1.M01()").WithLocation(43, 7) ); @@ -6494,7 +6476,7 @@ class C6 : C5 else { compilation2.VerifyEmitDiagnostics( - // (43,7): error CS8920: The interface 'I1' cannot be used as type argumen. Member 'I1.M01()' does not have a most specific implementation in the interface. + // (43,7): error CS8920: The interface 'I1' cannot be used as type argument. Static member 'I1.M01()' does not have a most specific implementation in the interface. // class C6 : C5 Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedInterfaceWithStaticAbstractMembers, "C6").WithArguments("I1", "I1.M01()").WithLocation(43, 7) ); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs index ba1fe31ecac84..2d14058a57436 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs @@ -14953,9 +14953,9 @@ public static void M4(this object o) { } }"; var compilation = CreateEmptyCompilation(source, new[] { Net40.References.mscorlib }); compilation.VerifyDiagnostics( - // (3,27): error CS1110: Cannot define a new extension method because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? + // (3,27): error CS1110: Cannot define a new extension because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "this").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(3, 27), - // (4,27): error CS1110: Cannot define a new extension method because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? + // (4,27): error CS1110: Cannot define a new extension because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "this").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(4, 27), // (4,42): error CS1100: Method 'M2' has a parameter modifier 'this' which is not on the first parameter Diagnostic(ErrorCode.ERR_BadThisParam, "this").WithArguments("M2").WithLocation(4, 42), @@ -22136,30 +22136,27 @@ partial public PartialPublicCtor() { } } """ }).VerifyDiagnostics( - // (3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // 2.cs(3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. // partial public PartialPublicCtor() { } Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 5), - // (3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. - // partial public PartialPublicCtor() { } - Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 5), - // (3,5): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) - // partial PartialCtor() { } - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(3, 5), - // (3,12): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) - // public partial PublicPartialCtor() { } - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(3, 12), - // (3,13): error CS0542: 'PartialCtor': member names cannot be the same as their enclosing type + // 0.cs(3,13): error CS0751: A partial member must be declared within a partial type // partial PartialCtor() { } - Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "PartialCtor").WithArguments("PartialCtor").WithLocation(3, 13), - // (3,13): error CS0161: 'PartialCtor.PartialCtor()': not all code paths return a value + Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "PartialCtor").WithLocation(3, 13), + // 0.cs(3,13): error CS9276: Partial member 'PartialCtor.PartialCtor()' must have a definition part. // partial PartialCtor() { } - Diagnostic(ErrorCode.ERR_ReturnExpected, "PartialCtor").WithArguments("PartialCtor.PartialCtor()").WithLocation(3, 13), - // (3,20): error CS0542: 'PublicPartialCtor': member names cannot be the same as their enclosing type + Diagnostic(ErrorCode.ERR_PartialMemberMissingDefinition, "PartialCtor").WithArguments("PartialCtor.PartialCtor()").WithLocation(3, 13), + // 2.cs(3,20): error CS0751: A partial member must be declared within a partial type + // partial public PartialPublicCtor() { } + Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "PartialPublicCtor").WithLocation(3, 20), + // 1.cs(3,20): error CS0751: A partial member must be declared within a partial type // public partial PublicPartialCtor() { } - Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "PublicPartialCtor").WithArguments("PublicPartialCtor").WithLocation(3, 20), - // (3,20): error CS0161: 'PublicPartialCtor.PublicPartialCtor()': not all code paths return a value + Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "PublicPartialCtor").WithLocation(3, 20), + // 1.cs(3,20): error CS9276: Partial member 'PublicPartialCtor.PublicPartialCtor()' must have a definition part. // public partial PublicPartialCtor() { } - Diagnostic(ErrorCode.ERR_ReturnExpected, "PublicPartialCtor").WithArguments("PublicPartialCtor.PublicPartialCtor()").WithLocation(3, 20)); + Diagnostic(ErrorCode.ERR_PartialMemberMissingDefinition, "PublicPartialCtor").WithArguments("PublicPartialCtor.PublicPartialCtor()").WithLocation(3, 20), + // 2.cs(3,20): error CS9276: Partial member 'PartialPublicCtor.PartialPublicCtor()' must have a definition part. + // partial public PartialPublicCtor() { } + Diagnostic(ErrorCode.ERR_PartialMemberMissingDefinition, "PartialPublicCtor").WithArguments("PartialPublicCtor.PartialPublicCtor()").WithLocation(3, 20)); } [Fact] @@ -22216,75 +22213,63 @@ partial public static PartialPublicStaticCtor() { } } """, }).VerifyDiagnostics( - // (3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // 6.cs(3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. + // partial static public PartialStaticPublicCtor() { } + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 5), + // 6.cs(3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. + // partial static public PartialStaticPublicCtor() { } + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 5), + // 0.cs(3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. // partial static PartialStaticCtor() { } Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 5), - // (3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // 0.cs(3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. // partial static PartialStaticCtor() { } Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 5), - // (3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // 7.cs(3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. // partial public static PartialPublicStaticCtor() { } Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 5), - // (3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // 7.cs(3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. // partial public static PartialPublicStaticCtor() { } Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 5), - // (3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. - // partial static public PartialStaticPublicCtor() { } - Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 5), - // (3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. - // partial static public PartialStaticPublicCtor() { } - Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 5), - // (3,12): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // 3.cs(3,12): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. // public partial static PublicPartialStaticCtor() { } Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 12), - // (3,12): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // 3.cs(3,12): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. // public partial static PublicPartialStaticCtor() { } Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 12), - // (3,12): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // 1.cs(3,12): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. + // static partial StaticPartialCtor() { } + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 12), + // 5.cs(3,12): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. // static partial public StaticPartialPublicCtor() { } Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 12), - // (3,12): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // 5.cs(3,12): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. // static partial public StaticPartialPublicCtor() { } Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 12), - // (3,12): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) - // static partial StaticPartialCtor() { } - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(3, 12), - // (3,19): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) + // 2.cs(3,19): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. // public static partial PublicStaticPartialCtor() { } - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(3, 19), - // (3,19): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 19), + // 4.cs(3,19): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. // static public partial StaticPublicPartialCtor() { } - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(3, 19), - // (3,20): error CS0542: 'StaticPartialCtor': member names cannot be the same as their enclosing type - // static partial StaticPartialCtor() { } - Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "StaticPartialCtor").WithArguments("StaticPartialCtor").WithLocation(3, 20), - // (3,20): error CS0161: 'StaticPartialCtor.StaticPartialCtor()': not all code paths return a value - // static partial StaticPartialCtor() { } - Diagnostic(ErrorCode.ERR_ReturnExpected, "StaticPartialCtor").WithArguments("StaticPartialCtor.StaticPartialCtor()").WithLocation(3, 20), - // (3,27): error CS0515: 'PartialPublicStaticCtor.PartialPublicStaticCtor()': access modifiers are not allowed on static constructors - // partial public static PartialPublicStaticCtor() { } - Diagnostic(ErrorCode.ERR_StaticConstructorWithAccessModifiers, "PartialPublicStaticCtor").WithArguments("PartialPublicStaticCtor.PartialPublicStaticCtor()").WithLocation(3, 27), - // (3,27): error CS0515: 'PublicPartialStaticCtor.PublicPartialStaticCtor()': access modifiers are not allowed on static constructors + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 19), + // 3.cs(3,27): error CS0515: 'PublicPartialStaticCtor.PublicPartialStaticCtor()': access modifiers are not allowed on static constructors // public partial static PublicPartialStaticCtor() { } Diagnostic(ErrorCode.ERR_StaticConstructorWithAccessModifiers, "PublicPartialStaticCtor").WithArguments("PublicPartialStaticCtor.PublicPartialStaticCtor()").WithLocation(3, 27), - // (3,27): error CS0515: 'StaticPartialPublicCtor.StaticPartialPublicCtor()': access modifiers are not allowed on static constructors - // static partial public StaticPartialPublicCtor() { } - Diagnostic(ErrorCode.ERR_StaticConstructorWithAccessModifiers, "StaticPartialPublicCtor").WithArguments("StaticPartialPublicCtor.StaticPartialPublicCtor()").WithLocation(3, 27), - // (3,27): error CS0515: 'PartialStaticPublicCtor.PartialStaticPublicCtor()': access modifiers are not allowed on static constructors + // 6.cs(3,27): error CS0515: 'PartialStaticPublicCtor.PartialStaticPublicCtor()': access modifiers are not allowed on static constructors // partial static public PartialStaticPublicCtor() { } Diagnostic(ErrorCode.ERR_StaticConstructorWithAccessModifiers, "PartialStaticPublicCtor").WithArguments("PartialStaticPublicCtor.PartialStaticPublicCtor()").WithLocation(3, 27), - // (3,27): error CS0542: 'StaticPublicPartialCtor': member names cannot be the same as their enclosing type - // static public partial StaticPublicPartialCtor() { } - Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "StaticPublicPartialCtor").WithArguments("StaticPublicPartialCtor").WithLocation(3, 27), - // (3,27): error CS0542: 'PublicStaticPartialCtor': member names cannot be the same as their enclosing type + // 2.cs(3,27): error CS0515: 'PublicStaticPartialCtor.PublicStaticPartialCtor()': access modifiers are not allowed on static constructors // public static partial PublicStaticPartialCtor() { } - Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "PublicStaticPartialCtor").WithArguments("PublicStaticPartialCtor").WithLocation(3, 27), - // (3,27): error CS0161: 'StaticPublicPartialCtor.StaticPublicPartialCtor()': not all code paths return a value + Diagnostic(ErrorCode.ERR_StaticConstructorWithAccessModifiers, "PublicStaticPartialCtor").WithArguments("PublicStaticPartialCtor.PublicStaticPartialCtor()").WithLocation(3, 27), + // 4.cs(3,27): error CS0515: 'StaticPublicPartialCtor.StaticPublicPartialCtor()': access modifiers are not allowed on static constructors // static public partial StaticPublicPartialCtor() { } - Diagnostic(ErrorCode.ERR_ReturnExpected, "StaticPublicPartialCtor").WithArguments("StaticPublicPartialCtor.StaticPublicPartialCtor()").WithLocation(3, 27), - // (3,27): error CS0161: 'PublicStaticPartialCtor.PublicStaticPartialCtor()': not all code paths return a value - // public static partial PublicStaticPartialCtor() { } - Diagnostic(ErrorCode.ERR_ReturnExpected, "PublicStaticPartialCtor").WithArguments("PublicStaticPartialCtor.PublicStaticPartialCtor()").WithLocation(3, 27)); + Diagnostic(ErrorCode.ERR_StaticConstructorWithAccessModifiers, "StaticPublicPartialCtor").WithArguments("StaticPublicPartialCtor.StaticPublicPartialCtor()").WithLocation(3, 27), + // 7.cs(3,27): error CS0515: 'PartialPublicStaticCtor.PartialPublicStaticCtor()': access modifiers are not allowed on static constructors + // partial public static PartialPublicStaticCtor() { } + Diagnostic(ErrorCode.ERR_StaticConstructorWithAccessModifiers, "PartialPublicStaticCtor").WithArguments("PartialPublicStaticCtor.PartialPublicStaticCtor()").WithLocation(3, 27), + // 5.cs(3,27): error CS0515: 'StaticPartialPublicCtor.StaticPartialPublicCtor()': access modifiers are not allowed on static constructors + // static partial public StaticPartialPublicCtor() { } + Diagnostic(ErrorCode.ERR_StaticConstructorWithAccessModifiers, "StaticPartialPublicCtor").WithArguments("StaticPartialPublicCtor.StaticPartialPublicCtor()").WithLocation(3, 27)); } } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/UnsignedRightShiftTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/UnsignedRightShiftTests.cs index e76f6deb1b77f..b961e7c8c0b91 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/UnsignedRightShiftTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/UnsignedRightShiftTests.cs @@ -2325,7 +2325,7 @@ static void Main() } [Fact] - public void UserDefined_CompountAssignment_01() + public void UserDefined_CompoundAssignment_01() { var source1 = @" public class C1 @@ -2545,7 +2545,7 @@ static void Main() } [Fact] - public void UserDefined_Lifted_CompountAssignment_01() + public void UserDefined_Lifted_CompoundAssignment_01() { var source1 = @" public struct C1 @@ -3457,7 +3457,7 @@ class C } [Fact] - public void UserDefined_CompountAssignment_LangVersion_01() + public void UserDefined_CompoundAssignment_LangVersion_01() { var source0 = @" public class C1 @@ -3561,7 +3561,7 @@ class C } [Fact] - public void UserDefined_Lifted_CompountAssignment_LangVersion_01() + public void UserDefined_Lifted_CompoundAssignment_LangVersion_01() { var source0 = @" public struct C1 diff --git a/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs b/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs index e2c7ddb41920c..a24253bd6119e 100644 --- a/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs +++ b/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs @@ -324,7 +324,7 @@ public void WarningLevel_2() case ErrorCode.WRN_Experimental: case ErrorCode.WRN_ExperimentalWithMessage: case ErrorCode.WRN_ConvertingLock: - case ErrorCode.WRN_PartialPropertySignatureDifference: + case ErrorCode.WRN_PartialMemberSignatureDifference: case ErrorCode.WRN_UnscopedRefAttributeOldRules: Assert.Equal(1, ErrorFacts.GetWarningLevel(errorCode)); break; @@ -2991,6 +2991,7 @@ public void TestIsBuildOnlyDiagnostic() case ErrorCode.ERR_PossibleAsyncIteratorWithoutYield: case ErrorCode.ERR_PossibleAsyncIteratorWithoutYieldOrAwait: case ErrorCode.ERR_RefLocalAcrossAwait: + case ErrorCode.ERR_DataSectionStringLiteralHashCollision: Assert.True(isBuildOnly, $"Check failed for ErrorCode.{errorCode}"); break; diff --git a/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs b/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs index 88f2342f45eec..604aa3566ef2d 100644 --- a/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs +++ b/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs @@ -520,6 +520,9 @@ private static Syntax.InternalSyntax.DelegateDeclarationSyntax GenerateDelegateD private static Syntax.InternalSyntax.EnumMemberDeclarationSyntax GenerateEnumMemberDeclaration() => InternalSyntaxFactory.EnumMemberDeclaration(new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), InternalSyntaxFactory.Identifier("Identifier"), null); + private static Syntax.InternalSyntax.ExtensionDeclarationSyntax GenerateExtensionDeclaration() + => InternalSyntaxFactory.ExtensionDeclaration(new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), InternalSyntaxFactory.Token(SyntaxKind.ExtensionKeyword), null, null, new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), null, new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), null, null); + private static Syntax.InternalSyntax.BaseListSyntax GenerateBaseList() => InternalSyntaxFactory.BaseList(InternalSyntaxFactory.Token(SyntaxKind.ColonToken), new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList()); @@ -602,7 +605,7 @@ private static Syntax.InternalSyntax.BracketedParameterListSyntax GenerateBracke => InternalSyntaxFactory.BracketedParameterList(InternalSyntaxFactory.Token(SyntaxKind.OpenBracketToken), new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList(), InternalSyntaxFactory.Token(SyntaxKind.CloseBracketToken)); private static Syntax.InternalSyntax.ParameterSyntax GenerateParameter() - => InternalSyntaxFactory.Parameter(new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), null, InternalSyntaxFactory.Identifier("Identifier"), null); + => InternalSyntaxFactory.Parameter(new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), null, null, null); private static Syntax.InternalSyntax.FunctionPointerParameterSyntax GenerateFunctionPointerParameter() => InternalSyntaxFactory.FunctionPointerParameter(new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), GenerateIdentifierName()); @@ -2891,6 +2894,25 @@ public void TestEnumMemberDeclarationFactoryAndProperties() AttachAndCheckDiagnostics(node); } + [Fact] + public void TestExtensionDeclarationFactoryAndProperties() + { + var node = GenerateExtensionDeclaration(); + + Assert.Equal(default, node.AttributeLists); + Assert.Equal(default, node.Modifiers); + Assert.Equal(SyntaxKind.ExtensionKeyword, node.Keyword.Kind); + Assert.Null(node.TypeParameterList); + Assert.Null(node.ParameterList); + Assert.Equal(default, node.ConstraintClauses); + Assert.Null(node.OpenBraceToken); + Assert.Equal(default, node.Members); + Assert.Null(node.CloseBraceToken); + Assert.Null(node.SemicolonToken); + + AttachAndCheckDiagnostics(node); + } + [Fact] public void TestBaseListFactoryAndProperties() { @@ -3268,7 +3290,7 @@ public void TestParameterFactoryAndProperties() Assert.Equal(default, node.AttributeLists); Assert.Equal(default, node.Modifiers); Assert.Null(node.Type); - Assert.Equal(SyntaxKind.IdentifierToken, node.Identifier.Kind); + Assert.Null(node.Identifier); Assert.Null(node.Default); AttachAndCheckDiagnostics(node); @@ -8297,6 +8319,32 @@ public void TestEnumMemberDeclarationIdentityRewriter() Assert.Same(oldNode, newNode); } + [Fact] + public void TestExtensionDeclarationTokenDeleteRewriter() + { + var oldNode = GenerateExtensionDeclaration(); + var rewriter = new TokenDeleteRewriter(); + var newNode = rewriter.Visit(oldNode); + + if(!oldNode.IsMissing) + { + Assert.NotEqual(oldNode, newNode); + } + + Assert.NotNull(newNode); + Assert.True(newNode.IsMissing, "No tokens => missing"); + } + + [Fact] + public void TestExtensionDeclarationIdentityRewriter() + { + var oldNode = GenerateExtensionDeclaration(); + var rewriter = new IdentityRewriter(); + var newNode = rewriter.Visit(oldNode); + + Assert.Same(oldNode, newNode); + } + [Fact] public void TestBaseListTokenDeleteRewriter() { @@ -10736,6 +10784,9 @@ private static DelegateDeclarationSyntax GenerateDelegateDeclaration() private static EnumMemberDeclarationSyntax GenerateEnumMemberDeclaration() => SyntaxFactory.EnumMemberDeclaration(new SyntaxList(), new SyntaxTokenList(), SyntaxFactory.Identifier("Identifier"), default(EqualsValueClauseSyntax)); + private static ExtensionDeclarationSyntax GenerateExtensionDeclaration() + => SyntaxFactory.ExtensionDeclaration(new SyntaxList(), new SyntaxTokenList(), SyntaxFactory.Token(SyntaxKind.ExtensionKeyword), default(TypeParameterListSyntax), default(ParameterListSyntax), new SyntaxList(), default(SyntaxToken), new SyntaxList(), default(SyntaxToken), default(SyntaxToken)); + private static BaseListSyntax GenerateBaseList() => SyntaxFactory.BaseList(SyntaxFactory.Token(SyntaxKind.ColonToken), new SeparatedSyntaxList()); @@ -10818,7 +10869,7 @@ private static BracketedParameterListSyntax GenerateBracketedParameterList() => SyntaxFactory.BracketedParameterList(SyntaxFactory.Token(SyntaxKind.OpenBracketToken), new SeparatedSyntaxList(), SyntaxFactory.Token(SyntaxKind.CloseBracketToken)); private static ParameterSyntax GenerateParameter() - => SyntaxFactory.Parameter(new SyntaxList(), new SyntaxTokenList(), default(TypeSyntax), SyntaxFactory.Identifier("Identifier"), default(EqualsValueClauseSyntax)); + => SyntaxFactory.Parameter(new SyntaxList(), new SyntaxTokenList(), default(TypeSyntax), default(SyntaxToken), default(EqualsValueClauseSyntax)); private static FunctionPointerParameterSyntax GenerateFunctionPointerParameter() => SyntaxFactory.FunctionPointerParameter(new SyntaxList(), new SyntaxTokenList(), GenerateIdentifierName()); @@ -13107,6 +13158,25 @@ public void TestEnumMemberDeclarationFactoryAndProperties() Assert.Equal(node, newNode); } + [Fact] + public void TestExtensionDeclarationFactoryAndProperties() + { + var node = GenerateExtensionDeclaration(); + + Assert.Equal(default, node.AttributeLists); + Assert.Equal(default, node.Modifiers); + Assert.Equal(SyntaxKind.ExtensionKeyword, node.Keyword.Kind()); + Assert.Null(node.TypeParameterList); + Assert.Null(node.ParameterList); + Assert.Equal(default, node.ConstraintClauses); + Assert.Equal(SyntaxKind.None, node.OpenBraceToken.Kind()); + Assert.Equal(default, node.Members); + Assert.Equal(SyntaxKind.None, node.CloseBraceToken.Kind()); + Assert.Equal(SyntaxKind.None, node.SemicolonToken.Kind()); + var newNode = node.WithAttributeLists(node.AttributeLists).WithModifiers(node.Modifiers).WithKeyword(node.Keyword).WithTypeParameterList(node.TypeParameterList).WithParameterList(node.ParameterList).WithConstraintClauses(node.ConstraintClauses).WithOpenBraceToken(node.OpenBraceToken).WithMembers(node.Members).WithCloseBraceToken(node.CloseBraceToken).WithSemicolonToken(node.SemicolonToken); + Assert.Equal(node, newNode); + } + [Fact] public void TestBaseListFactoryAndProperties() { @@ -13484,7 +13554,7 @@ public void TestParameterFactoryAndProperties() Assert.Equal(default, node.AttributeLists); Assert.Equal(default, node.Modifiers); Assert.Null(node.Type); - Assert.Equal(SyntaxKind.IdentifierToken, node.Identifier.Kind()); + Assert.Equal(SyntaxKind.None, node.Identifier.Kind()); Assert.Null(node.Default); var newNode = node.WithAttributeLists(node.AttributeLists).WithModifiers(node.Modifiers).WithType(node.Type).WithIdentifier(node.Identifier).WithDefault(node.Default); Assert.Equal(node, newNode); @@ -18513,6 +18583,32 @@ public void TestEnumMemberDeclarationIdentityRewriter() Assert.Same(oldNode, newNode); } + [Fact] + public void TestExtensionDeclarationTokenDeleteRewriter() + { + var oldNode = GenerateExtensionDeclaration(); + var rewriter = new TokenDeleteRewriter(); + var newNode = rewriter.Visit(oldNode); + + if(!oldNode.IsMissing) + { + Assert.NotEqual(oldNode, newNode); + } + + Assert.NotNull(newNode); + Assert.True(newNode.IsMissing, "No tokens => missing"); + } + + [Fact] + public void TestExtensionDeclarationIdentityRewriter() + { + var oldNode = GenerateExtensionDeclaration(); + var rewriter = new IdentityRewriter(); + var newNode = rewriter.Visit(oldNode); + + Assert.Same(oldNode, newNode); + } + [Fact] public void TestBaseListTokenDeleteRewriter() { diff --git a/src/Compilers/CSharp/Test/Syntax/IncrementalParsing/IncrementalParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/IncrementalParsing/IncrementalParsingTests.cs index 9b02ce60e8227..fbcd7a9a1be36 100644 --- a/src/Compilers/CSharp/Test/Syntax/IncrementalParsing/IncrementalParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/IncrementalParsing/IncrementalParsingTests.cs @@ -9,6 +9,8 @@ using System.Linq; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; using Xunit; @@ -104,27 +106,35 @@ public void TestChangeClassNameToNotMatchConstructor() TestDiffsInOrder(diffs, SyntaxKind.CompilationUnit, SyntaxKind.ClassDeclaration, - SyntaxKind.IdentifierToken, - SyntaxKind.MethodDeclaration, - SyntaxKind.PredefinedType, - SyntaxKind.VoidKeyword); + SyntaxKind.IdentifierToken); } - private static void TestDiffsInOrder(ImmutableArray diffs, params SyntaxKind[] kinds) + private static void TestDiffsInOrder(ImmutableArray diffs, params SyntaxKind[] expectedKinds) { - Assert.InRange(diffs.Length, 0, kinds.Length); + if (diffs.Length != expectedKinds.Length) + { + Assert.Fail(getMessage()); + } - int diffI = 0; - foreach (var kind in kinds) + for (int i = 0; i < diffs.Length; i++) { - if (diffI < diffs.Length && diffs[diffI].IsKind(kind)) + if (!diffs[i].IsKind(expectedKinds[i])) { - diffI++; + Assert.Fail(getMessage()); } } - // all diffs must be consumed. - Assert.Equal(diffI, diffs.Length); + string getMessage() + { + var builder = PooledStringBuilder.GetInstance(); + builder.Builder.AppendLine("Actual:"); + foreach (var diff in diffs) + { + builder.Builder.AppendLine($"SyntaxKind.{diff.Kind()},"); + } + + return builder.ToStringAndFree(); + } } [Fact] @@ -140,8 +150,7 @@ public void TestChangeClassNameToMatchConstructor() TestDiffsInOrder(diffs, SyntaxKind.CompilationUnit, SyntaxKind.ClassDeclaration, - SyntaxKind.IdentifierToken, - SyntaxKind.ConstructorDeclaration); + SyntaxKind.IdentifierToken); } [Fact] @@ -226,7 +235,6 @@ public void TestChangeMethodName() SyntaxKind.CompilationUnit, SyntaxKind.ClassDeclaration, SyntaxKind.MethodDeclaration, - SyntaxKind.PredefinedType, SyntaxKind.IdentifierToken); } @@ -294,11 +302,8 @@ class C { void N() { } } SyntaxKind.CompilationUnit, SyntaxKind.ClassDeclaration, SyntaxKind.ClassKeyword, - SyntaxKind.IdentifierToken, SyntaxKind.MethodDeclaration, - SyntaxKind.PredefinedType, SyntaxKind.IdentifierToken, - SyntaxKind.ParameterList, SyntaxKind.Block, SyntaxKind.EndOfFileToken); } @@ -377,7 +382,6 @@ class C { void c() { } } SyntaxKind.CompilationUnit, SyntaxKind.ClassDeclaration, // class declaration on edge before change SyntaxKind.MethodDeclaration, - SyntaxKind.PredefinedType, SyntaxKind.Block, SyntaxKind.ClassDeclaration, // class declaration on edge after change SyntaxKind.ClassKeyword, // edge of change and directives different @@ -421,7 +425,6 @@ class C { void c() { } } SyntaxKind.CompilationUnit, SyntaxKind.ClassDeclaration, // class declaration on edge before change SyntaxKind.MethodDeclaration, - SyntaxKind.PredefinedType, SyntaxKind.Block, SyntaxKind.ClassDeclaration, // class declaration on edge after change SyntaxKind.ClassKeyword, // edge of change and directives different @@ -442,11 +445,9 @@ public void TestGlobalStatementToStatementChange() SyntaxKind.GlobalStatement, SyntaxKind.Block, SyntaxKind.OpenBraceToken, - SyntaxKind.EmptyStatement, SyntaxKind.LocalDeclarationStatement, SyntaxKind.VariableDeclaration, SyntaxKind.PointerType, - SyntaxKind.IdentifierName, SyntaxKind.VariableDeclarator, SyntaxKind.SemicolonToken, // missing SyntaxKind.CloseBraceToken); // missing @@ -464,12 +465,10 @@ public void TestStatementToGlobalStatementChange() TestDiffsInOrder(diffs, SyntaxKind.CompilationUnit, SyntaxKind.GlobalStatement, - SyntaxKind.EmptyStatement, SyntaxKind.GlobalStatement, SyntaxKind.ExpressionStatement, SyntaxKind.MultiplyExpression, SyntaxKind.IdentifierName, - SyntaxKind.IdentifierName, SyntaxKind.SemicolonToken); } @@ -846,6 +845,437 @@ public void M2() WalkTreeAndVerify(withCloseBraceDeletedTree.GetCompilationUnitRoot(), fullTree.GetCompilationUnitRoot()); } + [Fact, CompilerTrait(CompilerFeature.Extensions)] + public void UpdateFromExtensionToClass() + { + var text = @" +class C +{ + extension(object x) { } +} +"; + var oldTree = this.Parse(text, LanguageVersionFacts.CSharpNext); + var newTree = oldTree.WithReplaceFirst("extension", "class D"); + oldTree.GetDiagnostics().Verify(); + newTree.GetDiagnostics().Verify(); + + var diffs = SyntaxDifferences.GetRebuiltNodes(oldTree, newTree); + TestDiffsInOrder(diffs, + SyntaxKind.CompilationUnit, + SyntaxKind.ClassDeclaration, + SyntaxKind.ClassDeclaration, + SyntaxKind.ClassKeyword, + SyntaxKind.IdentifierToken); + + UsingTree(newTree); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "D"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact, CompilerTrait(CompilerFeature.Extensions)] + public void UpdateFromExtensionToClass_NoParameterIdentifier() + { + var text = @" +class C +{ + extension(object) { } +} +"; + var oldTree = this.Parse(text, LanguageVersionFacts.CSharpNext); + var newTree = oldTree.WithReplaceFirst("extension", "class D"); + oldTree.GetDiagnostics().Verify(); + newTree.GetDiagnostics().Verify( + // (4,19): error CS1001: Identifier expected + // class D(object) { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(4, 19)); + + var diffs = SyntaxDifferences.GetRebuiltNodes(oldTree, newTree); + TestDiffsInOrder(diffs, + SyntaxKind.CompilationUnit, + SyntaxKind.ClassDeclaration, + SyntaxKind.ClassDeclaration, + SyntaxKind.ClassKeyword, + SyntaxKind.IdentifierToken, + SyntaxKind.ParameterList, + SyntaxKind.Parameter, + SyntaxKind.IdentifierToken); + + UsingTree(newTree, + // (4,19): error CS1001: Identifier expected + // class D(object) { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(4, 19)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "D"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact, CompilerTrait(CompilerFeature.Extensions)] + public void UpdateFromExtensionToClass_WithName() + { + var text = @" +class C +{ + extension E(object x) { } +} +"; + var oldTree = this.Parse(text, LanguageVersionFacts.CSharpNext); + var newTree = oldTree.WithReplaceFirst("extension", "class"); + oldTree.GetDiagnostics().Verify( + // (4,15): error CS9281: Extension declarations may not have a name. + // extension E(object x) { } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsName, "E").WithLocation(4, 15)); + newTree.GetDiagnostics().Verify(); + + var diffs = SyntaxDifferences.GetRebuiltNodes(oldTree, newTree); + TestDiffsInOrder(diffs, + SyntaxKind.CompilationUnit, + SyntaxKind.ClassDeclaration, + SyntaxKind.ClassDeclaration, + SyntaxKind.ClassKeyword, + SyntaxKind.IdentifierToken); + + UsingTree(newTree); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "E"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact, CompilerTrait(CompilerFeature.Extensions)] + public void UpdateFromClassToExtension() + { + var text = @" +class C +{ + class D(object x) { } +} +"; + var oldTree = this.Parse(text, LanguageVersionFacts.CSharpNext); + var newTree = oldTree.WithReplaceFirst("class D", "extension"); + oldTree.GetDiagnostics().Verify(); + newTree.GetDiagnostics().Verify(); + + var diffs = SyntaxDifferences.GetRebuiltNodes(oldTree, newTree); + TestDiffsInOrder(diffs, + SyntaxKind.CompilationUnit, + SyntaxKind.ClassDeclaration, + SyntaxKind.ExtensionDeclaration, + SyntaxKind.ExtensionKeyword); + + UsingTree(newTree); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact, CompilerTrait(CompilerFeature.Extensions)] + public void UpdateFromClassToExtension_NoParameterIdentifier() + { + var text = @" +class C +{ + class D(object) { } +} +"; + var oldTree = this.Parse(text, LanguageVersionFacts.CSharpNext); + var newTree = oldTree.WithReplaceFirst("class D", "extension"); + oldTree.GetDiagnostics().Verify( + // (4,19): error CS1001: Identifier expected + // class D(object) { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(4, 19)); + newTree.GetDiagnostics().Verify(); + + var diffs = SyntaxDifferences.GetRebuiltNodes(oldTree, newTree); + TestDiffsInOrder(diffs, + SyntaxKind.CompilationUnit, + SyntaxKind.ClassDeclaration, + SyntaxKind.ExtensionDeclaration, + SyntaxKind.ExtensionKeyword, + SyntaxKind.ParameterList, + SyntaxKind.Parameter); + + UsingTree(newTree); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact, CompilerTrait(CompilerFeature.Extensions)] + public void UpdateFromClassToExtension_WithName() + { + var text = @" +class C +{ + struct D(object x) { } +} +"; + var oldTree = this.Parse(text, LanguageVersionFacts.CSharpNext); + var newTree = oldTree.WithReplaceFirst("struct", "extension"); + oldTree.GetDiagnostics().Verify(); + newTree.GetDiagnostics().Verify( + // (4,15): error CS9281: Extension declarations may not have a name. + // extension D(object x) { } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsName, "D").WithLocation(4, 15)); + + var diffs = SyntaxDifferences.GetRebuiltNodes(oldTree, newTree); + TestDiffsInOrder(diffs, + SyntaxKind.CompilationUnit, + SyntaxKind.ClassDeclaration, + SyntaxKind.ExtensionDeclaration, + SyntaxKind.ExtensionKeyword); + + UsingTree(newTree, + // (4,15): error CS9281: Extension declarations may not have a name. + // extension D(object x) { } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsName, "D").WithLocation(4, 15)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact, CompilerTrait(CompilerFeature.Extensions)] + public void UpdateExtension_ChangeParameterList() + { + var text = """ +class C +{ + extension(object, Type z1) { } +} +"""; + var oldTree = this.Parse(text, LanguageVersionFacts.CSharpNext); + var newTree = oldTree.WithReplaceFirst("z1", "z2"); + oldTree.GetDiagnostics().Verify(); + newTree.GetDiagnostics().Verify(); + + var diffs = SyntaxDifferences.GetRebuiltNodes(oldTree, newTree); + TestDiffsInOrder(diffs, + SyntaxKind.CompilationUnit, + SyntaxKind.ClassDeclaration, + SyntaxKind.ExtensionDeclaration, + SyntaxKind.ExtensionKeyword, + SyntaxKind.ParameterList, + SyntaxKind.Parameter, + SyntaxKind.IdentifierToken); + + UsingTree(newTree); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.IdentifierToken, "z2"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + #region "Regression" #if false diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/AsyncParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/AsyncParsingTests.cs index 563f7e270746e..b99cf257d1a95 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/AsyncParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/AsyncParsingTests.cs @@ -1567,9 +1567,6 @@ class C { async partial event ", - // (4,19): error CS1519: Invalid token 'event' in class, record, struct, or interface member declaration - // async partial event - Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "event").WithArguments("event").WithLocation(4, 19), // (4,24): error CS1031: Type expected // async partial event Diagnostic(ErrorCode.ERR_TypeExpected, "").WithLocation(4, 24), @@ -1589,16 +1586,10 @@ async partial event N(SyntaxKind.ClassKeyword); N(SyntaxKind.IdentifierToken, "C"); N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.IncompleteMember); - { - N(SyntaxKind.AsyncKeyword); - N(SyntaxKind.IdentifierName); - { - N(SyntaxKind.IdentifierToken, "partial"); - } - } N(SyntaxKind.EventDeclaration); { + N(SyntaxKind.AsyncKeyword); + N(SyntaxKind.PartialKeyword); N(SyntaxKind.EventKeyword); M(SyntaxKind.IdentifierName); { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ExtensionsParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ExtensionsParsingTests.cs new file mode 100644 index 0000000000000..dbd2ceed5f107 --- /dev/null +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ExtensionsParsingTests.cs @@ -0,0 +1,4936 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable disable + +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests; + +[CompilerTrait(CompilerFeature.Extensions)] +public class ExtensionsParsingTests : ParsingTests +{ + public ExtensionsParsingTests(ITestOutputHelper output) : base(output) { } + + [Fact] + public void LangVer13() + { + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : consider giving a LangVer error to trigger UpgradeProject + UsingTree(""" +class C +{ + extension(object o) where T : struct { } +} +""", + TestOptions.Regular13, + // (3,17): error CS1519: Invalid token '(' in class, record, struct, or interface member declaration + // extension(object o) where T : struct { } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "(").WithArguments("(").WithLocation(3, 17), + // (3,26): error CS8124: Tuple must contain at least two elements. + // extension(object o) where T : struct { } + Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(3, 26), + // (3,34): error CS1002: ; expected + // extension(object o) where T : struct { } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "T").WithLocation(3, 34), + // (3,36): error CS1519: Invalid token ':' in class, record, struct, or interface member declaration + // extension(object o) where T : struct { } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ":").WithArguments(":").WithLocation(3, 36), + // (3,36): error CS1519: Invalid token ':' in class, record, struct, or interface member declaration + // extension(object o) where T : struct { } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ":").WithArguments(":").WithLocation(3, 36), + // (3,45): error CS1001: Identifier expected + // extension(object o) where T : struct { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, "{").WithLocation(3, 45)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "extension"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.GreaterThanToken); + } + } + } + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.TupleType); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.TupleElement); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "o"); + } + M(SyntaxKind.CommaToken); + M(SyntaxKind.TupleElement); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "where"); + } + } + M(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + } + N(SyntaxKind.StructDeclaration); + { + N(SyntaxKind.StructKeyword); + M(SyntaxKind.IdentifierToken); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void LangVer14(bool useCSharp14) + { + UsingTree(""" +class C +{ + extension(object o) where T : struct { } +} +""", + useCSharp14 ? TestOptions.RegularNext : TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.TypeParameterList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.TypeParameter); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "o"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.TypeParameterConstraintClause); + { + N(SyntaxKind.WhereKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.StructConstraint); + { + N(SyntaxKind.StructKeyword); + } + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MultipleConstraints() + { + UsingTree(""" +class C +{ + extension(object o) where T1 : struct where T2 : class { } +} +""", + TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.TypeParameterList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.TypeParameter); + { + N(SyntaxKind.IdentifierToken, "T1"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.TypeParameter); + { + N(SyntaxKind.IdentifierToken, "T2"); + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "o"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.TypeParameterConstraintClause); + { + N(SyntaxKind.WhereKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T1"); + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.StructConstraint); + { + N(SyntaxKind.StructKeyword); + } + } + N(SyntaxKind.TypeParameterConstraintClause); + { + N(SyntaxKind.WhereKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T2"); + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.ClassConstraint); + { + N(SyntaxKind.ClassKeyword); + } + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MultipleConstraints_Incomplete() + { + UsingTree(""" +class C +{ + extension(object o) where T1 where T2 : class { } +} +""", + TestOptions.RegularPreview, + // (3,42): error CS1003: Syntax error, ':' expected + // extension(object o) where T1 where T2 : class { } + Diagnostic(ErrorCode.ERR_SyntaxError, "where").WithArguments(":").WithLocation(3, 42), + // (3,42): error CS1031: Type expected + // extension(object o) where T1 where T2 : class { } + Diagnostic(ErrorCode.ERR_TypeExpected, "where").WithLocation(3, 42)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.TypeParameterList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.TypeParameter); + { + N(SyntaxKind.IdentifierToken, "T1"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.TypeParameter); + { + N(SyntaxKind.IdentifierToken, "T2"); + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "o"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.TypeParameterConstraintClause); + { + N(SyntaxKind.WhereKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T1"); + } + M(SyntaxKind.ColonToken); + M(SyntaxKind.TypeConstraint); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + } + N(SyntaxKind.TypeParameterConstraintClause); + { + N(SyntaxKind.WhereKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T2"); + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.ClassConstraint); + { + N(SyntaxKind.ClassKeyword); + } + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithName() + { + UsingTree(""" +class C +{ + extension Name(Type) { } +} +""", + TestOptions.RegularPreview, + // (3,15): error CS9500: Extension declarations may not have a name. + // extension Name(Type) { } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsName, "Name").WithLocation(3, 15)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithName_02() + { + UsingTree(""" +class C +{ + extension Name(Type) { } +} +""", + TestOptions.RegularPreview, + // (3,15): error CS9500: Extension declarations may not have a name. + // extension Name(Type) { } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsName, "Name").WithLocation(3, 15)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.TypeParameterList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.TypeParameter); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithDefaultParameterValue() + { + var src = """ +static class C +{ + extension(object x = null) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,15): error CS9284: The receiver parameter of an extension cannot have a default value + // extension(object x = null) { } + Diagnostic(ErrorCode.ERR_ExtensionParameterDisallowsDefaultValue, "object x = null").WithLocation(3, 15)); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "x"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithDefaultParameterValue_02() + { + var src = """ +static class C +{ + extension(object = null) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,15): error CS9284: The receiver parameter of an extension cannot have a default value + // extension(object = null) { } + Diagnostic(ErrorCode.ERR_ExtensionParameterDisallowsDefaultValue, "object = null").WithLocation(3, 15)); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithDefaultParameterValue_03() + { + var src = """ +class C +{ + extension(Type =) { } +} +"""; + UsingTree(src, TestOptions.RegularPreview, + // (3,21): error CS1525: Invalid expression term ')' + // extension(Type =) { } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(3, 21)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithBaseList() + { + var src = """ +class C +{ + extension Name(Type) : Type2() { } +} +"""; + UsingTree(src, TestOptions.RegularPreview, + // (3,15): error CS9500: Extension declarations may not have a name. + // extension Name(Type) : Type2() { } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsName, "Name").WithLocation(3, 15), + // (3,26): error CS1514: { expected + // extension Name(Type) : Type2() { } + Diagnostic(ErrorCode.ERR_LbraceExpected, ":").WithLocation(3, 26), + // (3,26): error CS1513: } expected + // extension Name(Type) : Type2() { } + Diagnostic(ErrorCode.ERR_RbraceExpected, ":").WithLocation(3, 26), + // (3,26): error CS1519: Invalid token ':' in a member declaration + // extension Name(Type) : Type2() { } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ":").WithArguments(":").WithLocation(3, 26)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + M(SyntaxKind.OpenBraceToken); + M(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.IdentifierToken, "Type2"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void TypeNamedExtension(bool useCSharp14) + { + UsingTree(""" +class extension +{ + extension(Type constructorParameter) { } +} +""", + TestOptions.Regular13); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "extension"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.IdentifierToken, "extension"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.IdentifierToken, "constructorParameter"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + + // Tracked by https://github.com/dotnet/roslyn/issues/76130 : report error for declaring type named "extension" + // Note: break from C# 13 + UsingTree(""" +class extension +{ + extension(Type constructorParameter) { } +} +""", + useCSharp14 ? TestOptions.RegularNext : TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "extension"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.IdentifierToken, "constructorParameter"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + + UsingTree(""" +class extension +{ + @extension(Type constructorParameter) { } +} +""", + useCSharp14 ? TestOptions.RegularNext : TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "extension"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.IdentifierToken, "@extension"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.IdentifierToken, "constructorParameter"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ReceiverParameter_NoName() + { + UsingTree(""" +class C +{ + extension(Type) { } +} +""", + TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ReceiverParameter_NoName_02() + { + UsingTree(""" +class C +{ + extension(object) { } +} +""", + TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ReceiverParameter_Multiple() + { + var src = """ +static class C +{ + extension(object x1, string x2) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,26): error CS9285: An extension container can have only one receiver parameter + // extension(object x1, string x2) { } + Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "string x2").WithLocation(3, 26)); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "x1"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.StringKeyword); + } + N(SyntaxKind.IdentifierToken, "x2"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ReceiverParameter_Multiple_02() + { + var src = """ +static class C +{ + extension(object, string) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,23): error CS9285: An extension container can have only one receiver parameter + // extension(object, string) { } + Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "string").WithLocation(3, 23)); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.StringKeyword); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ReceiverParameter_Multiple_03() + { + var src = """ +class C +{ + extension(object object) { } +} +"""; + UsingTree(src, TestOptions.RegularPreview, + // (3,22): error CS1003: Syntax error, ',' expected + // extension(object object) { } + Diagnostic(ErrorCode.ERR_SyntaxError, "object").WithArguments(",").WithLocation(3, 22)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ReceiverParameter_Multiple_04() + { + var src = """ +class C +{ + extension(Type, object object) { } +} +"""; + + UsingTree(src, TestOptions.RegularPreview, + // (3,28): error CS1003: Syntax error, ',' expected + // extension(Type, object object) { } + Diagnostic(ErrorCode.ERR_SyntaxError, "object").WithArguments(",").WithLocation(3, 28)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ReceiverParameter_Multiple_05() + { + var src = """ +class C +{ + extension(Type, object =) { } +} +"""; + UsingTree(src, TestOptions.RegularPreview, + // (3,29): error CS1525: Invalid expression term ')' + // extension(Type, object =) { } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(3, 29)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ReceiverParameter_Multiple_06() + { + var src = """ +class C +{ + extension(Type, object { } +} +"""; + UsingTree(src, TestOptions.RegularPreview, + // (3,28): error CS1026: ) expected + // extension(Type, object { } + Diagnostic(ErrorCode.ERR_CloseParenExpected, "{").WithLocation(3, 28)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + M(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ReceiverParameter_Multiple_07() + { + var src = """ +static class C +{ + extension(object, params object[]) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,23): error CS9285: An extension container can have only one receiver parameter + // extension(object, params object[]) { } + Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "params object[]").WithLocation(3, 23)); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.ParamsKeyword); + N(SyntaxKind.ArrayType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.ArrayRankSpecifier); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.OmittedArraySizeExpression); + { + N(SyntaxKind.OmittedArraySizeExpressionToken); + } + N(SyntaxKind.CloseBracketToken); + } + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ReceiverParameter_MissingClosingParen() + { + var src = """ +class C +{ + extension(object { } +} +"""; + + UsingTree(src, TestOptions.RegularPreview, + // (3,22): error CS1026: ) expected + // extension(object { } + Diagnostic(ErrorCode.ERR_CloseParenExpected, "{").WithLocation(3, 22)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + M(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void NoClosingBrace() + { + UsingTree(""" +class C +{ + extension(Type) { void M() { } +} +""", + TestOptions.RegularPreview, + // (4,2): error CS1513: } expected + // } + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 2)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + M(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void TopLevel() + { + var src = """ +extension(object) { } +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (1,1): error CS9283: Extensions must be declared in a top-level, non-generic, static class + // extension(Type) { } + Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(1, 1)); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void InNestedType() + { + var src = """ +static class C +{ + class Nested + { + extension(object) { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (5,9): error CS9283: Extensions must be declared in a top-level, non-generic, static class + // extension(object) { } + Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(5, 9)); + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "Nested"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void InExtension() + { + var src = """ +static class C +{ + extension(object) + { + extension(string) { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (5,9): error CS9282: Extension declarations can include only methods or properties + // extension(Type2) { } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "extension").WithLocation(5, 9)); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.StringKeyword); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithAttributes() + { + UsingTree(""" +class C +{ + [MyAttribute] + extension(Type) { } +} +""", + TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.AttributeList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "MyAttribute"); + } + } + N(SyntaxKind.CloseBracketToken); + } + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithModifiers_Partial() + { + var src = """ +static class C +{ + partial extension(Type) { } +} +"""; + + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,13): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', 'event', an instance constructor name, or a method or property return type. + // partial extension(Type) { } + Diagnostic(ErrorCode.ERR_PartialMisplaced, "extension").WithLocation(3, 13), + // (3,23): error CS0246: The type or namespace name 'Type' could not be found (are you missing a using directive or an assembly reference?) + // partial extension(Type) { } + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Type").WithArguments("Type").WithLocation(3, 23) + ); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithModifiers_Scoped() + { + UsingTree(""" +class C +{ + scoped extension(Type) { } +} +""", + TestOptions.RegularPreview, + // (3,26): error CS1001: Identifier expected + // scoped extension(Type) { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(3, 26)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "scoped"); + } + N(SyntaxKind.IdentifierToken, "extension"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithModifiers_Async() + { + UsingTree(""" +class C +{ + async extension(Type) { } +} +""", + TestOptions.RegularPreview, + // (3,25): error CS1001: Identifier expected + // async extension(Type) { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(3, 25)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "async"); + } + N(SyntaxKind.IdentifierToken, "extension"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithModifiers_Const() + { + UsingTree(""" +class C +{ + const extension(Type) { } +} +""", + TestOptions.RegularPreview, + // (3,20): error CS1001: Identifier expected + // const extension(Type) { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, "(").WithLocation(3, 20), + // (3,20): error CS1528: Expected ; or = (cannot specify constructor arguments in declaration) + // const extension(Type) { } + Diagnostic(ErrorCode.ERR_BadVarDecl, "(Type").WithLocation(3, 20), + // (3,20): error CS1003: Syntax error, '[' expected + // const extension(Type) { } + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[").WithLocation(3, 20), + // (3,25): error CS1003: Syntax error, ']' expected + // const extension(Type) { } + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]").WithLocation(3, 25), + // (3,27): error CS1003: Syntax error, ',' expected + // const extension(Type) { } + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(3, 27), + // (3,29): error CS1002: ; expected + // const extension(Type) { } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "}").WithLocation(3, 29), + // (4,1): error CS1022: Type or namespace definition, or end-of-file expected + // } + Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(4, 1)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.ConstKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "extension"); + } + N(SyntaxKind.VariableDeclarator); + { + M(SyntaxKind.IdentifierToken); + N(SyntaxKind.BracketedArgumentList); + { + M(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Argument); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + M(SyntaxKind.CloseBracketToken); + } + } + } + M(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithModifiers_Fixed() + { + UsingTree(""" +class C +{ + fixed extension(Type) { } +} +""", + TestOptions.RegularPreview, + // (3,20): error CS1001: Identifier expected + // fixed extension(Type) { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, "(").WithLocation(3, 20), + // (3,20): error CS1528: Expected ; or = (cannot specify constructor arguments in declaration) + // fixed extension(Type) { } + Diagnostic(ErrorCode.ERR_BadVarDecl, "(Type").WithLocation(3, 20), + // (3,20): error CS1003: Syntax error, '[' expected + // fixed extension(Type) { } + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[").WithLocation(3, 20), + // (3,25): error CS1003: Syntax error, ']' expected + // fixed extension(Type) { } + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]").WithLocation(3, 25), + // (3,27): error CS1003: Syntax error, ',' expected + // fixed extension(Type) { } + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(3, 27), + // (3,29): error CS1002: ; expected + // fixed extension(Type) { } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "}").WithLocation(3, 29), + // (4,1): error CS1022: Type or namespace definition, or end-of-file expected + // } + Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(4, 1)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.FixedKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "extension"); + } + N(SyntaxKind.VariableDeclarator); + { + M(SyntaxKind.IdentifierToken); + N(SyntaxKind.BracketedArgumentList); + { + M(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Argument); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + M(SyntaxKind.CloseBracketToken); + } + } + } + M(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithModifiers_Ref() + { + UsingTree(""" +class C +{ + ref extension(Type) { } +} +""", + TestOptions.RegularPreview, + // (3,18): error CS1519: Invalid token '(' in a member declaration + // ref extension(Type) { } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "(").WithArguments("(").WithLocation(3, 18), + // (3,23): error CS8124: Tuple must contain at least two elements. + // ref extension(Type) { } + Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(3, 23), + // (3,25): error CS1519: Invalid token '{' in a member declaration + // ref extension(Type) { } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "{").WithArguments("{").WithLocation(3, 25), + // (4,1): error CS1022: Type or namespace definition, or end-of-file expected + // } + Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(4, 1)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.RefType); + { + N(SyntaxKind.RefKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "extension"); + } + } + } + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.TupleType); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.TupleElement); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + M(SyntaxKind.CommaToken); + M(SyntaxKind.TupleElement); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.CloseParenToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData("abstract", SyntaxKind.AbstractKeyword)] + [InlineData("sealed", SyntaxKind.SealedKeyword)] + [InlineData("static", SyntaxKind.StaticKeyword)] + [InlineData("new", SyntaxKind.NewKeyword)] + [InlineData("public", SyntaxKind.PublicKeyword)] + [InlineData("protected", SyntaxKind.ProtectedKeyword)] + [InlineData("private", SyntaxKind.PrivateKeyword)] + [InlineData("readonly", SyntaxKind.ReadOnlyKeyword)] + [InlineData("volatile", SyntaxKind.VolatileKeyword)] + [InlineData("extern", SyntaxKind.ExternKeyword)] + [InlineData("unsafe", SyntaxKind.UnsafeKeyword)] + [InlineData("virtual", SyntaxKind.VirtualKeyword)] + [InlineData("override", SyntaxKind.OverrideKeyword)] + [InlineData("required", SyntaxKind.RequiredKeyword)] + [InlineData("file", SyntaxKind.FileKeyword)] + public void WithModifiers_Misc(string modifier, SyntaxKind expected) + { + var src = $$""" +static class C +{ + {{modifier}} extension(object) { } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (3,14): error CS0106: The modifier 'abstract' is not valid for this item + // abstract extension(object) { } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "extension").WithArguments(modifier)); + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(expected); + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Member_Const() + { + var src = """ +static class C +{ + extension(object) + { + const int i = 0; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (5,19): error CS9282: Extension declarations can include only methods or properties + // const int i = 0; + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "i").WithLocation(5, 19)); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.ConstKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "i"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "0"); + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Member_FixedField() + { + var src = """ +static class C +{ + extension(object o) + { + fixed int field[10]; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (5,19): error CS1642: Fixed size buffer fields may only be members of structs + // fixed int field[10]; + Diagnostic(ErrorCode.ERR_FixedNotInStruct, "field").WithLocation(5, 19), + // (5,19): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // fixed int field[10]; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "field[10]").WithLocation(5, 19), + // (5,19): error CS9282: Extension declarations can include only methods or properties + // fixed int field[10]; + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "field").WithLocation(5, 19)); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "o"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.FixedKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "field"); + N(SyntaxKind.BracketedArgumentList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Argument); + { + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "10"); + } + } + N(SyntaxKind.CloseBracketToken); + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Member_EventField() + { + var src = """ +static class C +{ + extension(object o) + { + event System.EventHandler eventField; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (5,35): error CS9282: Extension declarations can include only methods or properties + // event System.EventHandler eventField; + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "eventField").WithLocation(5, 35), + // (5,35): error CS9282: Extension declarations can include only methods or properties + // event System.EventHandler eventField; + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "eventField").WithLocation(5, 35), + // (5,35): error CS9282: Extension declarations can include only methods or properties + // event System.EventHandler eventField; + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "eventField").WithLocation(5, 35), + // (5,35): warning CS0067: The event 'C.extension(object).eventField' is never used + // event System.EventHandler eventField; + Diagnostic(ErrorCode.WRN_UnreferencedEvent, "eventField").WithArguments("C.extension(object).eventField").WithLocation(5, 35)); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "o"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.QualifiedName); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "System"); + } + N(SyntaxKind.DotToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "EventHandler"); + } + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "eventField"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Member_Event() + { + var src = """ +static class C +{ + extension(object o) + { + event System.EventHandler Event { add { } remove { } } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (5,35): error CS9282: Extension declarations can include only methods or properties + // event System.EventHandler Event { add { } remove { } } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "Event").WithLocation(5, 35), + // (5,43): error CS9282: Extension declarations can include only methods or properties + // event System.EventHandler Event { add { } remove { } } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "add").WithLocation(5, 43), + // (5,51): error CS9282: Extension declarations can include only methods or properties + // event System.EventHandler Event { add { } remove { } } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "remove").WithLocation(5, 51)); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "o"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.EventDeclaration); + { + N(SyntaxKind.EventKeyword); + N(SyntaxKind.QualifiedName); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "System"); + } + N(SyntaxKind.DotToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "EventHandler"); + } + } + N(SyntaxKind.IdentifierToken, "Event"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.AddAccessorDeclaration); + { + N(SyntaxKind.AddKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.RemoveAccessorDeclaration); + { + N(SyntaxKind.RemoveKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Member_MethodAndProperty() + { + UsingTree(""" +class C +{ + extension(Type) + { + void M() { } + int Property { get; set; } + } +} +""", + TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "Property"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.GetAccessorDeclaration); + { + N(SyntaxKind.GetKeyword); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.SetAccessorDeclaration); + { + N(SyntaxKind.SetKeyword); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Member_NestedType() + { + var src = """ +static class C +{ + extension(object) + { + class Nested { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (5,15): error CS9282: Extension declarations can include only methods or properties + // class Nested { } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "Nested").WithLocation(5, 15)); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "Nested"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Member_Constructor() + { + var src = """ +static class C +{ + extension(object o) + { + Constructor() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (5,9): error CS1520: Method must have a return type + // Constructor() { } + Diagnostic(ErrorCode.ERR_MemberNeedsType, "Constructor").WithLocation(5, 9), + // (5,9): error CS9282: Extension declarations can include only methods or properties + // Constructor() { } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "Constructor").WithLocation(5, 9)); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "o"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.IdentifierToken, "Constructor"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Member_StaticConstructor() + { + var src = """ +static class C +{ + extension(object) + { + static Constructor() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (5,16): error CS1520: Method must have a return type + // static Constructor() { } + Diagnostic(ErrorCode.ERR_MemberNeedsType, "Constructor").WithLocation(5, 16), + // (5,16): error CS9282: Extension declarations can include only methods or properties + // static Constructor() { } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "Constructor").WithLocation(5, 16)); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.IdentifierToken, "Constructor"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Member_Finalizer() + { + var src = """ +static class C +{ + extension(object o) + { + ~Finalizer() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (5,10): error CS9282: Extension declarations can include only methods or properties + // ~Finalizer() { } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "Finalizer").WithLocation(5, 10)); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "o"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.DestructorDeclaration); + { + N(SyntaxKind.TildeToken); + N(SyntaxKind.IdentifierToken, "Finalizer"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Member_Field() + { + var src = """ +static class C +{ + extension(object o) + { + int field; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (5,13): error CS9282: Extension declarations can include only methods or properties + // int field; + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "field").WithLocation(5, 13), + // (5,13): warning CS0169: The field 'C.extension(object).field' is never used + // int field; + Diagnostic(ErrorCode.WRN_UnreferencedField, "field").WithArguments("C.extension(object).field").WithLocation(5, 13)); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "o"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "field"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Member_Indexer() + { + var src = """ +class C +{ + extension(Type) + { + int this[int i] { get => 0; set { } } + } +} +"""; + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.IndexerDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.ThisKeyword); + N(SyntaxKind.BracketedParameterList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "i"); + } + N(SyntaxKind.CloseBracketToken); + } + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.GetAccessorDeclaration); + { + N(SyntaxKind.GetKeyword); + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "0"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.SetAccessorDeclaration); + { + N(SyntaxKind.SetKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Member_Operator() + { + var src = """ +static class C +{ + extension(object) + { + public static object operator +(object a, object b) => a; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (5,39): error CS0563: One of the parameters of a binary operator must be the containing type + // public static object operator +(object a, object b) => a; + Diagnostic(ErrorCode.ERR_BadBinaryOperatorSignature, "+").WithLocation(5, 39), + // (5,39): error CS9282: Extension declarations can include only methods or properties + // public static object operator +(object a, object b) => a; + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "+").WithLocation(5, 39)); + + UsingTree(src, TestOptions.RegularPreview); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.OperatorDeclaration); + { + N(SyntaxKind.PublicKeyword); + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.OperatorKeyword); + N(SyntaxKind.PlusToken); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "a"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "b"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "a"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Member_ConversionOperator() + { + var src = """ +static class C +{ + extension(object) + { + public static implicit operator int(object t) => 0; + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (5,41): error CS0556: User-defined conversion must convert to or from the enclosing type + // public static implicit operator int(object t) => 0; + Diagnostic(ErrorCode.ERR_ConversionNotInvolvingContainedType, "int").WithLocation(5, 41), + // (5,41): error CS9282: Extension declarations can include only methods or properties + // public static implicit operator int(object t) => 0; + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "int").WithLocation(5, 41)); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ConversionOperatorDeclaration); + { + N(SyntaxKind.PublicKeyword); + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.ImplicitKeyword); + N(SyntaxKind.OperatorKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "t"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "0"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithRef() + { + UsingTree(""" +class C +{ + ref extension(Type) { } +} +""", + TestOptions.RegularPreview, + // (3,18): error CS1519: Invalid token '(' in class, record, struct, or interface member declaration + // ref extension(Type) { } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "(").WithArguments("(").WithLocation(3, 18), + // (3,23): error CS8124: Tuple must contain at least two elements. + // ref extension(Type) { } + Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(3, 23), + // (3,25): error CS1519: Invalid token '{' in class, record, struct, or interface member declaration + // ref extension(Type) { } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "{").WithArguments("{").WithLocation(3, 25), + // (4,1): error CS1022: Type or namespace definition, or end-of-file expected + // } + Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(4, 1)); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.RefType); + { + N(SyntaxKind.RefKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "extension"); + } + } + } + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.TupleType); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.TupleElement); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + M(SyntaxKind.CommaToken); + M(SyntaxKind.TupleElement); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.CloseParenToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithAttributeOnParameter() + { + UsingTree(""" +class C +{ + extension([MyAttribute] Type) { } +} +""", + TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.AttributeList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "MyAttribute"); + } + } + N(SyntaxKind.CloseBracketToken); + } + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithModifierOnParameter() + { + UsingTree(""" +class C +{ + extension(ref Type) { } +} +""", + TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.RefKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithModifierOnParameter_Scoped() + { + UsingTree(""" +class C +{ + extension(scoped Type x) { } +} +""", + TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.ScopedKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithModifierOnParameter_ScopedRef() + { + UsingTree(""" +class C +{ + extension(scoped ref Type x) { } +} +""", + TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.ScopedKeyword); + N(SyntaxKind.RefKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData("partial")] + [InlineData("await")] + [InlineData("on")] + [InlineData("by")] + public void MiscIdentifier(string identifier) + { + UsingTree($$""" +class C +{ + extension(Type {{identifier}}) { } +} +""", + TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.IdentifierToken, identifier); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithTerminator_SemiColon() + { + UsingTree(""" +class C +{ + extension(Type) { ; + class D { } +} +""", + TestOptions.RegularPreview, + // (3,23): error CS1519: Invalid token ';' in a member declaration + // extension(Type) { ; + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(3, 23), + // (5,2): error CS1513: } expected + // } + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(5, 2)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "D"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + M(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithTerminator_SemiColon_02() + { + UsingTree(""" +class C +{ + extension(Type) { ; +} +""", + TestOptions.RegularPreview, + // (3,23): error CS1519: Invalid token ';' in a member declaration + // extension(Type) { ; + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(3, 23), + // (4,2): error CS1513: } expected + // } + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 2)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + M(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithTerminator_SemiColon_03() + { + UsingTree(""" +class C +{ + extension' expected + // extension").WithLocation(3, 17), + // (3,17): error CS1003: Syntax error, '(' expected + // extension(Type) where T : struct; + class D { } +} +""", + TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.TypeParameterList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.TypeParameter); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.TypeParameterConstraintClause); + { + N(SyntaxKind.WhereKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.StructConstraint); + { + N(SyntaxKind.StructKeyword); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "D"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithTerminator_OpenBrace() + { + UsingTree(""" +class C +{ + extension(Type) { { +} +""", + TestOptions.RegularPreview, + // (3,23): error CS1519: Invalid token '{' in a member declaration + // extension(Type) { { + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "{").WithArguments("{").WithLocation(3, 23), + // (4,2): error CS1513: } expected + // } + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 2)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + M(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithTerminator_OpenBrace_02() + { + UsingTree(""" +class C +{ + extension(Type) where { } +} +""", + TestOptions.RegularPreview, + // (3,30): error CS1001: Identifier expected + // extension(Type) where { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, "{").WithLocation(3, 30), + // (3,30): error CS1003: Syntax error, ':' expected + // extension(Type) where { } + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(":").WithLocation(3, 30), + // (3,30): error CS1031: Type expected + // extension(Type) where { } + Diagnostic(ErrorCode.ERR_TypeExpected, "{").WithLocation(3, 30)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.TypeParameterList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.TypeParameter); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.TypeParameterConstraintClause); + { + N(SyntaxKind.WhereKeyword); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + M(SyntaxKind.ColonToken); + M(SyntaxKind.TypeConstraint); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithTerminator_OpenBrace_03() + { + UsingTree(""" +class C +{ + extension(Type) where T { } + class D { } +} +""", + TestOptions.RegularPreview, + // (3,32): error CS1003: Syntax error, ':' expected + // extension(Type) where T { } + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(":").WithLocation(3, 32), + // (3,32): error CS1031: Type expected + // extension(Type) where T { } + Diagnostic(ErrorCode.ERR_TypeExpected, "{").WithLocation(3, 32)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.TypeParameterList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.TypeParameter); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.TypeParameterConstraintClause); + { + N(SyntaxKind.WhereKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + M(SyntaxKind.ColonToken); + M(SyntaxKind.TypeConstraint); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "D"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithTerminator_OpenBrace_04() + { + UsingTree(""" +class C +{ + extension(Type) where T : { } +} +""", + TestOptions.RegularPreview, + // (3,34): error CS1031: Type expected + // extension(Type) where T : { } + Diagnostic(ErrorCode.ERR_TypeExpected, "{").WithLocation(3, 34)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.TypeParameterList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.TypeParameter); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.TypeParameterConstraintClause); + { + N(SyntaxKind.WhereKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.ColonToken); + M(SyntaxKind.TypeConstraint); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithTerminator_OpenBrace_05() + { + UsingTree(""" +class C +{ + extension(Type) where T : struct, { } +} +""", + TestOptions.RegularPreview, + // (3,42): error CS1031: Type expected + // extension(Type) where T : struct, { } + Diagnostic(ErrorCode.ERR_TypeExpected, "{").WithLocation(3, 42)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.TypeParameterList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.TypeParameter); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.TypeParameterConstraintClause); + { + N(SyntaxKind.WhereKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.StructConstraint); + { + N(SyntaxKind.StructKeyword); + } + N(SyntaxKind.CommaToken); + M(SyntaxKind.TypeConstraint); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithTerminator_OpenBrace_06() + { + UsingTree(""" +class C +{ + extension' expected + // extension").WithLocation(3, 17), + // (3,17): error CS1003: Syntax error, '(' expected + // extension x, _ => y };;); + """); + + N(SyntaxKind.ForStatement); + { + N(SyntaxKind.ForKeyword); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "A"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "b"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.SwitchExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "c"); + } + N(SyntaxKind.SwitchKeyword); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.SwitchExpressionArm); + { + N(SyntaxKind.ConstantPattern); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "A"); + } + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.SwitchExpressionArm); + { + N(SyntaxKind.DiscardPattern); + { + N(SyntaxKind.UnderscoreToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "y"); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + } + } + N(SyntaxKind.SemicolonToken); + N(SyntaxKind.SemicolonToken); + N(SyntaxKind.CloseParenToken); + N(SyntaxKind.EmptyStatement); + { + N(SyntaxKind.SemicolonToken); + } + } + EOF(); + } + + [Fact] + public void TestComplexInitializer9() + { + UsingStatement(""" + for (int i =;;); + """, + // (1,13): error CS1525: Invalid expression term ';' + // for (int i =;;); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ";").WithArguments(";").WithLocation(1, 13)); + + N(SyntaxKind.ForStatement); + { + N(SyntaxKind.ForKeyword); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "i"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + } + } + N(SyntaxKind.SemicolonToken); + N(SyntaxKind.SemicolonToken); + N(SyntaxKind.CloseParenToken); + N(SyntaxKind.EmptyStatement); + { + N(SyntaxKind.SemicolonToken); + } + } + EOF(); + } + + [Fact] + public void TestComplexInitializer10() + { + UsingStatement(""" + for (int i = 0, j =;;); + """, + // (1,20): error CS1525: Invalid expression term ';' + // for (int i = 0, j =;;); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ";").WithArguments(";").WithLocation(1, 20)); + + N(SyntaxKind.ForStatement); + { + N(SyntaxKind.ForKeyword); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "i"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "0"); + } + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "j"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + } + } + N(SyntaxKind.SemicolonToken); + N(SyntaxKind.SemicolonToken); + N(SyntaxKind.CloseParenToken); + N(SyntaxKind.EmptyStatement); + { + N(SyntaxKind.SemicolonToken); + } + } + EOF(); + } } diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaAttributeParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaAttributeParsingTests.cs index 50984cae0d14a..d18d7f741cabc 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaAttributeParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaAttributeParsingTests.cs @@ -4519,7 +4519,7 @@ void M() } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73789")] - public void ParseAttributeWithLambaPathological() + public void ParseAttributeWithLambdaPathological() { // Ensure we can parse this pathological lambda attribute code without getting into exponential time. int n = 30; diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs index 863aad136bf7c..8b982117a0f2a 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs @@ -10120,7 +10120,7 @@ public void UncheckedOperatorDeclaration_04(string op, SyntaxKind opToken) [Theory, WorkItem(60394, "https://github.com/dotnet/roslyn/issues/60394")] [InlineData("implicit", SyntaxKind.ImplicitKeyword)] [InlineData("explicit", SyntaxKind.ExplicitKeyword)] - public void UnheckedOperatorDeclaration_05(string op, SyntaxKind opToken) + public void UncheckedOperatorDeclaration_05(string op, SyntaxKind opToken) { UsingDeclaration(op + " operator unchecked D(C x) => x;", expectedErrors: // (1,19): error CS9027: Unexpected keyword 'unchecked' diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/PartialEventsAndConstructorsParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/PartialEventsAndConstructorsParsingTests.cs new file mode 100644 index 0000000000000..62eb5c4c8a0cd --- /dev/null +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/PartialEventsAndConstructorsParsingTests.cs @@ -0,0 +1,1528 @@ +// Licensed to the .NET Foundation under one or more agreements. +// 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.Test.Utilities; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests; + +public sealed class PartialEventsAndConstructorsParsingTests(ITestOutputHelper output) : ParsingTests(output) +{ + private sealed class CSharp14_Preview() + : CombinatorialValuesAttribute(LanguageVersionFacts.CSharpNext, LanguageVersion.Preview); + + private sealed class CSharp13_CSharp14_Preview() + : CombinatorialValuesAttribute(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext, LanguageVersion.Preview); + + [Theory, CombinatorialData] + public void Event_Tree([CSharp14_Preview] LanguageVersion langVersion) + { + UsingTree(""" + partial class C + { + partial event Action E; + partial event Action E { add { } remove { } } + } + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "E"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.EventDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.IdentifierToken, "E"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.AddAccessorDeclaration); + { + N(SyntaxKind.AddKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.RemoveAccessorDeclaration); + { + N(SyntaxKind.RemoveKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Definition([CSharp13_CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial event Action E; + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "E"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Definition_Multiple([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial event Action E, F; + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "E"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "F"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Definition_Initializer([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial event Action E = null; + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "E"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Definition_Multiple_Initializer([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial event Action E, F = null; + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "E"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "F"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Definition_Multiple_Initializers([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial event Action E = null, F = null; + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "E"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "F"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Definition_PartialAfterEvent([CSharp13_CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + event partial Action E; + """, + TestOptions.Regular.WithLanguageVersion(langVersion), + // (1,7): error CS1031: Type expected + // event partial Action E; + Diagnostic(ErrorCode.ERR_TypeExpected, "partial").WithLocation(1, 7), + // (1,7): error CS1525: Invalid expression term 'partial' + // event partial Action E; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "partial").WithArguments("partial").WithLocation(1, 7), + // (1,7): error CS1003: Syntax error, ',' expected + // event partial Action E; + Diagnostic(ErrorCode.ERR_SyntaxError, "partial").WithArguments(",").WithLocation(1, 7)); + + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.EventKeyword); + M(SyntaxKind.VariableDeclaration); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + M(SyntaxKind.VariableDeclarator); + { + M(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Definition_PartialAfterType([CSharp13_CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + event Action partial E; + """, + TestOptions.Regular.WithLanguageVersion(langVersion), + // (1,22): error CS1003: Syntax error, ',' expected + // event Action partial E; + Diagnostic(ErrorCode.ERR_SyntaxError, "E").WithArguments(",").WithLocation(1, 22)); + + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Definition_PartialAfterPublic([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + public partial event Action E; + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.PublicKeyword); + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "E"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Definition_PartialBeforePublic([CSharp13_CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial public event Action E; + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.PublicKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "E"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Definition_DoublePartial([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial partial event Action E; + """, + TestOptions.Regular.WithLanguageVersion(langVersion), + // (1,9): error CS1525: Invalid expression term 'partial' + // partial partial event Action E; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "partial").WithArguments("partial").WithLocation(1, 9), + // (1,9): error CS1003: Syntax error, ',' expected + // partial partial event Action E; + Diagnostic(ErrorCode.ERR_SyntaxError, "partial").WithArguments(",").WithLocation(1, 9)); + + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + M(SyntaxKind.VariableDeclarator); + { + M(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Definition_MissingRest([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial event + """, + TestOptions.Regular.WithLanguageVersion(langVersion), + // (1,14): error CS1031: Type expected + // partial event + Diagnostic(ErrorCode.ERR_TypeExpected, "").WithLocation(1, 14), + // (1,14): error CS1514: { expected + // partial event + Diagnostic(ErrorCode.ERR_LbraceExpected, "").WithLocation(1, 14), + // (1,14): error CS1513: } expected + // partial event + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(1, 14)); + + N(SyntaxKind.EventDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EventKeyword); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + M(SyntaxKind.IdentifierToken); + M(SyntaxKind.AccessorList); + { + M(SyntaxKind.OpenBraceToken); + M(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Implementation([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial event Action E { add { } remove { } } + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.EventDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.IdentifierToken, "E"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.AddAccessorDeclaration); + { + N(SyntaxKind.AddKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.RemoveAccessorDeclaration); + { + N(SyntaxKind.RemoveKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Implementation_Multiple([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial event Action E, F { add { } remove { } } + """, + TestOptions.Regular.WithLanguageVersion(langVersion), + // (1,27): error CS1003: Syntax error, ',' expected + // partial event Action E, F { add { } remove { } } + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(1, 27), + // (1,49): error CS1002: ; expected + // partial event Action E, F { add { } remove { } } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 49)); + + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "E"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "F"); + } + } + M(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Implementation_PartialAfterEvent([CSharp13_CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + event partial Action E { add { } remove { } } + """, + TestOptions.Regular.WithLanguageVersion(langVersion), + // (1,7): error CS1031: Type expected + // event partial Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_TypeExpected, "partial").WithLocation(1, 7), + // (1,7): error CS1525: Invalid expression term 'partial' + // event partial Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "partial").WithArguments("partial").WithLocation(1, 7), + // (1,7): error CS1003: Syntax error, ',' expected + // event partial Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_SyntaxError, "partial").WithArguments(",").WithLocation(1, 7), + // (1,46): error CS1002: ; expected + // event partial Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 46)); + + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.EventKeyword); + M(SyntaxKind.VariableDeclaration); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + M(SyntaxKind.VariableDeclarator); + { + M(SyntaxKind.IdentifierToken); + } + } + M(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Implementation_SemicolonAccessors([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial event Action E { add; remove; } + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.EventDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.IdentifierToken, "E"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.AddAccessorDeclaration); + { + N(SyntaxKind.AddKeyword); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.RemoveAccessorDeclaration); + { + N(SyntaxKind.RemoveKeyword); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Implementation_PartialAccessors([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial event Action E { partial add; partial remove; } + """, + TestOptions.Regular.WithLanguageVersion(langVersion), + // (1,26): error CS1055: An add or remove accessor expected + // partial event Action E { partial add; partial remove; } + Diagnostic(ErrorCode.ERR_AddOrRemoveExpected, "partial").WithLocation(1, 26), + // (1,39): error CS1055: An add or remove accessor expected + // partial event Action E { partial add; partial remove; } + Diagnostic(ErrorCode.ERR_AddOrRemoveExpected, "partial").WithLocation(1, 39)); + + N(SyntaxKind.EventDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.IdentifierToken, "E"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.UnknownAccessorDeclaration); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + N(SyntaxKind.AddAccessorDeclaration); + { + N(SyntaxKind.AddKeyword); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.UnknownAccessorDeclaration); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + N(SyntaxKind.RemoveAccessorDeclaration); + { + N(SyntaxKind.RemoveKeyword); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_InPlaceOfIdentifier([CSharp14_Preview] LanguageVersion langVersion) + { + UsingTree(""" + partial class C + { + [Attr( + partial event Action E; + } + """, + TestOptions.Regular.WithLanguageVersion(langVersion), + // (3,11): error CS1026: ) expected + // [Attr( + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(3, 11), + // (3,11): error CS1003: Syntax error, ']' expected + // [Attr( + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]").WithLocation(3, 11)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.AttributeList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Attr"); + } + N(SyntaxKind.AttributeArgumentList); + { + N(SyntaxKind.OpenParenToken); + M(SyntaxKind.CloseParenToken); + } + } + M(SyntaxKind.CloseBracketToken); + } + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "E"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Constructor_Tree([CSharp14_Preview] LanguageVersion langVersion) + { + UsingTree(""" + partial class C + { + partial C(); + partial C() { } + } + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Constructor_Declaration([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial C() { } + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Fact] + public void Constructor_Declaration_CSharp13() + { + UsingDeclaration(""" + partial C() { } + """, + TestOptions.Regular13); + + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Theory, CombinatorialData] + public void Constructor_ArrowBody([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial C() => throw null; + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.ThrowExpression); + { + N(SyntaxKind.ThrowKeyword); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Constructor_NoParens([CSharp13_CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial C; + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "C"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Constructor_NoName([CSharp13_CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial (); + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.IdentifierToken, "partial"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Constructor_PartialAsName([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial partial(); + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.IdentifierToken, "partial"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Constructor_PartialAfterName([CSharp13_CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + C partial(); + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + N(SyntaxKind.IdentifierToken, "partial"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Constructor_PartialAfterPublic([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + public partial C(); + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.PublicKeyword); + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Constructor_PartialBeforePublic([CSharp13_CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial public C(); + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.PublicKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Constructor_TypeTwice([CSharp13_CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial C C(); + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Constructor_PartialEscaped([CSharp13_CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + @partial C(); + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "@partial"); + } + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Constructor_KeywordName([CSharp13_CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial const(); + """, + TestOptions.Regular.WithLanguageVersion(langVersion), + // (1,1): error CS1073: Unexpected token 'const' + // partial const(); + Diagnostic(ErrorCode.ERR_UnexpectedToken, "partial").WithArguments("const").WithLocation(1, 1), + // (1,9): error CS1519: Invalid token 'const' in class, record, struct, or interface member declaration + // partial const(); + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "const").WithArguments("const").WithLocation(1, 9)); + + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + } + EOF(); + } + + [Theory, CombinatorialData] + public void Constructor_InPlaceOfIdentifier([CSharp14_Preview] LanguageVersion langVersion) + { + UsingTree(""" + partial class C + { + [Attr( + partial C(); + } + """, + TestOptions.Regular.WithLanguageVersion(langVersion), + // (3,11): error CS1026: ) expected + // [Attr( + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(3, 11), + // (3,11): error CS1003: Syntax error, ']' expected + // [Attr( + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]").WithLocation(3, 11)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.AttributeList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Attr"); + } + N(SyntaxKind.AttributeArgumentList); + { + N(SyntaxKind.OpenParenToken); + M(SyntaxKind.CloseParenToken); + } + } + M(SyntaxKind.CloseBracketToken); + } + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void ReturningPartialType_LocalFunction_InMethod([CSharp14_Preview] LanguageVersion langVersion) + { + UsingTree(""" + class C + { + void M() + { + partial F() => null; + } + } + """, + TestOptions.Regular.WithLanguageVersion(langVersion), + // (4,6): error CS1513: } expected + // { + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 6), + // (7,1): error CS1022: Type or namespace definition, or end-of-file expected + // } + Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(7, 1)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + M(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.IdentifierToken, "F"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ReturningPartialType_LocalFunction_InMethod_CSharp13() + { + UsingTree(""" + class C + { + void M() + { + partial F() => null; + } + } + """, + TestOptions.Regular13); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalFunctionStatement); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + N(SyntaxKind.IdentifierToken, "F"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void ReturningPartialType_LocalFunction_TopLevel([CSharp14_Preview] LanguageVersion langVersion) + { + UsingTree(""" + partial F() => null; + """, + TestOptions.Regular.WithLanguageVersion(langVersion), + // (1,9): error CS0116: A namespace cannot directly contain members such as fields, methods or statements + // partial F() => null; + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "F").WithLocation(1, 9)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "F"); + } + } + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.ExpressionStatement); + { + N(SyntaxKind.ParenthesizedLambdaExpression); + { + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ReturningPartialType_LocalFunction_TopLevel_CSharp13() + { + UsingTree(""" + partial F() => null; + """, + TestOptions.Regular13); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalFunctionStatement); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + N(SyntaxKind.IdentifierToken, "F"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void ReturningPartialType_Method([CSharp14_Preview] LanguageVersion langVersion) + { + UsingTree(""" + class C + { + partial M() => null; + @partial M() => null; + } + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "@partial"); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ReturningPartialType_Method_CSharp13() + { + UsingTree(""" + class C + { + partial M() => null; + @partial M() => null; + } + """, + TestOptions.Regular13); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "@partial"); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } +} diff --git a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs index bcb044788b178..4abda44062fae 100644 --- a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs @@ -3790,6 +3790,26 @@ void goo() "}"); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76856")] + public void TestNormalizeDocumentationMultiLineCommentsWithTrailingNewline() + { + TestNormalizeStatement(""" + /** + * + * Escape XML special characters + */ + private String EscapeXML(String str) + { + """, """ + /// + /// + /// Escape XML special characters + ////// + private String EscapeXML(String str) + { + """); + } + [Fact] public void TestNormalizeEOL() { diff --git a/src/Compilers/Core/CodeAnalysisTest/AnalyzerAssemblyLoaderTests.cs b/src/Compilers/Core/CodeAnalysisTest/AnalyzerAssemblyLoaderTests.cs index ee3925cc2d9ef..a21427abe5c62 100644 --- a/src/Compilers/Core/CodeAnalysisTest/AnalyzerAssemblyLoaderTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/AnalyzerAssemblyLoaderTests.cs @@ -23,6 +23,9 @@ using Basic.Reference.Assemblies; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.UnitTests.Diagnostics; +using System.Diagnostics; +using System.ComponentModel; #if NET using Roslyn.Test.Utilities.CoreClr; @@ -69,20 +72,6 @@ public enum AnalyzerTestKind /// /// Similar to Limitation 1 is when the dependency, B.dll, is already present in the Load or LoadFrom context /// then that will be used. The runtime will not attempt to load a better version (an exact match for example). - /// - /// Limitation 3: Shadow copy breaks up directories - /// - /// The shadow copy loader strategy is to put every analyzer dependency into a different shadow directory. That - /// means if A.dll and B.dll are in the same directory for a normal load, they are in different directories - /// during a shadow copy load. - /// - /// This causes significant issues in .NET Framework because we don't have the ability to know where a load - /// is coming from. The AppDomain.AssemblyResolve event just requests "B, Version=1.0.0.0" but gives no context - /// as to where the request is coming from. That means we often end up loading a different copy of B.dll in a - /// shadow load scenario. - /// - /// Long term this is something that needs to be addressed. Tracked by https://github.com/dotnet/roslyn/issues/66532 - /// /// [Collection(AssemblyLoadTestFixtureCollection.Name)] public sealed class AnalyzerAssemblyLoaderTests : TestBase @@ -102,95 +91,106 @@ public AnalyzerAssemblyLoaderTests(ITestOutputHelper testOutputHelper, AssemblyL private void Run( AnalyzerTestKind kind, Action testAction, - IAnalyzerAssemblyResolver[]? externalResolvers = null, - [CallerMemberName] string? memberName = null) => + ImmutableArray pathResolvers = default, + ImmutableArray assemblyResolvers = default) => Run( kind, - static (_, _) => { }, - testAction, - externalResolvers, - memberName); + state: null, + testAction.Method, + pathResolvers.NullToEmpty(), + assemblyResolvers.NullToEmpty()); private void Run( AnalyzerTestKind kind, object state, Action testAction, - IAnalyzerAssemblyResolver[]? externalResolvers = null, - [CallerMemberName] string? memberName = null) => + ImmutableArray pathResolvers = default, + ImmutableArray assemblyResolvers = default) => Run( kind, state, - static (_, _) => { }, testAction.Method, - externalResolvers, - memberName); + pathResolvers.NullToEmpty(), + assemblyResolvers.NullToEmpty()); private void Run( AnalyzerTestKind kind, - Action prepLoadContextAction, - Action testAction, - IAnalyzerAssemblyResolver[]? externalResolvers = null, - [CallerMemberName] string? memberName = null) => - Run( + object? state, + MethodInfo method, + ImmutableArray pathResolvers, + ImmutableArray assemblyResolvers) + { + var util = new InvokeUtil(); + util.Exec( + TestOutputHelper, + pathResolvers, + assemblyResolvers, + TestFixture, kind, - state: null, - prepLoadContextAction, - testAction.Method, - externalResolvers, - memberName); + method.DeclaringType!.FullName!, + method.Name, + state); + } private void Run( - AnalyzerTestKind kind, - object? state, - Action prepLoadContextAction, - MethodInfo method, - IAnalyzerAssemblyResolver[]? externalResolvers, - string? memberName) + AnalyzerAssemblyLoader loader, + Action testAction) { - var alc = new AssemblyLoadContext($"Test {memberName}", isCollectible: true); - try - { - prepLoadContextAction(alc, TestFixture); - var util = new InvokeUtil(); - util.Exec(TestOutputHelper, alc, TestFixture, kind, method.DeclaringType!.FullName!, method.Name, externalResolvers ?? [], state); - } - finally - { - alc.Unload(); - } + var util = new InvokeUtil(); + util.Exec( + TestOutputHelper, + TestFixture, + loader, + testAction.Method.DeclaringType!.FullName!, + testAction.Method.Name, + state: null); } + private void Run( + AnalyzerAssemblyLoader loader, + object state, + Action testAction) + { + var util = new InvokeUtil(); + util.Exec( + TestOutputHelper, + TestFixture, + loader, + testAction.Method.DeclaringType!.FullName!, + testAction.Method.Name, + state: state); + } #else private void Run( AnalyzerTestKind kind, Action testAction, - IAnalyzerAssemblyResolver[]? externalResolvers = null, + ImmutableArray pathResolvers = default, [CallerMemberName] string? memberName = null) => Run( kind, state: null, testAction.Method, - externalResolvers, + pathResolvers.NullToEmpty(), memberName); private void Run( AnalyzerTestKind kind, object state, Action testAction, - IAnalyzerAssemblyResolver[]? externalResolvers = null, + ImmutableArray pathResolvers = default, [CallerMemberName] string? memberName = null) => Run(kind, state, testAction.Method, - externalResolvers, + pathResolvers.NullToEmpty(), memberName); private void Run( AnalyzerTestKind kind, object state, MethodInfo method, - IAnalyzerAssemblyResolver[]? externalResolvers, + ImmutableArray pathResolvers, string? memberName) { AppDomain? appDomain = null; @@ -200,7 +200,7 @@ private void Run( var testOutputHelper = new AppDomainTestOutputHelper(TestOutputHelper); var type = typeof(InvokeUtil); var util = (InvokeUtil)appDomain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName); - util.Exec(testOutputHelper, TestFixture, kind, method.DeclaringType.FullName, method.Name, externalResolvers ?? [], state); + util.Exec(testOutputHelper, TestFixture, kind, method.DeclaringType.FullName, method.Name, pathResolvers.ToArray(), state); } finally { @@ -264,8 +264,8 @@ public void AddDependencyLocationThrowsOnNull(AnalyzerTestKind kind) { Run(kind, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture) => { - Assert.Throws("fullPath", () => loader.AddDependencyLocation(null!)); - Assert.Throws("fullPath", () => loader.AddDependencyLocation("a")); + Assert.Throws("originalPath", () => loader.AddDependencyLocation(null!)); + Assert.Throws("originalPath", () => loader.AddDependencyLocation("a")); }); } @@ -327,30 +327,22 @@ public void AssemblyLoading_Multiple(AnalyzerTestKind kind) } /// - /// The loaders should not actually look at the contents of the disk until a - /// call has occurred. This is historical behavior that doesn't have a clear reason for existing. There - /// is strong suspicion it's to delay loading of analyzers until absolutely necessary. As such we're - /// enshrining the behavior here so it is not _accidentally_ changed. + /// The loaders should not _require_ contents to actually be on disk until the + /// call has occurred. If the file + /// contents were required immediately then would throw in its ctor + /// rather than when using the reference. /// [Theory] [CombinatorialData] - public void AssemblyLoading_OverwriteBeforeLoad(AnalyzerTestKind kind) + public void AssemblyLoading_AssemblyLocationInvalid(AnalyzerTestKind kind) { Run(kind, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture) => { using var temp = new TempRoot(); var tempDir = temp.CreateDirectory(); - var delta1Copy = tempDir.CreateDirectory("a").CreateFile("Delta.dll").CopyContentFrom(testFixture.Delta1).Path; - loader.AddDependencyLocation(delta1Copy); - File.Copy(testFixture.Delta2, delta1Copy, overwrite: true); - var assembly = loader.LoadFromPath(delta1Copy); - - var name = AssemblyName.GetAssemblyName(testFixture.Delta2); - Assert.Equal(name.FullName, assembly.GetName().FullName); - - VerifyDependencyAssemblies( - loader, - delta1Copy); + var analyzerPath = Path.Combine(tempDir.CreateDirectory("a").Path, "analyzer.dll"); + loader.AddDependencyLocation(analyzerPath); + Assert.Throws(() => loader.LoadFromPath(analyzerPath)); }); } @@ -362,7 +354,7 @@ public void AssemblyLoading_AssemblyLocationNotAdded(AnalyzerTestKind kind) { loader.AddDependencyLocation(testFixture.Gamma); loader.AddDependencyLocation(testFixture.Delta1); - Assert.Throws(() => loader.LoadFromPath(testFixture.Beta)); + Assert.Throws(() => loader.LoadFromPath(testFixture.Beta)); }); } @@ -370,7 +362,7 @@ public void AssemblyLoading_AssemblyLocationNotAdded(AnalyzerTestKind kind) [CombinatorialData] public void AssemblyLoading_DependencyLocationNotAdded(AnalyzerTestKind kind) { - Run(kind, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture) => + Run(kind, state: kind, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture, object state) => { StringBuilder sb = new StringBuilder(); @@ -381,7 +373,7 @@ public void AssemblyLoading_DependencyLocationNotAdded(AnalyzerTestKind kind) var b = beta.CreateInstance("Beta.B")!; var writeMethod = b.GetType().GetMethod("Write")!; - if (ExecutionConditionUtil.IsCoreClr || loader is ShadowCopyAnalyzerAssemblyLoader) + if (ExecutionConditionUtil.IsCoreClr || state is AnalyzerTestKind.ShadowLoad) { // We don't pass Alpha's path to AddDependencyLocation here, and therefore expect // calling Beta.B.Write to fail because loader will prevent the load of Alpha @@ -408,16 +400,27 @@ private static void VerifyAssemblies(AnalyzerAssemblyLoader loader, IEnumerable< private static void VerifyAssemblies(AnalyzerAssemblyLoader loader, IEnumerable assemblies, int? expectedCopyCount, params (string simpleName, string version, string path)[] expected) { - Assert.Equal( - expected - .Select(x => (x.simpleName, x.version, getExpectedLoadPath(x.path))) - .OrderBy(static x => x) - .ToArray(), - assemblies.Select(assembly => (assembly.GetName().Name!, assembly.GetName().Version!.ToString(), assembly.Location)) + var expectedVersions = expected + .Select(x => $"{x.simpleName} {x.version}") + .OrderBy(static x => x) + .ToArray(); + var assemblyVersions = assemblies + .Select(assembly => $"{assembly.GetName().Name!} {assembly.GetName().Version}") .OrderBy(static x => x) - .ToArray()); + .ToArray(); + Assert.Equal(expectedVersions, assemblyVersions); + + var expectedPaths = expected + .Select(x => getExpectedLoadPath(x.path)) + .OrderBy(static x => x) + .ToArray(); + var assemblyPaths = assemblies + .Select(x => x.Location) + .OrderBy(static x => x) + .ToArray(); + Assert.Equal(expectedPaths, assemblyPaths); - if (loader is ShadowCopyAnalyzerAssemblyLoader shadowLoader) + if (loader.AnalyzerPathResolvers.OfType().FirstOrDefault() is { } shadowLoader) { Assert.All(assemblies, x => x.Location.StartsWith(shadowLoader.BaseDirectory, StringComparison.Ordinal)); Assert.Equal(expectedCopyCount ?? expected.Length, shadowLoader.CopyCount); @@ -426,7 +429,7 @@ private static void VerifyAssemblies(AnalyzerAssemblyLoader loader, IEnumerable< string getExpectedLoadPath(string path) { #if NET - if (loader is AnalyzerAssemblyLoader { AnalyzerLoadOption: AnalyzerLoadOption.LoadFromStream }) + if (loader.AnalyzerAssemblyResolvers.Any(x => x == AnalyzerAssemblyLoader.StreamAnalyzerAssemblyResolver)) { return ""; } @@ -434,14 +437,14 @@ string getExpectedLoadPath(string path) if (path.EndsWith(".resources.dll", StringComparison.Ordinal)) { - return getRealSatelliteLoadPath(path) ?? ""; + return getRealSatellitePath(path) ?? ""; } - return loader.GetRealAnalyzerLoadPath(path ?? ""); + return loader.GetResolvedAnalyzerPath(path ?? ""); } // When PreparePathToLoad is overridden this returns the most recent // real path for the given analyzer satellite assembly path - string? getRealSatelliteLoadPath(string originalSatelliteFullPath) + string? getRealSatellitePath(string originalSatelliteFullPath) { // This is a satellite assembly, need to find the mapped path of the real assembly, then // adjust that mapped path for the suffix of the satellite assembly @@ -458,7 +461,7 @@ string getExpectedLoadPath(string path) // Real assembly is located in the directory above this one var assemblyPath = Path.Combine(assemblyDir, assemblyFileName); - return loader.GetRealSatelliteLoadPath(assemblyPath, cultureInfo); + return loader.GetResolvedSatellitePath(assemblyPath, cultureInfo); } } @@ -495,6 +498,13 @@ private static void VerifyDependencyAssemblies(AnalyzerAssemblyLoader loader, in .GetAssemblies() .Where(x => isInLoadFromContext(loader, x)); + // When debugging, the debugger will load this DLL and that can throw off the debugging + // session so exclude it here. + if (Debugger.IsAttached) + { + loadedAssemblies = loadedAssemblies.Where(x => x.GetName().Name != "Microsoft.VisualStudio.Debugger.Runtime.Desktop"); + } + static bool isInLoadFromContext(AnalyzerAssemblyLoader loader, Assembly assembly) { var undidHook = false; @@ -594,7 +604,7 @@ public void AssemblyLoading_DependencyInDifferentDirectory(AnalyzerTestKind kind [CombinatorialData] public void AssemblyLoading_RazorCompiler1(AnalyzerTestKind kind) { - Run(kind, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture) => + Run(kind, state: kind, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture, object state) => { using var temp = new TempRoot(); var tempDir = temp.CreateDirectory(); @@ -609,7 +619,7 @@ public void AssemblyLoading_RazorCompiler1(AnalyzerTestKind kind) // Even though EA.RazorCompiler is loaded from the compiler directory the shadow copy loader // still does a defensive copy. - var copyCount = loader is ShadowCopyAnalyzerAssemblyLoader + var copyCount = state is AnalyzerTestKind.ShadowLoad ? 1 : (int?)null; @@ -628,7 +638,7 @@ public void AssemblyLoading_RazorCompiler1(AnalyzerTestKind kind) [CombinatorialData] public void AssemblyLoading_RazorCompiler2(AnalyzerTestKind kind) { - Run(kind, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture) => + Run(kind, state: kind, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture, object state) => { using var temp = new TempRoot(); var tempDir = temp.CreateDirectory(); @@ -647,7 +657,7 @@ public void AssemblyLoading_RazorCompiler2(AnalyzerTestKind kind) // Even though EA.RazorCompiler is loaded from the compiler directory the shadow copy loader // still does a defensive copy. - var copyCount = loader is ShadowCopyAnalyzerAssemblyLoader + var copyCount = state is AnalyzerTestKind.ShadowLoad ? 2 : (int?)null; VerifyDependencyAssemblies( @@ -667,7 +677,7 @@ public void AssemblyLoading_RazorCompiler2(AnalyzerTestKind kind) [CombinatorialData] public void AssemblyLoading_DependencyInDifferentDirectory2(AnalyzerTestKind kind) { - Run(kind, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture) => + Run(kind, state: kind, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture, object state) => { using var temp = new TempRoot(); var tempDir = temp.CreateDirectory(); @@ -694,22 +704,11 @@ public void AssemblyLoading_DependencyInDifferentDirectory2(AnalyzerTestKind kin Assert.Equal(@"Delta: Gamma: Test G ", actual); - if (ExecutionConditionUtil.IsDesktop && loader is ShadowCopyAnalyzerAssemblyLoader) - { - // See limitation 3 - VerifyDependencyAssemblies( - loader, - deltaFile1, - gammaFile); - } - else - { - VerifyDependencyAssemblies( - loader, - deltaFile2, - gammaFile); - - } + VerifyDependencyAssemblies( + loader, + copyCount: 3, + deltaFile2, + gammaFile); }); } @@ -765,8 +764,8 @@ public void AssemblyLoading_DependencyInDifferentDirectory4(AnalyzerTestKind kin var analyzerDependencyReference = new AnalyzerFileReference(analyzerDependencyFile, loader); analyzerDependencyReference.AnalyzerLoadFailed += (_, e) => AssertEx.Fail(e.Exception!.Message); - Assert.True(loader.IsAnalyzerDependencyPath(analyzerMainFile)); - Assert.True(loader.IsAnalyzerDependencyPath(analyzerDependencyFile)); + Assert.NotNull(loader.GetResolvedAnalyzerPath(analyzerMainFile)); + Assert.NotNull(loader.GetResolvedAnalyzerPath(analyzerDependencyFile)); var analyzers = analyzerMainReference.GetAnalyzersForAllLanguages(); Assert.Equal(1, analyzers.Length); @@ -842,7 +841,7 @@ public void AssemblyLoading_MultipleVersions(AnalyzerTestKind kind) [CombinatorialData] public void AssemblyLoading_MultipleVersions_NoExactMatch(AnalyzerTestKind kind) { - Run(kind, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture) => + Run(kind, state: kind, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture, object state) => { StringBuilder sb = new StringBuilder(); @@ -855,7 +854,7 @@ public void AssemblyLoading_MultipleVersions_NoExactMatch(AnalyzerTestKind kind) e.GetType().GetMethod("Write")!.Invoke(e, new object[] { sb, "Test E" }); var actual = sb.ToString(); - if (ExecutionConditionUtil.IsCoreClr || loader is ShadowCopyAnalyzerAssemblyLoader) + if (ExecutionConditionUtil.IsCoreClr || state is AnalyzerTestKind.ShadowLoad) { // In .NET Core we have _full_ control over assembly loading and can prevent implicit // loads from probing paths. That means we can avoid implicitly loading the Delta v2 @@ -880,7 +879,7 @@ public void AssemblyLoading_MultipleVersions_NoExactMatch(AnalyzerTestKind kind) { // See limitation 1 // The Epsilon.dll has Delta.dll (v2) next to it in the directory. - Assert.Throws(() => loader.GetRealAnalyzerLoadPath(testFixture.Delta2)); + Assert.Throws(() => loader.GetResolvedAnalyzerPath(testFixture.Delta2)); // Fake the dependency so we can verify the rest of the load loader.AddDependencyLocation(testFixture.Delta2); @@ -901,7 +900,7 @@ public void AssemblyLoading_MultipleVersions_NoExactMatch(AnalyzerTestKind kind) [CombinatorialData] public void AssemblyLoading_MultipleVersions_MultipleEqualMatches(AnalyzerTestKind kind) { - Run(kind, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture) => + Run(kind, state: kind, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture, object state) => { StringBuilder sb = new StringBuilder(); @@ -913,37 +912,19 @@ public void AssemblyLoading_MultipleVersions_MultipleEqualMatches(AnalyzerTestKi var e = epsilon.CreateInstance("Epsilon.E")!; e.GetType().GetMethod("Write")!.Invoke(e, new object[] { sb, "Test E" }); - if (ExecutionConditionUtil.IsDesktop && loader is ShadowCopyAnalyzerAssemblyLoader) - { - // Delta2B and Delta2 have the same version, but we prefer Delta2B because it's added first and - // in shadow loader we can't fall back to same directory because the runtime doesn't provide - // context for who requested the load. Just have to go to best version. - VerifyDependencyAssemblies( - loader, - testFixture.Delta2B, - testFixture.Epsilon); - - var actual = sb.ToString(); - Assert.Equal( - @"Delta.2B: Epsilon: Test E -", - actual); - } - else - { - // See limitation 1 - // Delta2B and Delta2 have the same version, but we prefer Delta2 because it's in the same directory as Epsilon. - VerifyDependencyAssemblies( - loader, - testFixture.Delta2, - testFixture.Epsilon); + // See limitation 1 + // Delta2B and Delta2 have the same version, but we prefer Delta2 because it's in the same directory as Epsilon. + VerifyDependencyAssemblies( + loader, + copyCount: 3, + testFixture.Delta2, + testFixture.Epsilon); - var actual = sb.ToString(); - Assert.Equal( - @"Delta.2: Epsilon: Test E + var actual = sb.ToString(); + Assert.Equal( +@"Delta.2: Epsilon: Test E ", - actual); - } + actual); }); } @@ -951,7 +932,7 @@ public void AssemblyLoading_MultipleVersions_MultipleEqualMatches(AnalyzerTestKi [CombinatorialData] public void AssemblyLoading_MultipleVersions_MultipleVersionsOfSameAnalyzerItself(AnalyzerTestKind kind) { - Run(kind, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture) => + Run(kind, state: kind, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture, object state) => { StringBuilder sb = new StringBuilder(); @@ -966,11 +947,11 @@ public void AssemblyLoading_MultipleVersions_MultipleVersionsOfSameAnalyzerItsel #if NET // On Core, we're able to load both of these into separate AssemblyLoadContexts. - if (loader.AnalyzerLoadOption == AnalyzerLoadOption.LoadFromDisk) + if (state is AnalyzerTestKind.LoadDirect) { Assert.NotEqual(delta2B.Location, delta2.Location); - Assert.Equal(loader.GetRealAnalyzerLoadPath(testFixture.Delta2), delta2.Location); - Assert.Equal(loader.GetRealAnalyzerLoadPath(testFixture.Delta2B), delta2B.Location); + Assert.Equal(loader.GetResolvedAnalyzerPath(testFixture.Delta2), delta2.Location); + Assert.Equal(loader.GetResolvedAnalyzerPath(testFixture.Delta2B), delta2B.Location); } #else @@ -988,50 +969,58 @@ public void AssemblyLoading_MultipleVersions_MultipleVersionsOfSameAnalyzerItsel [CombinatorialData] public void AssemblyLoading_MultipleVersions_ExactAndGreaterMatch(AnalyzerTestKind kind) { - Run(kind, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture) => + Run(kind, state: kind, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture, object state) => { - StringBuilder sb = new StringBuilder(); + using var temp = new TempRoot(); + var tempDir = temp.CreateDirectory(); - loader.AddDependencyLocation(testFixture.Delta2B); - loader.AddDependencyLocation(testFixture.Delta3); - loader.AddDependencyLocation(testFixture.Epsilon); + // This test is about validating how dependencies resolve when there are multiple versions + // on disk with some registered and some not-registered. In this case Epislon has a dependency + // on Delta2. - Assembly epsilon = loader.LoadFromPath(testFixture.Epsilon); + var dir1 = tempDir.CreateDirectory("1"); + var unregisteredDeltaPath = dir1.CopyFile(testFixture.Delta2).Path; + var epsilonPath = dir1.CopyFile(testFixture.Epsilon).Path; + + var dir2 = tempDir.CreateDirectory("2"); + var registeredDeltaPath = dir2.CopyFile(testFixture.Delta2).Path; + + loader.AddDependencyLocation(registeredDeltaPath); + loader.AddDependencyLocation(epsilonPath); + + Assembly epsilon = loader.LoadFromPath(epsilonPath); + StringBuilder sb = new StringBuilder(); var e = epsilon.CreateInstance("Epsilon.E")!; e.GetType().GetMethod("Write")!.Invoke(e, new object[] { sb, "Test E" }); + Assert.Equal( + @"Delta.2: Epsilon: Test E +", + sb.ToString()); - var actual = sb.ToString(); - if (ExecutionConditionUtil.IsCoreClr || loader is ShadowCopyAnalyzerAssemblyLoader) + if (ExecutionConditionUtil.IsCoreClr || state is AnalyzerTestKind.ShadowLoad) { - // This works in CoreClr because we have full control over assembly loading. It - // works in shadow copy because all the DLLs are put into different directories - // so everything is a AppDomain.AssemblyResolve event and we get full control there. + // This works in CoreClr because we have full control over assembly loading. + // This works in ShadowLoad because the unregistered dependency is not copied hence can't be + // implicitly loaded VerifyDependencyAssemblies( loader, - testFixture.Delta2B, - testFixture.Epsilon); - - Assert.Equal( - @"Delta.2B: Epsilon: Test E -", - actual); + copyCount: 2, + registeredDeltaPath, + epsilonPath); } else { - // See limitation 2 - Assert.Throws(() => loader.GetRealAnalyzerLoadPath(testFixture.Delta2)); + // On desktop without shadow load then the desktop loader will grab the unregistered + // dependency because it's in the same directory as the main assembly and LoadFrom + // rules will pick it without a chance to intervene - // Fake the dependency so we can verify the rest of the load - loader.AddDependencyLocation(testFixture.Delta2); + // Add the dependency location just so we can run the verify below + loader.AddDependencyLocation(unregisteredDeltaPath); VerifyDependencyAssemblies( loader, - testFixture.Delta2, - testFixture.Epsilon); - - Assert.Equal( - @"Delta.2: Epsilon: Test E -", - actual); + copyCount: 2, + unregisteredDeltaPath, + epsilonPath); } }); } @@ -1040,14 +1029,14 @@ public void AssemblyLoading_MultipleVersions_ExactAndGreaterMatch(AnalyzerTestKi [CombinatorialData] public void AssemblyLoading_MultipleVersions_WorseMatchInSameDirectory(AnalyzerTestKind kind) { - Run(kind, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture) => + Run(kind, state: kind, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture, object state) => { using var temp = new TempRoot(); StringBuilder sb = new StringBuilder(); var tempDir = temp.CreateDirectory(); - var tempDir1 = tempDir.CreateDirectory("a"); - var tempDir2 = tempDir.CreateDirectory("b"); + var tempDir1 = tempDir.CreateDirectory("1"); + var tempDir2 = tempDir.CreateDirectory("2"); var epsilonFile = tempDir1.CreateFile("Epsilon.dll").CopyContentFrom(testFixture.Epsilon).Path; var delta1File = tempDir1.CreateFile("Delta.dll").CopyContentFrom(testFixture.Delta1).Path; var delta2File = tempDir2.CreateFile("Delta.dll").CopyContentFrom(testFixture.Delta2).Path; @@ -1060,38 +1049,18 @@ public void AssemblyLoading_MultipleVersions_WorseMatchInSameDirectory(AnalyzerT var e = epsilon.CreateInstance("Epsilon.E")!; e.GetType().GetMethod("Write")!.Invoke(e, new object[] { sb, "Test E" }); - if (ExecutionConditionUtil.IsDesktop && loader is ShadowCopyAnalyzerAssemblyLoader) - { - // In desktop + shadow load the dependencies are in different directories with - // no context available when the load for Delta comes in. So we pick the best - // option. - // Epsilon wants Delta2, but since Delta1 is in the same directory, we prefer Delta1 over Delta2. - VerifyDependencyAssemblies( - loader, - copyCount: 3, - delta2File, - epsilonFile); - - var actual = sb.ToString(); - Assert.Equal( - @"Delta.2: Epsilon: Test E -", - actual); - } - else - { - // See limitation 2 - VerifyDependencyAssemblies( - loader, - delta1File, - epsilonFile); + // See limitation 2 + VerifyDependencyAssemblies( + loader, + copyCount: 3, + delta1File, + epsilonFile); - var actual = sb.ToString(); - Assert.Equal( - @"Delta: Epsilon: Test E + var actual = sb.ToString(); + Assert.Equal( + @"Delta: Epsilon: Test E ", - actual); - } + actual); }); } @@ -1106,7 +1075,7 @@ public void AssemblyLoading_MultipleVersions_MultipleLoaders(AnalyzerTestKind ki loader1.AddDependencyLocation(testFixture.Gamma); loader1.AddDependencyLocation(testFixture.Delta1); - var loader2 = new DefaultAnalyzerAssemblyLoader(); + var loader2 = new AnalyzerAssemblyLoader(); loader2.AddDependencyLocation(testFixture.Epsilon); loader2.AddDependencyLocation(testFixture.Delta2); @@ -1484,7 +1453,7 @@ public void AssemblyLoading_NativeDependency(AnalyzerTestKind kind) [CombinatorialData] public void AssemblyLoading_DeleteAfterLoad1(AnalyzerTestKind kind) { - Run(kind, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture) => + Run(kind, state: kind, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture, object state) => { using var temp = new TempRoot(); var tempDir = temp.CreateDirectory(); @@ -1492,7 +1461,7 @@ public void AssemblyLoading_DeleteAfterLoad1(AnalyzerTestKind kind) loader.AddDependencyLocation(deltaCopy); _ = loader.LoadFromPath(deltaCopy); - if (loader is ShadowCopyAnalyzerAssemblyLoader || !ExecutionConditionUtil.IsWindows) + if (state is AnalyzerTestKind.ShadowLoad || !ExecutionConditionUtil.IsWindows) { File.Delete(deltaCopy); } @@ -1507,7 +1476,7 @@ public void AssemblyLoading_DeleteAfterLoad1(AnalyzerTestKind kind) [CombinatorialData] public void AssemblyLoading_DeleteAfterLoad2(AnalyzerTestKind kind) { - Run(kind, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture) => + Run(kind, state: kind, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture, object state) => { using var temp = new TempRoot(); StringBuilder sb = new StringBuilder(); @@ -1517,7 +1486,7 @@ public void AssemblyLoading_DeleteAfterLoad2(AnalyzerTestKind kind) loader.AddDependencyLocation(deltaCopy); Assembly? delta = loader.LoadFromPath(deltaCopy); - if (loader is ShadowCopyAnalyzerAssemblyLoader || !ExecutionConditionUtil.IsWindows) + if (state is AnalyzerTestKind.ShadowLoad || !ExecutionConditionUtil.IsWindows) { File.Delete(deltaCopy); } @@ -1538,7 +1507,7 @@ public void AssemblyLoading_DeleteAfterLoad2(AnalyzerTestKind kind) [CombinatorialData] public void AssemblyLoading_DeleteAfterLoad3(AnalyzerTestKind kind) { - Run(kind, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture) => + Run(kind, state: kind, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture, object state) => { using var temp = new TempRoot(); var tempDir = temp.CreateDirectory(); @@ -1561,7 +1530,7 @@ public void AssemblyLoading_DeleteAfterLoad3(AnalyzerTestKind kind) var writeMethod = b.GetType().GetMethod("Write")!; writeMethod.Invoke(b, new object[] { sb, "Test G" }); - if (loader is ShadowCopyAnalyzerAssemblyLoader) + if (state is AnalyzerTestKind.ShadowLoad) { File.Delete(delta1File); File.Delete(delta2File); @@ -1608,9 +1577,10 @@ public void AssemblyLoading_RepeatedLoads2(AnalyzerTestKind kind) loader.AddDependencyLocation(path); var expected = loader.LoadFromPath(path); + var shadowLoader = loader.AnalyzerPathResolvers.OfType().FirstOrDefault(); for (var i = 0; i < 5; i++) { - if (loader is ShadowCopyAnalyzerAssemblyLoader) + if (shadowLoader is not null) { File.WriteAllBytes(path, new byte[] { 42 }); } @@ -1619,7 +1589,7 @@ public void AssemblyLoading_RepeatedLoads2(AnalyzerTestKind kind) Assert.Same(expected, actual); } - if (loader is ShadowCopyAnalyzerAssemblyLoader shadowLoader) + if (shadowLoader is not null) { // Ensure that despite the on disk changes only one shadow copy occurred Assert.Equal(1, shadowLoader.CopyCount); @@ -1649,7 +1619,7 @@ public void AssemblyLoading_Resources(AnalyzerTestKind kind) // The copy count is 1 here as only one real assembly was copied, the resource // dlls don't apply for this count. - VerifyDependencyAssemblies(loader, copyCount: 1, analyzerPath, analyzerResourcesPath); + VerifyDependencyAssemblies(loader, copyCount: 2, analyzerPath, analyzerResourcesPath); }); } @@ -1670,9 +1640,7 @@ public void AssemblyLoading_ResourcesInParent(AnalyzerTestKind kind) .GetMethod("Exec", BindingFlags.Static | BindingFlags.Public)!; methodInfo.Invoke(null, ["es-ES"]); - // The copy count is 1 here as only one real assembly was copied, the resource - // dlls don't apply for this count. - VerifyDependencyAssemblies(loader, copyCount: 1, analyzerPath, analyzerResourcesPath); + VerifyDependencyAssemblies(loader, copyCount: 2, analyzerPath, analyzerResourcesPath); }); } @@ -1682,36 +1650,43 @@ public void AssemblyLoading_ResourcesInParent(AnalyzerTestKind kind) [CombinatorialData] public void AssemblyLoadingInNonDefaultContext_AnalyzerReferencesSystemCollectionsImmutable(AnalyzerTestKind kind) { - Run(kind, - static (AssemblyLoadContext compilerContext, AssemblyLoadTestFixture testFixture) => - { - // Load the compiler assembly and a modified version of S.C.I into the compiler load context. We - // expect the analyzer will use the bogus S.C.I in the compiler context instead of the one - // in the host context. - _ = compilerContext.LoadFromAssemblyPath(testFixture.UserSystemCollectionsImmutable); - _ = compilerContext.LoadFromAssemblyPath(typeof(AnalyzerAssemblyLoader).GetTypeInfo().Assembly.Location); - }, - static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture) => - { - StringBuilder sb = new StringBuilder(); + // Load the compiler assembly and a modified version of S.C.I into the compiler load context. We + // expect the analyzer will use the bogus S.C.I in the compiler context instead of the one + // in the host context. + var alc = new AssemblyLoadContext(nameof(AssemblyResolver_FirstOneWins), isCollectible: true); + _ = alc.LoadFromAssemblyPath(TestFixture.UserSystemCollectionsImmutable); + _ = alc.LoadFromAssemblyPath(typeof(AnalyzerAssemblyLoader).GetTypeInfo().Assembly.Location); + var loader = kind switch + { + AnalyzerTestKind.LoadStream => new AnalyzerAssemblyLoader([], [AnalyzerAssemblyLoader.StreamAnalyzerAssemblyResolver], alc), + AnalyzerTestKind.LoadDirect => new AnalyzerAssemblyLoader([], [AnalyzerAssemblyLoader.DiskAnalyzerAssemblyResolver], alc), + AnalyzerTestKind.ShadowLoad => new AnalyzerAssemblyLoader([new ShadowCopyAnalyzerPathResolver(Temp.CreateDirectory().Path)], [AnalyzerAssemblyLoader.DiskAnalyzerAssemblyResolver], alc), + _ => throw ExceptionUtilities.UnexpectedValue(kind) + }; - loader.AddDependencyLocation(testFixture.UserSystemCollectionsImmutable); - loader.AddDependencyLocation(testFixture.AnalyzerReferencesSystemCollectionsImmutable1); + Run(loader, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture) => + { + StringBuilder sb = new StringBuilder(); - Assembly analyzerAssembly = loader.LoadFromPath(testFixture.AnalyzerReferencesSystemCollectionsImmutable1); - var analyzer = analyzerAssembly.CreateInstance("Analyzer")!; - analyzer.GetType().GetMethod("Method")!.Invoke(analyzer, new object[] { sb }); + loader.AddDependencyLocation(testFixture.UserSystemCollectionsImmutable); + loader.AddDependencyLocation(testFixture.AnalyzerReferencesSystemCollectionsImmutable1); - Assert.Equal("42", sb.ToString()); - }); + Assembly analyzerAssembly = loader.LoadFromPath(testFixture.AnalyzerReferencesSystemCollectionsImmutable1); + var analyzer = analyzerAssembly.CreateInstance("Analyzer")!; + analyzer.GetType().GetMethod("Method")!.Invoke(analyzer, new object[] { sb }); + + Assert.Equal("42", sb.ToString()); + }); + + alc.Unload(); } #endif [Theory] [CombinatorialData] - public void ExternalResolver_CanIntercept_ReturningNull(AnalyzerTestKind kind) + public void PathResolver_CanIntercept_ReturningNull(AnalyzerTestKind kind) { - var resolver = new TestAnalyzerAssemblyResolver(n => null); + var resolver = new TestAnalyzerPathResolver(n => null); Run(kind, (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture) => { loader.AddDependencyLocation(testFixture.Delta1); @@ -1719,60 +1694,37 @@ public void ExternalResolver_CanIntercept_ReturningNull(AnalyzerTestKind kind) Assert.NotNull(delta); VerifyDependencyAssemblies(loader, testFixture.Delta1); - }, externalResolvers: [resolver]); - Assert.Collection(resolver.CalledFor, (a => Assert.Equal("Delta", a.Name))); - } - - [Theory] - [CombinatorialData] - public void ExternalResolver_CanIntercept_ReturningAssembly(AnalyzerTestKind kind) - { - var resolver = new TestAnalyzerAssemblyResolver(n => GetType().Assembly); - Run(kind, (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture) => - { - // net core assembly loader checks that the resolved assembly name is the same as the requested one - // so we use the assembly the tests are contained in as its already be loaded - var thisAssembly = typeof(AnalyzerAssemblyLoaderTests).Assembly; - loader.AddDependencyLocation(thisAssembly.Location); - Assembly loaded = loader.LoadFromPath(thisAssembly.Location); - Assert.Equal(thisAssembly, loaded); - - }, externalResolvers: [resolver]); - Assert.Collection(resolver.CalledFor, (a => Assert.Equal(GetType().Assembly.GetName().Name, a.Name))); + }, pathResolvers: [resolver]); + Assert.Equal([TestFixture.Delta1], resolver.CalledFor); } [Theory] [CombinatorialData] - public void ExternalResolver_CanIntercept_ReturningAssembly_Or_Null(AnalyzerTestKind kind) + public void PathResolver_CanIntercept_ReturningAssembly_Or_Null(AnalyzerTestKind kind) { - var thisAssemblyName = GetType().Assembly.GetName(); - var resolver = new TestAnalyzerAssemblyResolver(n => n == thisAssemblyName ? GetType().Assembly : null); + var resolver1 = new TestAnalyzerPathResolver(n => n == TestFixture.Alpha ? n : null); + var resolver2 = new TestAnalyzerPathResolver(n => n); Run(kind, (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture) => { - var thisAssembly = typeof(AnalyzerAssemblyLoaderTests).Assembly; - loader.AddDependencyLocation(testFixture.Alpha); Assembly alpha = loader.LoadFromPath(testFixture.Alpha); Assert.NotNull(alpha); - loader.AddDependencyLocation(thisAssembly.Location); - Assembly loaded = loader.LoadFromPath(thisAssembly.Location); - Assert.Equal(thisAssembly, loaded); - loader.AddDependencyLocation(testFixture.Delta1); Assembly delta = loader.LoadFromPath(testFixture.Delta1); Assert.NotNull(delta); - }, externalResolvers: [resolver]); - Assert.Collection(resolver.CalledFor, (a => Assert.Equal("Alpha", a.Name)), a => Assert.Equal(thisAssemblyName.Name, a.Name), a => Assert.Equal("Delta", a.Name)); + }, pathResolvers: [resolver1, resolver2]); + + Assert.Equal([TestFixture.Alpha, TestFixture.Delta1], resolver1.CalledFor); } [Theory] [CombinatorialData] - public void ExternalResolver_MultipleResolvers_CanIntercept_ReturningNull(AnalyzerTestKind kind) + public void PathResolver_MultipleResolvers_CanIntercept_ReturningNull(AnalyzerTestKind kind) { - var resolver1 = new TestAnalyzerAssemblyResolver(n => null); - var resolver2 = new TestAnalyzerAssemblyResolver(n => null); + var resolver1 = new TestAnalyzerPathResolver(n => null); + var resolver2 = new TestAnalyzerPathResolver(n => null); Run(kind, (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture) => { loader.AddDependencyLocation(testFixture.Delta1); @@ -1780,41 +1732,106 @@ public void ExternalResolver_MultipleResolvers_CanIntercept_ReturningNull(Analyz Assert.NotNull(delta); VerifyDependencyAssemblies(loader, testFixture.Delta1); - }, externalResolvers: [resolver1, resolver2]); - Assert.Collection(resolver1.CalledFor, (a => Assert.Equal("Delta", a.Name))); - Assert.Collection(resolver2.CalledFor, (a => Assert.Equal("Delta", a.Name))); + }, pathResolvers: [resolver1, resolver2]); + Assert.Equal([TestFixture.Delta1], resolver1.CalledFor); + Assert.Equal([TestFixture.Delta1], resolver2.CalledFor); } +#if NET + [Theory] [CombinatorialData] - public void ExternalResolver_MultipleResolvers_ResolutionStops_AfterFirstResolve(AnalyzerTestKind kind) + public void AssemblyResolver_CanIntercept_Identity(AnalyzerTestKind kind) { - var resolver1 = new TestAnalyzerAssemblyResolver(n => GetType().Assembly); - var resolver2 = new TestAnalyzerAssemblyResolver(n => null); - Run(kind, (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture) => + var assembly = typeof(AnalyzerAssemblyLoaderTests).Assembly; + var resolver = new TestAnalyzerAssemblyResolver((_, _, assemblyName, _) => assemblyName.Name == assembly.GetName().Name ? assembly : null); + Run(kind, state: assembly, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture, object state) => { - var thisAssembly = typeof(AnalyzerAssemblyLoaderTests).Assembly; - loader.AddDependencyLocation(thisAssembly.Location); - Assembly loaded = loader.LoadFromPath(thisAssembly.Location); - Assert.Equal(thisAssembly, loaded); + // net core assembly loader checks that the resolved assembly name is the same as the requested one + // so we use the assembly the tests are contained in as its already be loaded + var assembly = (Assembly)state; + loader.AddDependencyLocation(assembly.Location); + Assembly loaded = loader.LoadFromPath(assembly.Location); + Assert.Same(assembly, loaded); + }, assemblyResolvers: [resolver, AnalyzerAssemblyLoader.DiskAnalyzerAssemblyResolver]); + } - }, externalResolvers: [resolver1, resolver2]); - Assert.Collection(resolver1.CalledFor, (a => Assert.Equal(GetType().Assembly.GetName().Name, a.Name))); + [Fact] + public void AssemblyResolver_FirstOneWins() + { + var alc = new AssemblyLoadContext(nameof(AssemblyResolver_FirstOneWins), isCollectible: true); + var name = Path.GetFileNameWithoutExtension(TestFixture.Delta1); + var resolver1 = new TestAnalyzerAssemblyResolver((_, assemblyName, current, _) => + assemblyName.Name == name ? current.LoadFromAssemblyPath(TestFixture.Delta1) : null); + var resolver2 = new TestAnalyzerAssemblyResolver((_, _, assemblyName, _) => null); + var loader = new AnalyzerAssemblyLoader([], [resolver1, resolver2], alc); + + Run(loader, state: name, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture, object state) => + { + // net core assembly loader checks that the resolved assembly name is the same as the requested one + // so we use the assembly the tests are contained in as its already be loaded + loader.AddDependencyLocation(testFixture.Delta1); + Assembly loaded = loader.LoadFromPath(testFixture.Delta1); + Assert.Equal((string)state, loaded.GetName().Name); + }); + + Assert.Equal([name], resolver1.CalledFor.Select(x => x.Name)); Assert.Empty(resolver2.CalledFor); + alc.Unload(); + } + + [Fact] + public void AssemblyResolver_ThrowOnNoMatch() + { + var name = Path.GetFileNameWithoutExtension(TestFixture.Delta1); + var alc = new AssemblyLoadContext(nameof(AssemblyResolver_FirstOneWins), isCollectible: true); + var resolver = new TestAnalyzerAssemblyResolver((_, _, assemblyName, _) => null); + var loader = new AnalyzerAssemblyLoader([], [resolver], alc); + + Run(loader, static (AnalyzerAssemblyLoader loader, AssemblyLoadTestFixture testFixture) => + { + // net core assembly loader checks that the resolved assembly name is the same as the requested one + // so we use the assembly the tests are contained in as its already be loaded + loader.AddDependencyLocation(testFixture.Delta1); + Assert.Throws(() => loader.LoadFromPath(testFixture.Delta1)); + }); + + Assert.Equal([Path.GetFileNameWithoutExtension(TestFixture.Delta1)], resolver.CalledFor.Select(x => x.Name)); } +#endif - [Serializable] - private class TestAnalyzerAssemblyResolver(Func func) : MarshalByRefObject, IAnalyzerAssemblyResolver + private class TestAnalyzerPathResolver(Func getRealFilePathFunc) : MarshalByRefObject, IAnalyzerPathResolver { - private readonly Func _func = func; + private readonly Func _getRealFilePathFunc = getRealFilePathFunc; + + public List CalledFor { get; } = []; + + public bool IsAnalyzerPathHandled(string originalPath) + { + CalledFor.Add(originalPath); + return _getRealFilePathFunc(originalPath) is not null; + } + + public string GetResolvedAnalyzerPath(string originalAnalyzerPath) => _getRealFilePathFunc(originalAnalyzerPath)!; + + public string? GetResolvedSatellitePath(string originalAnalyzerPath, CultureInfo cultureInfo) => null; + } + +#if NET + + private class TestAnalyzerAssemblyResolver(Func resolveFunc) : IAnalyzerAssemblyResolver + { + private readonly Func _resolveFunc = resolveFunc; public List CalledFor { get; } = []; - public Assembly? ResolveAssembly(AssemblyName assemblyName, string rootDirectory) + public Assembly? Resolve(AnalyzerAssemblyLoader loader, AssemblyName assemblyName, AssemblyLoadContext directoryContext, string directory) { CalledFor.Add(assemblyName); - return _func(assemblyName); + return _resolveFunc(loader, assemblyName, directoryContext, directory); } } + +#endif } } diff --git a/src/Compilers/Core/CodeAnalysisTest/Analyzers/AnalyzerFileReferenceAppDomainTests.cs b/src/Compilers/Core/CodeAnalysisTest/Analyzers/AnalyzerFileReferenceAppDomainTests.cs index f79eaa292b2c4..2c5a72490f256 100644 --- a/src/Compilers/Core/CodeAnalysisTest/Analyzers/AnalyzerFileReferenceAppDomainTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/Analyzers/AnalyzerFileReferenceAppDomainTests.cs @@ -26,7 +26,7 @@ public override object InitializeLifetimeService() public Exception LoadAnalyzer(string shadowPath, string analyzerPath) { - var loader = DefaultAnalyzerAssemblyLoader.CreateNonLockingLoader(shadowPath); + var loader = AnalyzerAssemblyLoader.CreateNonLockingLoader(shadowPath, []); Exception analyzerLoadException = null; var analyzerRef = new AnalyzerFileReference(analyzerPath, loader); analyzerRef.AnalyzerLoadFailed += (s, e) => analyzerLoadException = e.Exception; diff --git a/src/Compilers/Core/CodeAnalysisTest/Analyzers/AnalyzerFileReferenceTests.cs b/src/Compilers/Core/CodeAnalysisTest/Analyzers/AnalyzerFileReferenceTests.cs index 700e0a6b64f8d..d03535c875e2e 100644 --- a/src/Compilers/Core/CodeAnalysisTest/Analyzers/AnalyzerFileReferenceTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/Analyzers/AnalyzerFileReferenceTests.cs @@ -29,7 +29,7 @@ private AssemblyLoadTestFixtureCollection() { } [Collection(AssemblyLoadTestFixtureCollection.Name)] public class AnalyzerFileReferenceTests : TestBase { - private static readonly AnalyzerAssemblyLoader s_analyzerLoader = new DefaultAnalyzerAssemblyLoader(); + private static readonly AnalyzerAssemblyLoader s_analyzerLoader = new AnalyzerAssemblyLoader(); private readonly AssemblyLoadTestFixture _testFixture; public AnalyzerFileReferenceTests(AssemblyLoadTestFixture testFixture) { @@ -319,13 +319,13 @@ public void AssemblyLoading_ReferencesLaterFakeCompiler_EndToEnd_CSharp() args: new[] { "/nologo", $@"/analyzer:""{_testFixture.AnalyzerWithLaterFakeCompilerDependency}""", "/nostdlib", $@"/r:""{corlib}""", "/out:something.dll", source.Path }, new BuildPaths(clientDir: directory.Path, workingDir: directory.Path, sdkDir: null, tempDir: null), additionalReferenceDirectories: null, - new DefaultAnalyzerAssemblyLoader()); + new AnalyzerAssemblyLoader()); var writer = new StringWriter(); var result = compiler.Run(writer); Assert.Equal(0, result); AssertEx.Equal($""" - warning CS9057: The analyzer assembly '{_testFixture.AnalyzerWithLaterFakeCompilerDependency}' references version '100.0.0.0' of the compiler, which is newer than the currently running version '{typeof(DefaultAnalyzerAssemblyLoader).Assembly.GetName().Version}'. + warning CS9057: Analyzer assembly '{_testFixture.AnalyzerWithLaterFakeCompilerDependency}' cannot be used because it references version '100.0.0.0' of the compiler, which is newer than the currently running version '42.42.42.42'. in.cs(1,5): warning CS0219: The variable 'x' is assigned but its value is never used """, writer.ToString()); @@ -348,7 +348,7 @@ public void DuplicateAnalyzerReference() args: new[] { "/nologo", $@"/analyzer:""{_testFixture.AnalyzerWithFakeCompilerDependency}""", $@"/analyzer:""{_testFixture.AnalyzerWithFakeCompilerDependency}""", "/nostdlib", $@"/r:""{corlib}""", "/out:something.dll", source.Path }, new BuildPaths(clientDir: directory.Path, workingDir: directory.Path, sdkDir: null, tempDir: null), additionalReferenceDirectories: null, - new DefaultAnalyzerAssemblyLoader()); + new AnalyzerAssemblyLoader()); var writer = new StringWriter(); var result = compiler.Run(writer); diff --git a/src/Compilers/Core/CodeAnalysisTest/CompilerAnalyzerAssemblyResolverTests.cs b/src/Compilers/Core/CodeAnalysisTest/CompilerAnalyzerAssemblyResolverTests.cs deleted file mode 100644 index 262e903666513..0000000000000 --- a/src/Compilers/Core/CodeAnalysisTest/CompilerAnalyzerAssemblyResolverTests.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#if NET -using System.Runtime.Loader; -using System.Reflection; -using Xunit; - -namespace Microsoft.CodeAnalysis.UnitTests; - -public sealed class CompilerAnalyzerAssemblyResolverTests -{ - [Fact] - public void ExceptionReturnsNull() - { - var context = new AssemblyLoadContext(nameof(ExceptionReturnsNull), isCollectible: true); - var resolver = new AnalyzerAssemblyLoader.CompilerAnalyzerAssemblyResolver(context); - var name = new AssemblyName("NotARealAssembly"); - Assert.Null(resolver.ResolveAssembly(name, directoryName: "")); - context.Unload(); - } -} -#endif diff --git a/src/Compilers/Core/CodeAnalysisTest/CompilerResolverTests.cs b/src/Compilers/Core/CodeAnalysisTest/CompilerResolverTests.cs new file mode 100644 index 0000000000000..546546ba3f649 --- /dev/null +++ b/src/Compilers/Core/CodeAnalysisTest/CompilerResolverTests.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. + +#if NET +using System; +using System.Linq; +using System.Reflection; +using System.Runtime.Loader; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.UnitTests; + +public sealed class CompilerResolverTests : IDisposable +{ + public TempRoot TempRoot { get; } + public int DefaultLoadContextCount { get; } + public AssemblyLoadContext CompilerContext { get; } + public AssemblyLoadContext ScratchContext { get; } + public Assembly AssemblyInCompilerContext { get; } + internal AnalyzerAssemblyLoader Loader { get; } + + public CompilerResolverTests() + { + TempRoot = new TempRoot(); + DefaultLoadContextCount = AssemblyLoadContext.Default.Assemblies.Count(); + CompilerContext = new AssemblyLoadContext(nameof(CompilerResolverTests), isCollectible: true); + AssemblyInCompilerContext = CompilerContext.LoadFromAssemblyPath(typeof(AnalyzerAssemblyLoader).Assembly.Location); + ScratchContext = new AssemblyLoadContext("Scratch", isCollectible: true); + Loader = new AnalyzerAssemblyLoader([], [AnalyzerAssemblyLoader.DiskAnalyzerAssemblyResolver], CompilerContext); + } + + public void Dispose() + { + // This test should not pollute the default load context and hence interfere with other tests. + Assert.Equal(DefaultLoadContextCount, AssemblyLoadContext.Default.Assemblies.Count()); + CompilerContext.Unload(); + ScratchContext.Unload(); + TempRoot.Dispose(); + } + + [Fact] + public void ResolveReturnsNullForNonHostAssembly() + { + var name = new AssemblyName("NotARealAssembly"); + var assembly = Loader.CompilerAnalyzerAssemblyResolver.Resolve(Loader, name, ScratchContext, TempRoot.CreateDirectory().Path); + Assert.Null(assembly); + } + + [Fact] + public void ResolveReturnsForHostAssembly() + { + var assembly = Loader.CompilerAnalyzerAssemblyResolver.Resolve(Loader, AssemblyInCompilerContext.GetName(), ScratchContext, TempRoot.CreateDirectory().Path); + Assert.Same(AssemblyInCompilerContext, assembly); + } +} +#endif diff --git a/src/Compilers/Core/CodeAnalysisTest/Emit/EmitOptionsTests.cs b/src/Compilers/Core/CodeAnalysisTest/Emit/EmitOptionsTests.cs index 17db9893fe02c..16fafd03acb16 100644 --- a/src/Compilers/Core/CodeAnalysisTest/Emit/EmitOptionsTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/Emit/EmitOptionsTests.cs @@ -92,7 +92,8 @@ public void TestFieldsForEqualsAndGetHashCode() nameof(EmitOptions.IncludePrivateMembers), nameof(EmitOptions.InstrumentationKinds), nameof(EmitOptions.DefaultSourceFileEncoding), - nameof(EmitOptions.FallbackSourceFileEncoding)); + nameof(EmitOptions.FallbackSourceFileEncoding), + nameof(EmitOptions.TestOnly_DataToHexViaXxHash128)); } [Fact] diff --git a/src/Compilers/Core/CodeAnalysisTest/FileUtilitiesTests.cs b/src/Compilers/Core/CodeAnalysisTest/FileUtilitiesTests.cs index 6883579179420..24b34de47378e 100644 --- a/src/Compilers/Core/CodeAnalysisTest/FileUtilitiesTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/FileUtilitiesTests.cs @@ -305,6 +305,7 @@ public void Extension() [InlineData("/a/../b/../c/file.cs", "/c/file.cs")] [InlineData("/../../c/file.cs", "/c/file.cs")] [InlineData("/a/../b/./././../c/file.cs", "/c/file.cs")] + [InlineData("/tmp/../.config/../.roslyn/**/*.cs", "/.roslyn/**/*.cs")] // not absolute paths [InlineData("a/b/c", "a/b/c")] [InlineData("./a/b/c", "./a/b/c")] diff --git a/src/Compilers/Core/CodeAnalysisTest/InvokeUtil.cs b/src/Compilers/Core/CodeAnalysisTest/InvokeUtil.cs index 265511935dd67..a7879283bce40 100644 --- a/src/Compilers/Core/CodeAnalysisTest/InvokeUtil.cs +++ b/src/Compilers/Core/CodeAnalysisTest/InvokeUtil.cs @@ -35,7 +35,54 @@ namespace Microsoft.CodeAnalysis.UnitTests public sealed class InvokeUtil { - internal void Exec(ITestOutputHelper testOutputHelper, AssemblyLoadContext compilerContext, AssemblyLoadTestFixture fixture, AnalyzerTestKind kind, string typeName, string methodName, IAnalyzerAssemblyResolver[] externalResolvers, object? state = null) + internal void Exec( + ITestOutputHelper testOutputHelper, + ImmutableArray pathResolvers, + ImmutableArray assemblyResolvers, + AssemblyLoadTestFixture fixture, + AnalyzerTestKind kind, + string typeName, + string methodName, + object? state = null) + { + using var tempRoot = new TempRoot(); + switch (kind) + { + case AnalyzerTestKind.LoadDirect: + assemblyResolvers = [.. assemblyResolvers, AnalyzerAssemblyLoader.DiskAnalyzerAssemblyResolver]; + break; + case AnalyzerTestKind.LoadStream: + assemblyResolvers = [.. assemblyResolvers, AnalyzerAssemblyLoader.StreamAnalyzerAssemblyResolver]; + break; + case AnalyzerTestKind.ShadowLoad: + pathResolvers = [.. pathResolvers, new ShadowCopyAnalyzerPathResolver(tempRoot.CreateDirectory().Path)]; + assemblyResolvers = [.. assemblyResolvers, AnalyzerAssemblyLoader.DiskAnalyzerAssemblyResolver]; + break; + default: + throw ExceptionUtilities.Unreachable(); + } + + var loader = new AnalyzerAssemblyLoader(pathResolvers, assemblyResolvers, compilerLoadContext: null); + var compilerContextAssemblyCount = loader.CompilerLoadContext.Assemblies.Count(); + try + { + Exec(testOutputHelper, fixture, loader, typeName, methodName, state); + } + finally + { + // When using the actual compiler load context (the one shared by all of our unit tests) the test + // did not load any additional assemblies that could interfere with later tests. + Assert.Equal(compilerContextAssemblyCount, loader.CompilerLoadContext.Assemblies.Count()); + } + } + + internal void Exec( + ITestOutputHelper testOutputHelper, + AssemblyLoadTestFixture fixture, + AnalyzerAssemblyLoader loader, + string typeName, + string methodName, + object? state = null) { // Ensure that the test did not load any of the test fixture assemblies into // the default load context. That should never happen. Assemblies should either @@ -43,16 +90,7 @@ internal void Exec(ITestOutputHelper testOutputHelper, AssemblyLoadContext compi // // Not only is this bad behavior it also pollutes future test results. var defaultContextCount = AssemblyLoadContext.Default.Assemblies.Count(); - var compilerContextCount = compilerContext.Assemblies.Count(); - using var tempRoot = new TempRoot(); - using AnalyzerAssemblyLoader loader = kind switch - { - AnalyzerTestKind.LoadDirect => new DefaultAnalyzerAssemblyLoader(compilerContext, AnalyzerLoadOption.LoadFromDisk, externalResolvers.ToImmutableArray()), - AnalyzerTestKind.LoadStream => new DefaultAnalyzerAssemblyLoader(compilerContext, AnalyzerLoadOption.LoadFromStream, externalResolvers.ToImmutableArray()), - AnalyzerTestKind.ShadowLoad => new ShadowCopyAnalyzerAssemblyLoader(compilerContext, tempRoot.CreateDirectory().Path, externalResolvers.ToImmutableArray()), - _ => throw ExceptionUtilities.Unreachable() - }; try { @@ -71,19 +109,18 @@ internal void Exec(ITestOutputHelper testOutputHelper, AssemblyLoadContext compi } } - if (loader is ShadowCopyAnalyzerAssemblyLoader shadowLoader) + if (loader.AnalyzerPathResolvers.OfType().FirstOrDefault() is { } shadowResolver) { - testOutputHelper.WriteLine($"Shadow loader: {shadowLoader.BaseDirectory}"); + testOutputHelper.WriteLine($"{nameof(ShadowCopyAnalyzerPathResolver)}: {shadowResolver.BaseDirectory}"); } testOutputHelper.WriteLine($"Loader path maps"); foreach (var pair in loader.GetPathMapSnapshot()) { - testOutputHelper.WriteLine($"\t{pair.OriginalAssemblyPath} -> {pair.RealAssemblyPath}"); + testOutputHelper.WriteLine($"\t{pair.OriginalAssemblyPath} -> {pair.ResolvedAssemblyPath}"); } Assert.Equal(defaultContextCount, AssemblyLoadContext.Default.Assemblies.Count()); - Assert.Equal(compilerContextCount, compilerContext.Assemblies.Count()); } } } @@ -92,16 +129,25 @@ internal void Exec(ITestOutputHelper testOutputHelper, AssemblyLoadContext compi public sealed class InvokeUtil : MarshalByRefObject { - internal void Exec(ITestOutputHelper testOutputHelper, AssemblyLoadTestFixture fixture, AnalyzerTestKind kind, string typeName, string methodName, IAnalyzerAssemblyResolver[] externalResolvers, object? state) + internal void Exec( + ITestOutputHelper testOutputHelper, + AssemblyLoadTestFixture fixture, + AnalyzerTestKind kind, + string typeName, + string methodName, + IAnalyzerPathResolver[] pathResolvers, + object? state) { using var tempRoot = new TempRoot(); - AnalyzerAssemblyLoader loader = kind switch + pathResolvers = kind switch { - AnalyzerTestKind.LoadDirect => new DefaultAnalyzerAssemblyLoader(externalResolvers.ToImmutableArray()), - AnalyzerTestKind.ShadowLoad => new ShadowCopyAnalyzerAssemblyLoader(tempRoot.CreateDirectory().Path, externalResolvers.ToImmutableArray()), - _ => throw ExceptionUtilities.Unreachable() + AnalyzerTestKind.LoadDirect => pathResolvers, + AnalyzerTestKind.ShadowLoad => [.. pathResolvers, new ShadowCopyAnalyzerPathResolver(tempRoot.CreateDirectory().Path)], + _ => throw ExceptionUtilities.Unreachable(), }; + var loader = new AnalyzerAssemblyLoader(pathResolvers.ToImmutableArray()); + try { AnalyzerAssemblyLoaderTests.InvokeTestCode(loader, fixture, typeName, methodName, state); @@ -121,15 +167,15 @@ internal void Exec(ITestOutputHelper testOutputHelper, AssemblyLoadTestFixture f testOutputHelper.WriteLine($"\t{assembly.FullName} -> {assembly.Location}"); } - if (loader is ShadowCopyAnalyzerAssemblyLoader shadowLoader) + if (loader.AnalyzerPathResolvers.OfType().FirstOrDefault() is { } shadowResolver) { - testOutputHelper.WriteLine($"Shadow loader: {shadowLoader.BaseDirectory}"); + testOutputHelper.WriteLine($"{nameof(ShadowCopyAnalyzerPathResolver)}: {shadowResolver.BaseDirectory}"); } testOutputHelper.WriteLine($"Loader path maps"); foreach (var pair in loader.GetPathMapSnapshot()) { - testOutputHelper.WriteLine($"\t{pair.OriginalAssemblyPath} -> {pair.RealAssemblyPath}"); + testOutputHelper.WriteLine($"\t{pair.OriginalAssemblyPath} -> {pair.ResolvedAssemblyPath}"); } } } diff --git a/src/Compilers/Core/CodeAnalysisTest/ShadowCopyAnalyzerPathResolverTests.cs b/src/Compilers/Core/CodeAnalysisTest/ShadowCopyAnalyzerPathResolverTests.cs new file mode 100644 index 0000000000000..b1df8e2b8680f --- /dev/null +++ b/src/Compilers/Core/CodeAnalysisTest/ShadowCopyAnalyzerPathResolverTests.cs @@ -0,0 +1,108 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.UnitTests.Collections; +using Xunit; + +namespace Microsoft.CodeAnalysis.UnitTests; + +public sealed class ShadowCopyAnalyzerPathResolverTests : IDisposable +{ + public TempRoot TempRoot { get; } + internal ShadowCopyAnalyzerPathResolver PathResolver { get; } + + public ShadowCopyAnalyzerPathResolverTests() + { + TempRoot = new TempRoot(); + PathResolver = new ShadowCopyAnalyzerPathResolver(TempRoot.CreateDirectory().Path); + } + + public void Dispose() + { + TempRoot.Dispose(); + } + + [Fact] + public void IsAnalyzerPathHandled() + { + var analyzerPath = TempRoot.CreateDirectory().CreateFile("analyzer.dll").Path; + Assert.True(PathResolver.IsAnalyzerPathHandled(analyzerPath)); + } + + /// + /// Don't create the shadow directory until a copy actually happens + /// + [Fact] + public void ShadowDirectoryIsDelayCreated() + { + Assert.False(Directory.Exists(PathResolver.ShadowDirectory)); + } + + /// + /// A shadow copy of a file that doesn't exist should produce a file that doesn't exist, not throw + /// + [Fact] + public void GetRealPath_FileDoesNotExist() + { + var analyzerPath = Path.Combine(TempRoot.CreateDirectory().Path, "analyzer.dll"); + var shadowPath = PathResolver.GetResolvedAnalyzerPath(analyzerPath); + Assert.False(File.Exists(shadowPath)); + } + + [Fact] + public void GetRealPath_Copies() + { + var analyzerPath = Path.Combine(TempRoot.CreateDirectory().Path, "analyzer.dll"); + File.WriteAllText(analyzerPath, "test"); + var shadowPath = PathResolver.GetResolvedAnalyzerPath(analyzerPath); + Assert.True(File.Exists(shadowPath)); + Assert.Equal("test", File.ReadAllText(shadowPath)); + } + + /// + /// When shadow copying two files in the same directory they should end up in the same shadow + /// directory + /// + [Fact] + public void GetRealPath_FilesInSameDirectory() + { + var dir = TempRoot.CreateDirectory().Path; + var analyzer1Path = Path.Combine(dir, "analyzer1.dll"); + File.WriteAllText(analyzer1Path, "test"); + var analyzer2Path = Path.Combine(dir, "analyzer2.dll"); + File.WriteAllText(analyzer2Path, "test"); + var shadow1Path = PathResolver.GetResolvedAnalyzerPath(analyzer1Path); + var shadow2Path = PathResolver.GetResolvedAnalyzerPath(analyzer2Path); + Assert.Equal(Path.GetDirectoryName(shadow1Path), Path.GetDirectoryName(shadow2Path)); + } + + [Fact] + public void GetRealPath_GroupOnDirectory() + { + var dir = TempRoot.CreateDirectory().Path; + var group1AnalyzerPath = createAnalyzer("group1", "analyzer.dll"); + var group2AnalyzerPath = createAnalyzer("group2", "analyzer.dll"); + var group1ShadowPath = PathResolver.GetResolvedAnalyzerPath(group1AnalyzerPath); + var group2ShadowPath = PathResolver.GetResolvedAnalyzerPath(group2AnalyzerPath); + Assert.NotEqual(group1ShadowPath, group2ShadowPath); + Assert.Equal("group1-analyzer.dll", File.ReadAllText(group1ShadowPath)); + Assert.Equal("group2-analyzer.dll", File.ReadAllText(group2ShadowPath)); + + string createAnalyzer(string groupName, string name) + { + var groupDir = Path.Combine(dir, groupName, "analyzers"); + _ = Directory.CreateDirectory(groupDir); + var filePath = Path.Combine(groupDir, name); + File.WriteAllText(filePath, $"{Path.GetFileName(groupName)}-{name}"); + return filePath; + } + } +} diff --git a/src/Compilers/Core/MSBuildTask/Microsoft.Build.Tasks.CodeAnalysis.csproj b/src/Compilers/Core/MSBuildTask/Microsoft.Build.Tasks.CodeAnalysis.csproj index d40e9c02f461d..1cc48b02c01b1 100644 --- a/src/Compilers/Core/MSBuildTask/Microsoft.Build.Tasks.CodeAnalysis.csproj +++ b/src/Compilers/Core/MSBuildTask/Microsoft.Build.Tasks.CodeAnalysis.csproj @@ -17,7 +17,7 @@ https://github.com/dotnet/arcade/issues/9305 --> false - + $(NoWarn);CA1819 @@ -53,14 +53,10 @@ - - - - @@ -80,9 +76,7 @@ - + PreserveNewest @@ -94,8 +88,7 @@ - + <_CompilerApiVersion>$([System.Version]::Parse($(VersionPrefix)).Major).$([System.Version]::Parse($(VersionPrefix)).Minor) @@ -108,9 +101,8 @@ - + + + diff --git a/src/Compilers/Core/Portable/CodeGen/ArrayMembers.cs b/src/Compilers/Core/Portable/CodeGen/ArrayMembers.cs index 5d4e4c662f8ff..39662c00c568e 100644 --- a/src/Compilers/Core/Portable/CodeGen/ArrayMembers.cs +++ b/src/Compilers/Core/Portable/CodeGen/ArrayMembers.cs @@ -365,13 +365,13 @@ public override string ToString() public sealed override bool Equals(object? obj) { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } public sealed override int GetHashCode() { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } } } diff --git a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs index 167f24f09be32..87b9df89e731c 100644 --- a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs +++ b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs @@ -100,6 +100,9 @@ internal sealed class PrivateImplementationDetails : DefaultTypeDef, Cci.INamesp // data section string literal holders (key is the full string literal) private readonly ConcurrentDictionary _dataSectionStringLiteralTypes = new ConcurrentDictionary(); + // map of data section string literal generated type names ( + hash) to the full text + private readonly ConcurrentDictionary _dataSectionStringLiteralNames = new ConcurrentDictionary(); + private ImmutableArray _orderedNestedTypes; internal PrivateImplementationDetails( @@ -333,16 +336,28 @@ internal MappedField GetOrAddDataField(ImmutableArray data, ushort alignme } var @this = moduleBuilder.GetPrivateImplClass(syntaxNode, diagnostics); - return @this._dataSectionStringLiteralTypes.GetOrAdd(text, static (key, arg) => + return @this._dataSectionStringLiteralTypes.GetOrAdd(text, static (text, arg) => { - var (@this, data, diagnostics) = arg; + var (@this, data, syntaxNode, diagnostics) = arg; - string name = "" + DataToHexViaXxHash128(data); + string name = "" + @this.DataToHexViaXxHash128(data); MappedField dataField = @this.GetOrAddDataField(data, alignment: 1); Cci.IMethodDefinition bytesToStringHelper = @this.GetOrSynthesizeBytesToStringHelper(diagnostics); + var previousText = @this._dataSectionStringLiteralNames.GetOrAdd(name, text); + if (previousText != text) + { + // If there is a hash collision, we cannot fallback to normal string literal emit strategy + // because the selection of which literal would get which emit strategy would not be deterministic. + var messageProvider = @this.ModuleBuilder.CommonCompilation.MessageProvider; + diagnostics.Add(messageProvider.CreateDiagnostic( + messageProvider.ERR_DataSectionStringLiteralHashCollision, + syntaxNode.GetLocation(), + previousText[..Math.Min(previousText.Length, 500)])); + } + return new DataSectionStringType( name: name, containingType: @this, @@ -350,7 +365,7 @@ internal MappedField GetOrAddDataField(ImmutableArray data, ushort alignme bytesToStringHelper: bytesToStringHelper, diagnostics: diagnostics); }, - (@this, ImmutableCollectionsMarshal.AsImmutableArray(data), diagnostics)).Field; + (@this, ImmutableCollectionsMarshal.AsImmutableArray(data), syntaxNode, diagnostics)).Field; } /// @@ -548,8 +563,13 @@ private static string DataToHex(ImmutableArray data) return HashToHex(hash.AsSpan()); } - private static string DataToHexViaXxHash128(ImmutableArray data) + private string DataToHexViaXxHash128(ImmutableArray data) { + if (ModuleBuilder.EmitOptions.TestOnly_DataToHexViaXxHash128 is { } handler) + { + return handler(data); + } + Span hash = stackalloc byte[sizeof(ulong) * 2]; int bytesWritten = XxHash128.Hash(data.AsSpan(), hash); Debug.Assert(bytesWritten == hash.Length); @@ -897,13 +917,13 @@ public MetadataConstant Constant public sealed override bool Equals(object? obj) { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } public sealed override int GetHashCode() { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } } @@ -1111,13 +1131,13 @@ public TypeDefinitionHandle TypeDef public sealed override bool Equals(object? obj) { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } public sealed override int GetHashCode() { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } } diff --git a/src/Compilers/Core/Portable/CodeGen/SequencePointList.cs b/src/Compilers/Core/Portable/CodeGen/SequencePointList.cs index 7ca22820a4292..fa05e381022cb 100644 --- a/src/Compilers/Core/Portable/CodeGen/SequencePointList.cs +++ b/src/Compilers/Core/Portable/CodeGen/SequencePointList.cs @@ -25,7 +25,7 @@ internal class SequencePointList private SequencePointList _next; // Linked list of all points. // No sequence points. - private static readonly SequencePointList s_empty = new SequencePointList(); + internal static readonly SequencePointList Empty = new SequencePointList(); // Construct a list with no sequence points. private SequencePointList() @@ -48,7 +48,7 @@ public static SequencePointList Create(ArrayBuilder seqPointBu { if (seqPointBuilder.Count == 0) { - return SequencePointList.s_empty; + return SequencePointList.Empty; } SequencePointList first = null, current = null; diff --git a/src/Compilers/Core/Portable/Collections/DictionaryExtensions.cs b/src/Compilers/Core/Portable/Collections/DictionaryExtensions.cs index cb74f75739217..f3f6f224cfa57 100644 --- a/src/Compilers/Core/Portable/Collections/DictionaryExtensions.cs +++ b/src/Compilers/Core/Portable/Collections/DictionaryExtensions.cs @@ -76,7 +76,7 @@ public static bool TryAdd( } #endif - public static void AddPooled(this IDictionary> dictionary, K key, V value) + public static void AddPooled(this Dictionary> dictionary, K key, V value) where K : notnull { if (!dictionary.TryGetValue(key, out var values)) @@ -88,15 +88,22 @@ public static void AddPooled(this IDictionary> dictiona values.Add(value); } - public static ImmutableSegmentedDictionary> ToImmutableSegmentedDictionaryAndFree(this IReadOnlyDictionary> builder) + /// + /// Converts the passed in dictionary to an , where all + /// the values in the passed builder will be converted to an using . The will be freed at the end of + /// this method as well, and should not be used afterwards. + /// + public static ImmutableSegmentedDictionary> ToImmutableSegmentedDictionaryAndFree(this PooledDictionary> dictionary) where K : notnull { var result = ImmutableSegmentedDictionary.CreateBuilder>(); - foreach (var (key, values) in builder) + foreach (var (key, values) in dictionary) { result.Add(key, values.ToImmutableAndFree()); } + dictionary.Free(); return result.ToImmutable(); } } diff --git a/src/Compilers/Core/Portable/Collections/Rope.cs b/src/Compilers/Core/Portable/Collections/Rope.cs index ac06ff20367fa..d70c278ee9864 100644 --- a/src/Compilers/Core/Portable/Collections/Rope.cs +++ b/src/Compilers/Core/Portable/Collections/Rope.cs @@ -19,6 +19,7 @@ internal abstract class Rope public abstract override string ToString(); public abstract string ToString(int maxLength); public abstract int Length { get; } + public bool IsEmpty => Length == 0; protected abstract IEnumerable GetChars(); private Rope() { } diff --git a/src/Compilers/Core/Portable/Compilation/DeterministicKeyBuilder.cs b/src/Compilers/Core/Portable/Compilation/DeterministicKeyBuilder.cs index be92b6a27b567..210421fe3375f 100644 --- a/src/Compilers/Core/Portable/Compilation/DeterministicKeyBuilder.cs +++ b/src/Compilers/Core/Portable/Compilation/DeterministicKeyBuilder.cs @@ -186,7 +186,7 @@ void writeGenerators() foreach (var generator in generators) { cancellationToken.ThrowIfCancellationRequested(); - WriteType(writer, generator.GetType()); + WriteType(writer, generator.GetGeneratorType()); } writer.WriteArrayEnd(); } diff --git a/src/Compilers/Core/Portable/Compilation/SemanticModel.cs b/src/Compilers/Core/Portable/Compilation/SemanticModel.cs index 85f861b6a26bc..c5b7638e2fe69 100644 --- a/src/Compilers/Core/Portable/Compilation/SemanticModel.cs +++ b/src/Compilers/Core/Portable/Compilation/SemanticModel.cs @@ -449,7 +449,7 @@ internal abstract SemanticModel ContainingPublicModelOrSelf /// scope around position is used. /// The name of the symbol to find. If null is specified then symbols /// with any names are returned. - /// Consider (reduced) extension methods. + /// Consider extension members. Classic extension methods will be returned in reduced form. /// A list of symbols that were found. If no symbols were found, an empty list is returned. /// /// The "position" is used to determine what variables are visible and accessible. Even if "container" is diff --git a/src/Compilers/Core/Portable/Diagnostic/CommonMessageProvider.cs b/src/Compilers/Core/Portable/Diagnostic/CommonMessageProvider.cs index 03af6e1a38996..b662165fee496 100644 --- a/src/Compilers/Core/Portable/Diagnostic/CommonMessageProvider.cs +++ b/src/Compilers/Core/Portable/Diagnostic/CommonMessageProvider.cs @@ -244,6 +244,7 @@ public string GetIdForErrorCode(int errorCode) public abstract int ERR_EncUpdateFailedMissingSymbol { get; } public abstract int ERR_InvalidDebugInfo { get; } public abstract int ERR_FunctionPointerTypesInAttributeNotSupported { get; } + public abstract int ERR_DataSectionStringLiteralHashCollision { get; } // Generators: public abstract int WRN_GeneratorFailedDuringInitialization { get; } diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.Core.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.Core.cs index b1e5e659f600c..a4b6fb9a55513 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.Core.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.Core.cs @@ -18,43 +18,56 @@ namespace Microsoft.CodeAnalysis { - internal enum AnalyzerLoadOption + internal sealed partial class AnalyzerAssemblyLoader { - /// - /// Once the assembly path is chosen, load it directly from disk at that location - /// - LoadFromDisk, + internal static IAnalyzerAssemblyResolver DiskAnalyzerAssemblyResolver => DiskResolver.Instance; + internal static IAnalyzerAssemblyResolver StreamAnalyzerAssemblyResolver => StreamResolver.Instance; /// - /// Once the assembly path is chosen, read the contents of disk and load from memory + /// Map of resolved directory paths to load contexts that manage their assemblies. /// - /// - /// While Windows supports this option it comes with a significant performance penalty due - /// to anti virus scans. It can have a load time of 300-500ms while loading from disk - /// is generally 1-2ms. Use this with caution on Windows. - /// - LoadFromStream - } + private readonly Dictionary _loadContextByDirectory = new Dictionary(GeneratedPathComparer); - internal partial class AnalyzerAssemblyLoader - { - private readonly AssemblyLoadContext _compilerLoadContext; - private readonly Dictionary _loadContextByDirectory = new Dictionary(StringComparer.Ordinal); - private readonly AnalyzerLoadOption _loadOption; + public IAnalyzerAssemblyResolver CompilerAnalyzerAssemblyResolver { get; } + public AssemblyLoadContext CompilerLoadContext { get; } + public ImmutableArray AnalyzerAssemblyResolvers { get; } - internal AssemblyLoadContext CompilerLoadContext => _compilerLoadContext; - internal AnalyzerLoadOption AnalyzerLoadOption => _loadOption; + internal AnalyzerAssemblyLoader() + : this(pathResolvers: []) + { + } - internal AnalyzerAssemblyLoader(ImmutableArray externalResolvers) - : this(null, AnalyzerLoadOption.LoadFromDisk, externalResolvers) + internal AnalyzerAssemblyLoader(ImmutableArray pathResolvers) + : this(pathResolvers, assemblyResolvers: [DiskAnalyzerAssemblyResolver], compilerLoadContext: null) { } - internal AnalyzerAssemblyLoader(AssemblyLoadContext? compilerLoadContext, AnalyzerLoadOption loadOption, ImmutableArray externalResolvers) + /// + /// Create a new with the given resolvers. + /// + /// This is the where the compiler resides. This parameter + /// is primarily used for testing purposes but is also useful in hosted scenarios where the compiler may be loaded outside + /// the default context. When null this will be the the compiler currently resides + /// in + /// + internal AnalyzerAssemblyLoader( + ImmutableArray pathResolvers, + ImmutableArray assemblyResolvers, + AssemblyLoadContext? compilerLoadContext) { - _loadOption = loadOption; - _compilerLoadContext = compilerLoadContext ?? AssemblyLoadContext.GetLoadContext(typeof(AnalyzerAssemblyLoader).GetTypeInfo().Assembly)!; - _externalResolvers = [.. externalResolvers, new CompilerAnalyzerAssemblyResolver(_compilerLoadContext)]; + if (assemblyResolvers.Length == 0) + { + throw new ArgumentException("Cannot be empty", nameof(assemblyResolvers)); + } + + CompilerLoadContext = compilerLoadContext ?? AssemblyLoadContext.GetLoadContext(typeof(SyntaxTree).GetTypeInfo().Assembly)!; + CompilerAnalyzerAssemblyResolver = new CompilerResolver(CompilerLoadContext); + AnalyzerPathResolvers = pathResolvers; + + // The CompilerAnalyzerAssemblyResolver must be first here as the host is _always_ given a chance + // to resolve the assembly before any other resolver. This is crucial to allow for items like + // unification of System.Collections.Immutable or other core assemblies for a host. + AnalyzerAssemblyResolvers = [CompilerAnalyzerAssemblyResolver, .. assemblyResolvers]; } public bool IsHostAssembly(Assembly assembly) @@ -62,14 +75,14 @@ public bool IsHostAssembly(Assembly assembly) CheckIfDisposed(); var alc = AssemblyLoadContext.GetLoadContext(assembly); - return alc == _compilerLoadContext || alc == AssemblyLoadContext.Default; + return alc == CompilerLoadContext || alc == AssemblyLoadContext.Default; } - private partial Assembly Load(AssemblyName assemblyName, string assemblyOriginalPath) + private partial Assembly Load(AssemblyName assemblyName, string resolvedPath) { DirectoryLoadContext? loadContext; - var fullDirectoryPath = Path.GetDirectoryName(assemblyOriginalPath) ?? throw new ArgumentException(message: null, paramName: nameof(assemblyOriginalPath)); + var fullDirectoryPath = Path.GetDirectoryName(resolvedPath) ?? throw new ArgumentException(message: null, paramName: nameof(resolvedPath)); lock (_guard) { if (!_loadContextByDirectory.TryGetValue(fullDirectoryPath, out loadContext)) @@ -83,6 +96,60 @@ private partial Assembly Load(AssemblyName assemblyName, string assemblyOriginal return loadContext.LoadFromAssemblyName(assemblyName); } + /// + /// Is this a registered analyzer file path that the loader knows about. + /// + /// Note: this is using resolved paths, not the original file paths + /// + private bool IsRegisteredAnalyzerPath(string resolvedPath) + { + CheckIfDisposed(); + + lock (_guard) + { + return _resolvedToOriginalPathMap.ContainsKey(resolvedPath); + } + } + + private string? GetAssemblyLoadPath(AssemblyName assemblyName, string directory) + { + // Prefer registered dependencies in the same directory first. + var simpleName = assemblyName.Name!; + var assemblyPath = Path.Combine(directory, simpleName + ".dll"); + if (IsRegisteredAnalyzerPath(assemblyPath)) + { + return assemblyPath; + } + + // Next if this is a resource assembly for a known assembly then load it from the + // appropriate sub directory if it exists + // + // Note: when loading from disk the .NET runtime has a fallback step that will handle + // satellite assembly loading if the call to Load(satelliteAssemblyName) fails. This + // loader has a mode where it loads from Stream though and the runtime will not handle + // that automatically. Rather than bifurcate our loading behavior between Disk and + // Stream both modes just handle satellite loading directly + if (assemblyName.CultureInfo is not null && simpleName.EndsWith(".resources", SimpleNameComparer.Comparison)) + { + var analyzerFileName = Path.ChangeExtension(simpleName, ".dll"); + var analyzerFilePath = Path.Combine(directory, analyzerFileName); + return GetSatelliteLoadPath(analyzerFilePath, assemblyName.CultureInfo); + } + + // Next prefer registered dependencies from other directories. Ideally this would not + // be necessary but msbuild target defaults have caused a number of customers to + // fall into this path. See discussion here for where it comes up + // https://github.com/dotnet/roslyn/issues/56442 + var (_, bestResolvedPath) = GetBestResolvedPath(assemblyName); + if (bestResolvedPath is not null) + { + return bestResolvedPath; + } + + // No analyzer registered this dependency. Time to fail + return null; + } + private partial bool IsMatch(AssemblyName requestedName, AssemblyName candidateName) => requestedName.Name == candidateName.Name; @@ -137,75 +204,24 @@ public DirectoryLoadContext(string directory, AnalyzerAssemblyLoader loader) protected override Assembly? Load(AssemblyName assemblyName) { - if (_loader.ResolveAssemblyExternally(assemblyName, Directory) is { } externallyResolvedAssembly) + foreach (var resolver in _loader.AnalyzerAssemblyResolvers) { - return externallyResolvedAssembly; - } - - // Prefer registered dependencies in the same directory first. - var simpleName = assemblyName.Name!; - var assemblyPath = Path.Combine(Directory, simpleName + ".dll"); - if (_loader.IsAnalyzerDependencyPath(assemblyPath)) - { - (_, var loadPath) = _loader.GetAssemblyInfoForPath(assemblyPath); - return loadCore(loadPath); - } - - // Next if this is a resource assembly for a known assembly then load it from the - // appropriate sub directory if it exists - // - // Note: when loading from disk the .NET runtime has a fallback step that will handle - // satellite assembly loading if the call to Load(satelliteAssemblyName) fails. This - // loader has a mode where it loads from Stream though and the runtime will not handle - // that automatically. Rather than bifurcate our loading behavior between Disk and - // Stream both modes just handle satellite loading directly - if (assemblyName.CultureInfo is not null && simpleName.EndsWith(".resources", StringComparison.Ordinal)) - { - var analyzerFileName = Path.ChangeExtension(simpleName, ".dll"); - var analyzerFilePath = Path.Combine(Directory, analyzerFileName); - var satelliteLoadPath = _loader.GetRealSatelliteLoadPath(analyzerFilePath, assemblyName.CultureInfo); - if (satelliteLoadPath is not null) + var assembly = resolver.Resolve(_loader, assemblyName, this, Directory); + if (assembly is not null) { - return loadCore(satelliteLoadPath); + return assembly; } - - return null; - } - - // Next prefer registered dependencies from other directories. Ideally this would not - // be necessary but msbuild target defaults have caused a number of customers to - // fall into this path. See discussion here for where it comes up - // https://github.com/dotnet/roslyn/issues/56442 - var (_, bestRealPath) = _loader.GetBestPath(assemblyName); - if (bestRealPath is not null) - { - return loadCore(bestRealPath); } - // No analyzer registered this dependency. Time to fail return null; - - Assembly loadCore(string assemblyPath) - { - if (_loader.AnalyzerLoadOption == AnalyzerLoadOption.LoadFromDisk) - { - return LoadFromAssemblyPath(assemblyPath); - } - else - { - using var stream = File.Open(assemblyPath, FileMode.Open, FileAccess.Read, FileShare.Read); - return LoadFromStream(stream); - } - } } protected override IntPtr LoadUnmanagedDll(string unmanagedDllName) { var assemblyPath = Path.Combine(Directory, unmanagedDllName + ".dll"); - if (_loader.IsAnalyzerDependencyPath(assemblyPath)) + if (_loader.IsRegisteredAnalyzerPath(assemblyPath)) { - (_, var loadPath) = _loader.GetAssemblyInfoForPath(assemblyPath); - return LoadUnmanagedDllFromPath(loadPath); + return LoadUnmanagedDllFromPath(assemblyPath); } return IntPtr.Zero; @@ -226,11 +242,11 @@ protected override IntPtr LoadUnmanagedDll(string unmanagedDllName) /// /// The that the core /// compiler assemblies are already loaded into. - internal sealed class CompilerAnalyzerAssemblyResolver(AssemblyLoadContext compilerContext) : IAnalyzerAssemblyResolver + private sealed class CompilerResolver(AssemblyLoadContext compilerContext) : IAnalyzerAssemblyResolver { private readonly AssemblyLoadContext _compilerAlc = compilerContext; - public Assembly? ResolveAssembly(AssemblyName assemblyName, string directoryName) + public Assembly? Resolve(AnalyzerAssemblyLoader loader, AssemblyName assemblyName, AssemblyLoadContext directoryContext, string directory) { try { @@ -244,6 +260,42 @@ internal sealed class CompilerAnalyzerAssemblyResolver(AssemblyLoadContext compi } } } + + private sealed class DiskResolver : IAnalyzerAssemblyResolver + { + public static readonly IAnalyzerAssemblyResolver Instance = new DiskResolver(); + public Assembly? Resolve(AnalyzerAssemblyLoader loader, AssemblyName assemblyName, AssemblyLoadContext directoryContext, string directory) + { + var assemblyPath = loader.GetAssemblyLoadPath(assemblyName, directory); + return assemblyPath is not null ? directoryContext.LoadFromAssemblyPath(assemblyPath) : null; + } + } + + /// + /// This loads the assemblies from a which is advantageous because it does + /// not lock the underlying assembly on disk. + /// + /// + /// This should be avoided on Windows. Yes locks files on disks but it also + /// amortizes the cost of AV scanning the assemblies. When loading from + /// the AV will scan the assembly every single time. That cost is significant and easily shows up in + /// performance profiles. + /// + private sealed class StreamResolver : IAnalyzerAssemblyResolver + { + public static readonly IAnalyzerAssemblyResolver Instance = new StreamResolver(); + public Assembly? Resolve(AnalyzerAssemblyLoader loader, AssemblyName assemblyName, AssemblyLoadContext directoryContext, string directory) + { + var assemblyPath = loader.GetAssemblyLoadPath(assemblyName, directory); + if (assemblyPath is null) + { + return null; + } + + using var stream = File.Open(assemblyPath, FileMode.Open, FileAccess.Read, FileShare.Read); + return directoryContext.LoadFromStream(stream); + } + } } } diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.Desktop.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.Desktop.cs index 698a16bb28747..edaf59a3f1094 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.Desktop.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.Desktop.cs @@ -14,24 +14,18 @@ namespace Microsoft.CodeAnalysis { - /// - /// Loads analyzer assemblies from their original locations in the file system. - /// Assemblies will only be loaded from the locations specified when the loader - /// is instantiated. - /// - /// - /// This type is meant to be used in scenarios where it is OK for the analyzer - /// assemblies to be locked on disk for the lifetime of the host; for example, - /// csc.exe and vbc.exe. In scenarios where support for updating or deleting - /// the analyzer on disk is required a different loader should be used. - /// internal partial class AnalyzerAssemblyLoader { private bool _hookedAssemblyResolve; - internal AnalyzerAssemblyLoader(ImmutableArray externalResolvers) + internal AnalyzerAssemblyLoader() + : this(analyzerPathResolvers: []) { - _externalResolvers = externalResolvers; + } + + internal AnalyzerAssemblyLoader(ImmutableArray analyzerPathResolvers) + { + AnalyzerPathResolvers = analyzerPathResolvers; } private partial void DisposeWorker() @@ -63,13 +57,9 @@ public bool IsHostAssembly(Assembly assembly) return false; } - private partial Assembly? Load(AssemblyName assemblyName, string assemblyOriginalPath) + private partial Assembly? Load(AssemblyName assemblyName, string resolvedPath) { EnsureResolvedHooked(); - if (ResolveAssemblyExternally(assemblyName, Path.GetDirectoryName(assemblyOriginalPath)) is { } externallyResolvedAssembly) - { - return externallyResolvedAssembly; - } return AppDomain.CurrentDomain.Load(assemblyName); } @@ -120,27 +110,25 @@ internal bool EnsureResolvedUnhooked() const string resourcesExtension = ".resources"; var assemblyName = new AssemblyName(args.Name); var simpleName = assemblyName.Name; - var isSatelliteAssembly = - assemblyName.CultureInfo is not null && - simpleName.EndsWith(resourcesExtension, StringComparison.Ordinal); - if (isSatelliteAssembly) + string? loadPath; + if (assemblyName.CultureInfo is not null && simpleName.EndsWith(resourcesExtension, SimpleNameComparer.Comparison)) { // Satellite assemblies should get the best path information using the // non-resource part of the assembly name. Once the path information is obtained - // GetSatelliteInfoForPath will translate to the resource assembly path. + // GetSatelliteLoadPath will translate to the resource assembly path. assemblyName.Name = simpleName[..^resourcesExtension.Length]; + var (_, resolvedPath) = GetBestResolvedPath(assemblyName); + loadPath = resolvedPath is not null ? GetSatelliteLoadPath(resolvedPath, assemblyName.CultureInfo) : null; } - - var (originalPath, realPath) = GetBestPath(assemblyName); - if (isSatelliteAssembly && originalPath is not null) + else { - realPath = GetRealSatelliteLoadPath(originalPath, assemblyName.CultureInfo); + (_, loadPath) = GetBestResolvedPath(assemblyName); } - if (realPath is not null) + if (loadPath is not null) { - return Assembly.LoadFrom(realPath); + return Assembly.LoadFrom(loadPath); } return null; diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.cs index c3f6ffc6c2d31..36e2fad512fc3 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.cs @@ -5,11 +5,12 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; -using Microsoft.CodeAnalysis.ErrorReporting; +using System.Runtime.InteropServices; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis @@ -31,66 +32,85 @@ internal interface IAnalyzerAssemblyLoaderInternal : IAnalyzerAssemblyLoader, ID } /// - /// The base implementation for . This type provides caching and tracking of inputs given + /// The implementation for . This type provides caching and tracking of inputs given /// to . /// /// /// This type generally assumes that files on disk aren't changing, since it ensure that two calls to /// will always return the same thing, per that interface's contract. + /// + /// A given analyzer can have two paths that represent it: the original path of the analyzer passed into this type + /// and the path returned after calling . In the + /// places where differentiating between the two is important, the original path will be referred to as the "original" and + /// the latter is referred to as "resolved". /// - internal abstract partial class AnalyzerAssemblyLoader : IAnalyzerAssemblyLoaderInternal + internal sealed partial class AnalyzerAssemblyLoader : IAnalyzerAssemblyLoaderInternal { private readonly object _guard = new(); /// - /// Set of analyzer dependencies original full paths to the data calculated for that path + /// The original paths are compared ordinally as the expectation is the host needs to handle normalization, + /// if necessary. That means if the host passes in a.dll and a.DLL the loader will treat them as different + /// even if the underlying file system is case insensitive. /// - /// - /// Access must be guarded by - /// - private readonly Dictionary _analyzerAssemblyInfoMap = new(); + internal static readonly StringComparer OriginalPathComparer = StringComparer.Ordinal; + + /// + /// These are paths generated by the loader, or one of its plugins. They need no normalization and hence + /// should be compared ordinally. + /// + internal static readonly StringComparer GeneratedPathComparer = StringComparer.Ordinal; + + /// + /// Simple names are not case sensitive + /// + internal static readonly (StringComparer Comparer, StringComparison Comparison) SimpleNameComparer = (StringComparer.OrdinalIgnoreCase, StringComparison.OrdinalIgnoreCase); /// - /// Mapping of analyzer dependency original full path and culture to the real satellite - /// assembly path. If the satellite assembly doesn't exist for the original analyzer and - /// culture, the real path value stored will be null. + /// This is a map between the original full path and how it is represented in this loader. Specifically + /// the key is the original path before it is considered by . /// /// /// Access must be guarded by /// - private readonly Dictionary<(string OriginalAnalyzerPath, CultureInfo CultureInfo), string?> _analyzerSatelliteAssemblyRealPaths = new(); + private readonly Dictionary _originalPathInfoMap = new(OriginalPathComparer); /// - /// Maps analyzer dependency simple names to the set of original full paths it was loaded from. This _only_ - /// tracks the paths provided to the analyzer as it's a place to look for indirect loads. + /// This is a map between assembly simple names and the collection of original paths that map to them. /// /// /// Access must be guarded by + /// + /// Simple names are not case sensitive /// - private readonly Dictionary> _knownAssemblyPathsBySimpleName = new(StringComparer.OrdinalIgnoreCase); + private readonly Dictionary> _assemblySimpleNameToOriginalPathListMap = new(SimpleNameComparer.Comparer); /// - /// A collection of s that can be used to override the assembly resolution process. + /// Map from resolved paths to the original ones /// /// - /// When multiple resolvers are present they are consulted in-order, with the first resolver to return a non-null - /// winning. - private readonly ImmutableArray _externalResolvers; + /// Access must be guarded by + /// + /// The paths are compared ordinally here as these are computed values, not user supplied ones, and the + /// values should refer to the file on disk with no alteration of its path. + /// + private readonly Dictionary _resolvedToOriginalPathMap = new(GeneratedPathComparer); /// - /// Whether or not we're disposed. Once disposed, all functionality on this type should throw. + /// Whether or not we're disposed. Once disposed, all functionality on this type should throw. /// private bool _isDisposed; + public ImmutableArray AnalyzerPathResolvers { get; } + /// - /// The implementation needs to load an with the specified . The - /// parameter is the original path. It may be different than - /// as that is empty on .NET Core. + /// The implementation needs to load an with the specified from + /// the specified path. /// /// /// This method should return an instance or throw. /// - private partial Assembly Load(AssemblyName assemblyName, string assemblyOriginalPath); + private partial Assembly Load(AssemblyName assemblyName, string resolvedPath); /// /// Determines if the satisfies the request for @@ -120,183 +140,194 @@ public void Dispose() private partial void DisposeWorker(); - internal bool IsAnalyzerDependencyPath(string fullPath) + public void AddDependencyLocation(string originalPath) { CheckIfDisposed(); - lock (_guard) + CompilerPathUtilities.RequireAbsolutePath(originalPath, nameof(originalPath)); + var simpleName = PathUtilities.GetFileName(originalPath, includeExtension: false); + string resolvedPath = originalPath; + IAnalyzerPathResolver? resolver = null; + foreach (var current in AnalyzerPathResolvers) { - return _analyzerAssemblyInfoMap.ContainsKey(fullPath); + if (current.IsAnalyzerPathHandled(originalPath)) + { + resolver = current; + resolvedPath = resolver.GetResolvedAnalyzerPath(originalPath); + break; + } } - } - public void AddDependencyLocation(string fullPath) - { - CheckIfDisposed(); - - CompilerPathUtilities.RequireAbsolutePath(fullPath, nameof(fullPath)); - string simpleName = PathUtilities.GetFileName(fullPath, includeExtension: false); + var assemblyName = readAssemblyName(resolvedPath); lock (_guard) { - if (!_knownAssemblyPathsBySimpleName.TryGetValue(simpleName, out var paths)) + if (_originalPathInfoMap.TryAdd(originalPath, (resolver, resolvedPath, assemblyName))) { - paths = ImmutableHashSet.Create(PathUtilities.Comparer, fullPath); - _knownAssemblyPathsBySimpleName.Add(simpleName, paths); + // In the case multiple original paths map to the same resolved path then the first one + // wins. + // + // An example reason to map multiple original paths to the same real path would be to + // unify references. + _ = _resolvedToOriginalPathMap.TryAdd(resolvedPath, originalPath); + + if (!_assemblySimpleNameToOriginalPathListMap.TryGetValue(simpleName, out var set)) + { + set = new(OriginalPathComparer); + _assemblySimpleNameToOriginalPathListMap[simpleName] = set; + } + + _ = set.Add(originalPath); } else { - _knownAssemblyPathsBySimpleName[simpleName] = paths.Add(fullPath); + Debug.Assert(GeneratedPathComparer.Equals(_originalPathInfoMap[originalPath].ResolvedPath, resolvedPath)); + } + } + + static AssemblyName? readAssemblyName(string filePath) + { + AssemblyName? assemblyName; + try + { + assemblyName = AssemblyName.GetAssemblyName(filePath); + } + catch + { + // The above can fail when the assembly doesn't exist because it's corrupted, + // doesn't exist on disk, or is a native DLL. Those failures are handled when + // the actual load is attempted. Just record the failure now. + assemblyName = null; } - // This type assumes the file system is static for the duration of the - // it's instance. Repeated calls to this method, even if the underlying - // file system contents, should reuse the results of the first call. - _ = _analyzerAssemblyInfoMap.TryAdd(fullPath, null); + return assemblyName; } } - public Assembly LoadFromPath(string originalAnalyzerPath) + /// + /// Called from the consumer of to load an analyzer assembly from disk. It + /// should _not_ be called from the implementation. + /// + public Assembly LoadFromPath(string originalPath) { CheckIfDisposed(); - CompilerPathUtilities.RequireAbsolutePath(originalAnalyzerPath, nameof(originalAnalyzerPath)); - - (AssemblyName? assemblyName, _) = GetAssemblyInfoForPath(originalAnalyzerPath); - - // Not a managed assembly, nothing else to do + CompilerPathUtilities.RequireAbsolutePath(originalPath, nameof(originalPath)); + var (resolvedPath, assemblyName) = GetResolvedAnalyzerPathAndName(originalPath); if (assemblyName is null) { - throw new ArgumentException($"Not a valid assembly: {originalAnalyzerPath}"); + // Not a managed assembly, nothing else to do + throw new ArgumentException($"Not a valid assembly: {originalPath}"); } try { - return Load(assemblyName, originalAnalyzerPath); + return Load(assemblyName, resolvedPath); } catch (Exception ex) { - throw new InvalidOperationException($"Unable to load {assemblyName.Name}", ex); + throw new InvalidOperationException($"Unable to load {assemblyName.Name}: {ex.Message}", ex); } } - /// - /// Get the and the path it should be loaded from for the given original - /// analyzer path - /// - /// - /// This is used in the implementation of the loader instead of - /// because we only want information for registered paths. Using unregistered paths inside the - /// implementation should result in errors. - /// - protected (AssemblyName? AssemblyName, string RealAssemblyPath) GetAssemblyInfoForPath(string originalAnalyzerPath) + private (string ResolvedPath, AssemblyName? AssemblyName) GetResolvedAnalyzerPathAndName(string originalPath) { CheckIfDisposed(); - lock (_guard) { - if (!_analyzerAssemblyInfoMap.TryGetValue(originalAnalyzerPath, out var tuple)) + if (!_originalPathInfoMap.TryGetValue(originalPath, out var info)) { - throw new InvalidOperationException(); + throw new ArgumentException("Path not registered: " + originalPath, nameof(originalPath)); } - if (tuple is { } info) - { - return info; - } + return (info.ResolvedPath, info.AssemblyName); } + } - string realPath = PreparePathToLoad(originalAnalyzerPath); - AssemblyName? assemblyName; - try - { - assemblyName = AssemblyName.GetAssemblyName(realPath); - } - catch + public string GetResolvedAnalyzerPath(string originalPath) => + GetResolvedAnalyzerPathAndName(originalPath).ResolvedPath; + + public string? GetResolvedSatellitePath(string originalPath, CultureInfo cultureInfo) + { + CheckIfDisposed(); + + IAnalyzerPathResolver? resolver; + lock (_guard) { - // The above can fail when the assembly doesn't exist because it's corrupted, - // doesn't exist on disk, or is a native DLL. Those failures are handled when - // the actual load is attempted. Just record the failure now. - assemblyName = null; + if (!_originalPathInfoMap.TryGetValue(originalPath, out var info)) + { + throw new ArgumentException("Path not registered: " + originalPath, nameof(originalPath)); + } + + resolver = info.Resolver; } - lock (_guard) + if (resolver is not null) { - _analyzerAssemblyInfoMap[originalAnalyzerPath] = (assemblyName, realPath); + return resolver.GetResolvedSatellitePath(originalPath, cultureInfo); } - return (assemblyName, realPath); + return GetSatelliteAssemblyPath(originalPath, cultureInfo); } /// - /// Get the path a satellite assembly should be loaded from for the given original + /// Get the path a satellite assembly should be loaded from for the given resolved /// analyzer path and culture /// - /// - /// This is used during assembly resolve for satellite assemblies to determine the - /// path from where the satellite assembly should be loaded for the specified culture. - /// This method calls to ensure this path - /// contains the satellite assembly. - /// - internal string? GetRealSatelliteLoadPath(string originalAnalyzerPath, CultureInfo cultureInfo) + private string? GetSatelliteLoadPath(string resolvedPath, CultureInfo cultureInfo) { - CheckIfDisposed(); - - string? realSatelliteAssemblyPath = null; + string? originalPath; lock (_guard) { - if (_analyzerSatelliteAssemblyRealPaths.TryGetValue((originalAnalyzerPath, cultureInfo), out realSatelliteAssemblyPath)) + if (!_resolvedToOriginalPathMap.TryGetValue(resolvedPath, out originalPath)) { - return realSatelliteAssemblyPath; + return null; } } - var actualCultureName = getSatelliteCultureName(originalAnalyzerPath, cultureInfo); - if (actualCultureName != null) - { - realSatelliteAssemblyPath = PrepareSatelliteAssemblyToLoad(originalAnalyzerPath, actualCultureName); - } + return GetResolvedSatellitePath(originalPath, cultureInfo); + } - lock (_guard) + /// + /// This method mimics the .NET lookup rules for satellite assemblies and will return the ideal + /// resource assembly for the given culture. + /// + internal static string? GetSatelliteAssemblyPath(string assemblyFilePath, CultureInfo cultureInfo) + { + var assemblyFileName = Path.GetFileName(assemblyFilePath); + var satelliteAssemblyName = Path.ChangeExtension(assemblyFileName, ".resources.dll"); + var path = Path.GetDirectoryName(assemblyFilePath); + if (path is null) { - _analyzerSatelliteAssemblyRealPaths[(originalAnalyzerPath, cultureInfo)] = realSatelliteAssemblyPath; + return null; } - return realSatelliteAssemblyPath; - - // Discover the most specific culture name to use for the specified analyzer path and culture - static string? getSatelliteCultureName(string originalAnalyzerPath, CultureInfo cultureInfo) + while (cultureInfo != CultureInfo.InvariantCulture) { - var path = Path.GetDirectoryName(originalAnalyzerPath)!; - var resourceFileName = GetSatelliteFileName(Path.GetFileName(originalAnalyzerPath)); - - while (cultureInfo != CultureInfo.InvariantCulture) + var filePath = Path.Combine(path, cultureInfo.Name, satelliteAssemblyName); + if (File.Exists(filePath)) { - var resourceFilePath = Path.Combine(path, cultureInfo.Name, resourceFileName); - - if (File.Exists(resourceFilePath)) - { - return cultureInfo.Name; - } - - cultureInfo = cultureInfo.Parent; + return filePath; } - return null; + cultureInfo = cultureInfo.Parent; } + + return null; } public string? GetOriginalDependencyLocation(AssemblyName assemblyName) { CheckIfDisposed(); - return GetBestPath(assemblyName).BestOriginalPath; + return GetBestResolvedPath(assemblyName).BestOriginalPath; } + /// - /// Return the best (original, real) path information for loading an assembly with the specified . + /// Return the best (original, resolved) path information for loading an assembly with the specified . /// - protected (string? BestOriginalPath, string? BestRealPath) GetBestPath(AssemblyName requestedName) + private (string? BestOriginalPath, string? BestResolvedPath) GetBestResolvedPath(AssemblyName requestedName) { CheckIfDisposed(); @@ -305,23 +336,23 @@ public Assembly LoadFromPath(string originalAnalyzerPath) return (null, null); } - ImmutableHashSet? paths; + List originalPaths; lock (_guard) { - if (!_knownAssemblyPathsBySimpleName.TryGetValue(requestedName.Name, out paths)) + if (!_assemblySimpleNameToOriginalPathListMap.TryGetValue(requestedName.Name, out var set)) { return (null, null); } + + originalPaths = set.OrderBy(x => x).ToList(); } - // Sort the candidate paths by ordinal, to ensure determinism with the same inputs if you were to have - // multiple assemblies providing the same version. - string? bestRealPath = null; + string? bestResolvedPath = null; string? bestOriginalPath = null; AssemblyName? bestName = null; - foreach (var candidateOriginalPath in paths.OrderBy(StringComparer.Ordinal)) + foreach (var candidateOriginalPath in originalPaths) { - (AssemblyName? candidateName, string candidateRealPath) = GetAssemblyInfoForPath(candidateOriginalPath); + var (candidateResolvedPath, candidateName) = GetResolvedAnalyzerPathAndName(candidateOriginalPath); if (candidateName is null) { continue; @@ -331,98 +362,91 @@ public Assembly LoadFromPath(string originalAnalyzerPath) { if (candidateName.Version == requestedName.Version) { - return (candidateOriginalPath, candidateRealPath); + return (candidateOriginalPath, candidateResolvedPath); } if (bestName is null || candidateName.Version > bestName.Version) { bestOriginalPath = candidateOriginalPath; - bestRealPath = candidateRealPath; + bestResolvedPath = candidateResolvedPath; bestName = candidateName; } } } - return (bestOriginalPath, bestRealPath); + return (bestOriginalPath, bestResolvedPath); } - protected static string GetSatelliteFileName(string assemblyFileName) => - Path.ChangeExtension(assemblyFileName, ".resources.dll"); - - /// - /// When overridden in a derived class, allows substituting an assembly path after we've - /// identified the context to load an assembly in, but before the assembly is actually - /// loaded from disk. This is used to substitute out the original path with the shadow-copied version. - /// - protected abstract string PreparePathToLoad(string assemblyFilePath); - - /// - /// When overridden in a derived class, allows substituting a satellite assembly path after we've - /// identified the context to load a satellite assembly in, but before the satellite assembly is actually - /// loaded from disk. This is used to substitute out the original path with the shadow-copied version. - /// - protected abstract string PrepareSatelliteAssemblyToLoad(string assemblyFilePath, string cultureName); - - /// - /// When is overridden this returns the most recent - /// real path calculated for the - /// - internal string GetRealAnalyzerLoadPath(string originalFullPath) + internal ImmutableArray<(string OriginalAssemblyPath, string ResolvedAssemblyPath)> GetPathMapSnapshot() { CheckIfDisposed(); lock (_guard) { - if (!_analyzerAssemblyInfoMap.TryGetValue(originalFullPath, out var tuple)) - { - throw new InvalidOperationException($"Invalid original path: {originalFullPath}"); - } - - return tuple is { } value ? value.RealAssemblyPath : originalFullPath; + return _resolvedToOriginalPathMap.Select(x => (x.Value, x.Key)).ToImmutableArray(); } } - internal (string OriginalAssemblyPath, string RealAssemblyPath)[] GetPathMapSnapshot() +#if NET + /// + /// Return an which does not lock assemblies on disk that is + /// most appropriate for the current platform. + /// + /// A shadow copy path will be created on Windows and this value + /// will be the base directory where shadow copy assemblies are stored. + internal static IAnalyzerAssemblyLoaderInternal CreateNonLockingLoader( + string windowsShadowPath, + ImmutableArray pathResolvers = default, + ImmutableArray assemblyResolvers = default, + System.Runtime.Loader.AssemblyLoadContext? compilerLoadContext = null) { - CheckIfDisposed(); + pathResolvers = pathResolvers.NullToEmpty(); + assemblyResolvers = assemblyResolvers.NullToEmpty(); - lock (_guard) + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - return _analyzerAssemblyInfoMap - .Select(x => (x.Key, x.Value?.RealAssemblyPath ?? "")) - .OrderBy(x => x.Key) - .ToArray(); + // The only reason we don't use LoadFromStream on Windows is because the anti-virus checker will amortize + // the cost of scanning files on disk. When loading from stream there is no such amortization, the + // anti-virus checker will scan the file every time it is loaded and the performance hit is significant. + // + // On non-Windows OS this is generally not a concern and loading from stream is sufficient to avoid + // locking the file. + return new AnalyzerAssemblyLoader( + pathResolvers, + [.. assemblyResolvers, StreamResolver.Instance], + compilerLoadContext); } + + // The goal here is to avoid locking files on disk that are reasonably expected to be changed by + // developers for the lifetime of VBCSCompiler, Visual Studio, VS Code, etc ... Places like + // Program Files are not expected to change and so locking is not a concern. But for everything else + // we want to avoid locking and use shadow copy. + return new AnalyzerAssemblyLoader( + [.. pathResolvers, ProgramFilesAnalyzerPathResolver.Instance, new ShadowCopyAnalyzerPathResolver(windowsShadowPath)], + [.. assemblyResolvers, DiskResolver.Instance], + compilerLoadContext); } +#else + /// - /// Iterates the if any, to see if any of them can resolve - /// the given to an . + /// Return an which does not lock assemblies on disk that is + /// most appropriate for the current platform. /// - /// The name of the assembly to resolve - /// An if one of the resolvers is successful, or - internal Assembly? ResolveAssemblyExternally(AssemblyName assemblyName, string rootDirectory) + /// A shadow copy path will be created on Windows and this value + /// will be the base directory where shadow copy assemblies are stored. + internal static IAnalyzerAssemblyLoaderInternal CreateNonLockingLoader( + string windowsShadowPath, + ImmutableArray pathResolvers = default) { - CheckIfDisposed(); + pathResolvers = pathResolvers.NullToEmpty(); - if (!_externalResolvers.IsDefaultOrEmpty) - { - foreach (var resolver in _externalResolvers) - { - try - { - if (resolver.ResolveAssembly(assemblyName, rootDirectory) is { } resolvedAssembly) - { - return resolvedAssembly; - } - } - catch (Exception ex) when (FatalError.ReportAndCatch(ex, ErrorSeverity.Diagnostic)) - { - // Ignore if the external resolver throws - } - } - } - return null; + // The goal here is to avoid locking files on disk that are reasonably expected to be changed by + // developers for the lifetime of VBCSCompiler, Visual Studio, VS Code, etc ... Places like + // Program Files are not expected to change and so locking is not a concern. But for everything else + // we want to avoid locking and use shadow copy. + return new AnalyzerAssemblyLoader([.. pathResolvers, ProgramFilesAnalyzerPathResolver.Instance, new ShadowCopyAnalyzerPathResolver(windowsShadowPath)]); } +#endif } } diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.GroupedAnalyzerActions.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.GroupedAnalyzerActions.cs index 04132ae8fafbe..521c4437f1a98 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.GroupedAnalyzerActions.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.GroupedAnalyzerActions.cs @@ -5,6 +5,7 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Linq; +using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; @@ -17,16 +18,25 @@ internal partial class AnalyzerDriver : AnalyzerDriver where /// private sealed class GroupedAnalyzerActions : IGroupedAnalyzerActions { - public static readonly GroupedAnalyzerActions Empty = new GroupedAnalyzerActions(ImmutableArray<(DiagnosticAnalyzer, GroupedAnalyzerActionsForAnalyzer)>.Empty, AnalyzerActions.Empty); + public static readonly GroupedAnalyzerActions Empty = new GroupedAnalyzerActions( + ImmutableArray<(DiagnosticAnalyzer, GroupedAnalyzerActionsForAnalyzer)>.Empty, + ImmutableSegmentedDictionary>.Empty, + AnalyzerActions.Empty); - private GroupedAnalyzerActions(ImmutableArray<(DiagnosticAnalyzer, GroupedAnalyzerActionsForAnalyzer)> groupedActionsAndAnalyzers, in AnalyzerActions analyzerActions) + private GroupedAnalyzerActions( + ImmutableArray<(DiagnosticAnalyzer, GroupedAnalyzerActionsForAnalyzer)> groupedActionsAndAnalyzers, + ImmutableSegmentedDictionary> analyzersByKind, + in AnalyzerActions analyzerActions) { GroupedActionsByAnalyzer = groupedActionsAndAnalyzers; AnalyzerActions = analyzerActions; + AnalyzersByKind = analyzersByKind; } public ImmutableArray<(DiagnosticAnalyzer analyzer, GroupedAnalyzerActionsForAnalyzer groupedActions)> GroupedActionsByAnalyzer { get; } + public ImmutableSegmentedDictionary> AnalyzersByKind { get; } + public AnalyzerActions AnalyzerActions { get; } public bool IsEmpty @@ -48,7 +58,8 @@ public static GroupedAnalyzerActions Create(DiagnosticAnalyzer analyzer, in Anal var groupedActions = new GroupedAnalyzerActionsForAnalyzer(analyzer, analyzerActions, analyzerActionsNeedFiltering: false); var groupedActionsAndAnalyzers = ImmutableArray<(DiagnosticAnalyzer, GroupedAnalyzerActionsForAnalyzer)>.Empty.Add((analyzer, groupedActions)); - return new GroupedAnalyzerActions(groupedActionsAndAnalyzers, in analyzerActions); + var analyzersByKind = CreateAnalyzersByKind(groupedActionsAndAnalyzers); + return new GroupedAnalyzerActions(groupedActionsAndAnalyzers, analyzersByKind, in analyzerActions); } public static GroupedAnalyzerActions Create(ImmutableArray analyzers, in AnalyzerActions analyzerActions) @@ -58,7 +69,8 @@ public static GroupedAnalyzerActions Create(ImmutableArray a var groups = analyzers.SelectAsArray( (analyzer, analyzerActions) => (analyzer, new GroupedAnalyzerActionsForAnalyzer(analyzer, analyzerActions, analyzerActionsNeedFiltering: true)), analyzerActions); - return new GroupedAnalyzerActions(groups, in analyzerActions); + var analyzersByKind = CreateAnalyzersByKind(groups); + return new GroupedAnalyzerActions(groups, analyzersByKind, in analyzerActions); } IGroupedAnalyzerActions IGroupedAnalyzerActions.Append(IGroupedAnalyzerActions igroupedAnalyzerActions) @@ -74,7 +86,22 @@ IGroupedAnalyzerActions IGroupedAnalyzerActions.Append(IGroupedAnalyzerActions i var newGroupedActions = GroupedActionsByAnalyzer.AddRange(groupedAnalyzerActions.GroupedActionsByAnalyzer); var newAnalyzerActions = AnalyzerActions.Append(groupedAnalyzerActions.AnalyzerActions); - return new GroupedAnalyzerActions(newGroupedActions, newAnalyzerActions); + var analyzersByKind = CreateAnalyzersByKind(newGroupedActions); + return new GroupedAnalyzerActions(newGroupedActions, analyzersByKind, newAnalyzerActions); + } + + private static ImmutableSegmentedDictionary> CreateAnalyzersByKind(ImmutableArray<(DiagnosticAnalyzer, GroupedAnalyzerActionsForAnalyzer)> groupedActionsAndAnalyzers) + { + var analyzersByKind = PooledDictionary>.GetInstance(); + foreach (var (analyzer, groupedActionsForAnalyzer) in groupedActionsAndAnalyzers) + { + foreach (var (kind, _) in groupedActionsForAnalyzer.NodeActionsByAnalyzerAndKind) + { + analyzersByKind.AddPooled(kind, analyzer); + } + } + + return analyzersByKind.ToImmutableSegmentedDictionaryAndFree(); } } } diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.GroupedAnalyzerActionsForAnalyzer.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.GroupedAnalyzerActionsForAnalyzer.cs index aa67d28c38cd7..021710ef3d925 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.GroupedAnalyzerActionsForAnalyzer.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.GroupedAnalyzerActionsForAnalyzer.cs @@ -4,8 +4,8 @@ using System.Collections.Immutable; using System.Diagnostics; -using System.Linq; using Microsoft.CodeAnalysis.Collections; +using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.Diagnostics { @@ -37,7 +37,7 @@ public GroupedAnalyzerActionsForAnalyzer(DiagnosticAnalyzer analyzer, in Analyze public AnalyzerActions AnalyzerActions { get; } [Conditional("DEBUG")] - private static void VerifyActions(in ImmutableArray actions, DiagnosticAnalyzer analyzer) + private static void VerifyActions(ArrayBuilder actions, DiagnosticAnalyzer analyzer) where TAnalyzerAction : AnalyzerAction { foreach (var action in actions) @@ -46,22 +46,33 @@ private static void VerifyActions(in ImmutableArray GetFilteredActions(in ImmutableArray actions) + private void AddFilteredActions( + ImmutableArray actions, + ArrayBuilder builder) where TAnalyzerAction : AnalyzerAction - => GetFilteredActions(actions, _analyzer, _analyzerActionsNeedFiltering); + { + AddFilteredActions(actions, _analyzer, _analyzerActionsNeedFiltering, builder); + } - private static ImmutableArray GetFilteredActions( + private static void AddFilteredActions( in ImmutableArray actions, DiagnosticAnalyzer analyzer, - bool analyzerActionsNeedFiltering) + bool analyzerActionsNeedFiltering, + ArrayBuilder builder) where TAnalyzerAction : AnalyzerAction { if (!analyzerActionsNeedFiltering) { - return actions; + builder.AddRange(actions); + } + else + { + foreach (var action in actions) + { + if (action.Analyzer == analyzer) + builder.Add(action); + } } - - return actions.WhereAsArray((action, analyzer) => action.Analyzer == analyzer, analyzer); } public ImmutableSegmentedDictionary>> NodeActionsByAnalyzerAndKind @@ -70,14 +81,15 @@ public ImmutableSegmentedDictionary(_analyzer) : - AnalyzerActions.GetSyntaxNodeActions(); + var nodeActions = ArrayBuilder>.GetInstance(); + if (_analyzerActionsNeedFiltering) + AnalyzerActions.AddSyntaxNodeActions(_analyzer, nodeActions); + else + AnalyzerActions.AddSyntaxNodeActions(nodeActions); + VerifyActions(nodeActions, _analyzer); - var analyzerActionsByKind = !nodeActions.IsEmpty ? - AnalyzerExecutor.GetNodeActionsByKind(nodeActions) : - ImmutableSegmentedDictionary>>.Empty; - RoslynImmutableInterlocked.InterlockedInitialize(ref _lazyNodeActionsByKind, analyzerActionsByKind); + RoslynImmutableInterlocked.InterlockedInitialize(ref _lazyNodeActionsByKind, AnalyzerExecutor.GetNodeActionsByKind(nodeActions)); + nodeActions.Free(); } return _lazyNodeActionsByKind; @@ -90,12 +102,11 @@ public ImmutableSegmentedDictionary.GetInstance(); + AddFilteredActions(AnalyzerActions.OperationActions, operationActions); VerifyActions(operationActions, _analyzer); - var analyzerActionsByKind = operationActions.Any() ? - AnalyzerExecutor.GetOperationActionsByKind(operationActions) : - ImmutableSegmentedDictionary>.Empty; - RoslynImmutableInterlocked.InterlockedInitialize(ref _lazyOperationActionsByKind, analyzerActionsByKind); + RoslynImmutableInterlocked.InterlockedInitialize(ref _lazyOperationActionsByKind, AnalyzerExecutor.GetOperationActionsByKind(operationActions)); + operationActions.Free(); } return _lazyOperationActionsByKind; @@ -108,9 +119,10 @@ private ImmutableArray> CodeBloc { if (_lazyCodeBlockStartActions.IsDefault) { - var codeBlockActions = GetFilteredActions(AnalyzerActions.GetCodeBlockStartActions()); + var codeBlockActions = ArrayBuilder>.GetInstance(); + AddFilteredActions(AnalyzerActions.GetCodeBlockStartActions(), codeBlockActions); VerifyActions(codeBlockActions, _analyzer); - ImmutableInterlocked.InterlockedInitialize(ref _lazyCodeBlockStartActions, codeBlockActions); + ImmutableInterlocked.InterlockedInitialize(ref _lazyCodeBlockStartActions, codeBlockActions.ToImmutableAndFree()); } return _lazyCodeBlockStartActions; @@ -144,9 +156,10 @@ private static ImmutableArray GetExecutableCodeActions( { if (lazyCodeBlockActions.IsDefault) { - codeBlockActions = GetFilteredActions(codeBlockActions, analyzer, analyzerActionsNeedFiltering); - VerifyActions(codeBlockActions, analyzer); - ImmutableInterlocked.InterlockedInitialize(ref lazyCodeBlockActions, codeBlockActions); + var finalActions = ArrayBuilder.GetInstance(); + AddFilteredActions(codeBlockActions, analyzer, analyzerActionsNeedFiltering, finalActions); + VerifyActions(finalActions, analyzer); + ImmutableInterlocked.InterlockedInitialize(ref lazyCodeBlockActions, finalActions.ToImmutableAndFree()); } return lazyCodeBlockActions; diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs index f3f942d2d1cfc..0528bc9c60098 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs @@ -844,7 +844,7 @@ internal static AnalyzerDriver CreateAndAttachToCompilation( { AnalyzerDriver analyzerDriver = compilation.CreateAnalyzerDriver(analyzers, analyzerManager, severityFilter); newCompilation = compilation - .WithSemanticModelProvider(new CachingSemanticModelProvider()) + .WithSemanticModelProvider(CachingSemanticModelProvider.Instance) .WithEventQueue(new AsyncQueue()); var categorizeDiagnostics = false; @@ -2611,10 +2611,26 @@ void executeNodeActions() void executeNodeActionsByKind(ArrayBuilder nodesToAnalyze, GroupedAnalyzerActions groupedActions, bool arePerSymbolActions) { + if (groupedActions.GroupedActionsByAnalyzer.Length == 0) + { + return; + } + + var analyzersForNodes = PooledHashSet.GetInstance(); + foreach (var node in nodesToAnalyze) + { + if (groupedActions.AnalyzersByKind.TryGetValue(_getKind(node), out var analyzersForKind)) + { + foreach (var analyzer in analyzersForKind) + { + analyzersForNodes.Add(analyzer); + } + } + } + foreach (var (analyzer, groupedActionsForAnalyzer) in groupedActions.GroupedActionsByAnalyzer) { - var nodeActionsByKind = groupedActionsForAnalyzer.NodeActionsByAnalyzerAndKind; - if (nodeActionsByKind.IsEmpty || !analysisScope.Contains(analyzer)) + if (!analyzersForNodes.Contains(analyzer) || !analysisScope.Contains(analyzer)) { continue; } @@ -2642,6 +2658,8 @@ void executeNodeActionsByKind(ArrayBuilder nodesToAnalyze, GroupedAn } } + analyzersForNodes.Free(); + void executeSyntaxNodeActions( DiagnosticAnalyzer analyzer, GroupedAnalyzerActionsForAnalyzer groupedActionsForAnalyzer, @@ -2764,7 +2782,7 @@ void executeOperationsActionsByKind(ImmutableArray operationsToAnaly } } - void executeOperationsBlockActions(ImmutableArray operationBlocksToAnalyze, ImmutableArray operationsToAnalyze, IEnumerable codeBlockActions) + void executeOperationsBlockActions(ImmutableArray operationBlocksToAnalyze, ImmutableArray operationsToAnalyze, ArrayBuilder codeBlockActions) { if (!shouldExecuteOperationBlockActions) { @@ -2792,7 +2810,7 @@ void executeOperationsBlockActions(ImmutableArray operationBlocksToA } } - void executeCodeBlockActions(ImmutableArray executableCodeBlocks, IEnumerable codeBlockActions) + void executeCodeBlockActions(ImmutableArray executableCodeBlocks, ArrayBuilder codeBlockActions) { if (executableCodeBlocks.IsEmpty || !shouldExecuteCodeBlockActions) { diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerExecutor.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerExecutor.cs index 17eeeb262d9b7..19d913bc9aa2a 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerExecutor.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerExecutor.cs @@ -201,11 +201,10 @@ public void ExecuteInitializeMethod(HostSessionStartAnalysisScope sessionScope, { var context = new AnalyzerAnalysisContext(sessionScope, severityFilter); - // The Initialize method should be run asynchronously in case it is not well behaved, e.g. does not terminate. ExecuteAndCatchIfThrows( sessionScope.Analyzer, - data => data.analyzer.Initialize(data.context), - (analyzer: sessionScope.Analyzer, context), + static data => data.sessionScope.Analyzer.Initialize(data.context), + (sessionScope, context), contextInfo: null, cancellationToken); } @@ -218,18 +217,19 @@ public void ExecuteInitializeMethod(HostSessionStartAnalysisScope sessionScope, /// Cancellation token. public void ExecuteCompilationStartActions(ImmutableArray actions, HostCompilationStartAnalysisScope compilationScope, CancellationToken cancellationToken) { + // This context doesn't build up any state as we pass it to the Action method of the analyzer. As such, we + // can use the same instance across all actions. + var context = new AnalyzerCompilationStartAnalysisContext(compilationScope, + Compilation, AnalyzerOptions, _compilationAnalysisValueProviderFactory, cancellationToken); + var contextInfo = new AnalysisContextInfo(Compilation); + foreach (var startAction in actions) { - cancellationToken.ThrowIfCancellationRequested(); - - var context = new AnalyzerCompilationStartAnalysisContext(compilationScope, - Compilation, AnalyzerOptions, _compilationAnalysisValueProviderFactory, cancellationToken); - ExecuteAndCatchIfThrows( startAction.Analyzer, - data => data.action(data.context), - (action: startAction.Action, context), - new AnalysisContextInfo(Compilation), + static data => data.startAction.Action(data.context), + (startAction, context), + contextInfo, cancellationToken); } } @@ -257,19 +257,21 @@ public void ExecuteSymbolStartActions( return; } + // This context doesn't build up any state as we pass it to the Action method of the analyzer. As such, we + // can use the same instance across all actions. + var context = new AnalyzerSymbolStartAnalysisContext(symbolScope, + symbol, Compilation, AnalyzerOptions, isGeneratedCodeSymbol, filterTree, filterSpan, cancellationToken); + var contextInfo = new AnalysisContextInfo(Compilation, symbol); + foreach (var startAction in actions) { Debug.Assert(startAction.Analyzer == symbolScope.Analyzer); - cancellationToken.ThrowIfCancellationRequested(); - - var context = new AnalyzerSymbolStartAnalysisContext(symbolScope, - symbol, Compilation, AnalyzerOptions, isGeneratedCodeSymbol, filterTree, filterSpan, cancellationToken); ExecuteAndCatchIfThrows( startAction.Analyzer, - data => data.action(data.context), - (action: startAction.Action, context), - new AnalysisContextInfo(Compilation, symbol), + static data => data.startAction.Action(data.context), + (startAction, context), + contextInfo, cancellationToken); } } @@ -292,15 +294,19 @@ public void ExecuteSuppressionAction(DiagnosticSuppressor suppressor, ImmutableA cancellationToken.ThrowIfCancellationRequested(); var supportedSuppressions = _analyzerManager.GetSupportedSuppressionDescriptors(suppressor, this, cancellationToken); - Func isSupportedSuppression = supportedSuppressions.Contains; - Action action = suppressor.ReportSuppressions; + + using var _ = PooledDelegates.GetPooledFunction( + static (d, supportedSuppressions) => supportedSuppressions.Contains(d), + supportedSuppressions, + out Func isSupportedSuppression); + var context = new SuppressionAnalysisContext(Compilation, AnalyzerOptions, reportedDiagnostics, _addSuppression, isSupportedSuppression, _getSemanticModel, cancellationToken); ExecuteAndCatchIfThrows( suppressor, - data => data.action(data.context), - (action, context), + static data => data.suppressor.ReportSuppressions(data.context), + (suppressor, context), new AnalysisContextInfo(Compilation), cancellationToken); } @@ -322,21 +328,25 @@ public void ExecuteCompilationActions( var addDiagnostic = GetAddCompilationDiagnostic(analyzer, cancellationToken); - using var _ = PooledDelegates.GetPooledFunction((d, ct, arg) => arg.self.IsSupportedDiagnostic(arg.analyzer, d, ct), (self: this, analyzer), out Func isSupportedDiagnostic); + using var _ = PooledDelegates.GetPooledFunction( + static (d, ct, arg) => arg.self.IsSupportedDiagnostic(arg.analyzer, d, ct), + (self: this, analyzer), + out Func isSupportedDiagnostic); + + // This context doesn't build up any state as we pass it to the Action method of the analyzer. As such, we + // can use the same instance across all actions. + var context = new CompilationAnalysisContext( + Compilation, AnalyzerOptions, addDiagnostic, + isSupportedDiagnostic, _compilationAnalysisValueProviderFactory, cancellationToken); + var contextInfo = new AnalysisContextInfo(Compilation); foreach (var endAction in compilationActions) { - cancellationToken.ThrowIfCancellationRequested(); - - var context = new CompilationAnalysisContext( - Compilation, AnalyzerOptions, addDiagnostic, - isSupportedDiagnostic, _compilationAnalysisValueProviderFactory, cancellationToken); - ExecuteAndCatchIfThrows( endAction.Analyzer, - data => data.action(data.context), - (action: endAction.Action, context), - new AnalysisContextInfo(Compilation), + static data => data.endAction.Action(data.context), + (endAction, context), + contextInfo, cancellationToken); } } @@ -372,25 +382,30 @@ public void ExecuteSymbolActions( var symbol = symbolDeclaredEvent.Symbol; var addDiagnostic = GetAddDiagnostic(symbol, symbolDeclaredEvent.DeclaringSyntaxReferences, analyzer, getTopMostNodeForAnalysis, cancellationToken); - using var _ = PooledDelegates.GetPooledFunction((d, ct, arg) => arg.self.IsSupportedDiagnostic(arg.analyzer, d, ct), (self: this, analyzer), out Func isSupportedDiagnostic); + using var _ = PooledDelegates.GetPooledFunction( + static (d, ct, arg) => arg.self.IsSupportedDiagnostic(arg.analyzer, d, ct), + (self: this, analyzer), + out Func isSupportedDiagnostic); + + // This context doesn't build up any state as we pass it to the Action method of the analyzer. As such, we + // can use the same instance across all actions. + var context = new SymbolAnalysisContext( + symbol, Compilation, AnalyzerOptions, addDiagnostic, + isSupportedDiagnostic, isGeneratedCodeSymbol, filterTree, + filterSpan, cancellationToken); + var contextInfo = new AnalysisContextInfo(Compilation, symbol); foreach (var symbolAction in symbolActions) { - var action = symbolAction.Action; - var kinds = symbolAction.Kinds; + cancellationToken.ThrowIfCancellationRequested(); - if (kinds.Contains(symbol.Kind)) + if (symbolAction.Kinds.Contains(symbol.Kind)) { - cancellationToken.ThrowIfCancellationRequested(); - - var context = new SymbolAnalysisContext(symbol, Compilation, AnalyzerOptions, addDiagnostic, - isSupportedDiagnostic, isGeneratedCodeSymbol, filterTree, filterSpan, cancellationToken); - ExecuteAndCatchIfThrows( symbolAction.Analyzer, - data => data.action(data.context), - (action, context), - new AnalysisContextInfo(Compilation, symbol), + static data => data.symbolAction.Action(data.context), + (symbolAction, context), + contextInfo, cancellationToken); } } @@ -477,22 +492,24 @@ private void ExecuteSymbolEndActionsCore( var symbol = symbolDeclaredEvent.Symbol; var addDiagnostic = GetAddDiagnostic(symbol, symbolDeclaredEvent.DeclaringSyntaxReferences, analyzer, getTopMostNodeForAnalysis, cancellationToken); - using var _ = PooledDelegates.GetPooledFunction((d, ct, arg) => arg.self.IsSupportedDiagnostic(arg.analyzer, d, ct), (self: this, analyzer), out Func isSupportedDiagnostic); + using var _ = PooledDelegates.GetPooledFunction( + static (d, ct, arg) => arg.self.IsSupportedDiagnostic(arg.analyzer, d, ct), + (self: this, analyzer), + out Func isSupportedDiagnostic); + + // This context doesn't build up any state as we pass it to the Action method of the analyzer. As such, we + // can use the same instance across all actions. + var context = new SymbolAnalysisContext(symbol, Compilation, AnalyzerOptions, addDiagnostic, + isSupportedDiagnostic, isGeneratedCode, filterTree, filterSpan, cancellationToken); + var contextInfo = new AnalysisContextInfo(Compilation, symbol); foreach (var symbolAction in symbolEndActions) { - var action = symbolAction.Action; - - cancellationToken.ThrowIfCancellationRequested(); - - var context = new SymbolAnalysisContext(symbol, Compilation, AnalyzerOptions, addDiagnostic, - isSupportedDiagnostic, isGeneratedCode, filterTree, filterSpan, cancellationToken); - ExecuteAndCatchIfThrows( symbolAction.Analyzer, - data => data.action(data.context), - (action, context), - new AnalysisContextInfo(Compilation, symbol), + static data => data.symbolAction.Action(data.context), + (symbolAction, context), + contextInfo, cancellationToken); } @@ -524,21 +541,25 @@ public void ExecuteSemanticModelActions( var diagReporter = GetAddSemanticDiagnostic(semanticModel.SyntaxTree, analyzer, cancellationToken); - using var _ = PooledDelegates.GetPooledFunction((d, ct, arg) => arg.self.IsSupportedDiagnostic(arg.analyzer, d, ct), (self: this, analyzer), out Func isSupportedDiagnostic); + using var _ = PooledDelegates.GetPooledFunction( + static (d, ct, arg) => arg.self.IsSupportedDiagnostic(arg.analyzer, d, ct), + (self: this, analyzer), + out Func isSupportedDiagnostic); + + // This context doesn't build up any state as we pass it to the Action method of the analyzer. As such, we + // can use the same instance across all actions. + var context = new SemanticModelAnalysisContext( + semanticModel, AnalyzerOptions, diagReporter.AddDiagnosticAction, + isSupportedDiagnostic, filterSpan, isGeneratedCode, cancellationToken); + var contextInfo = new AnalysisContextInfo(semanticModel); foreach (var semanticModelAction in semanticModelActions) { - cancellationToken.ThrowIfCancellationRequested(); - - var context = new SemanticModelAnalysisContext(semanticModel, AnalyzerOptions, diagReporter.AddDiagnosticAction, - isSupportedDiagnostic, filterSpan, isGeneratedCode, cancellationToken); - - // Catch Exception from action. ExecuteAndCatchIfThrows( semanticModelAction.Analyzer, - data => data.action(data.context), - (action: semanticModelAction.Action, context), - new AnalysisContextInfo(semanticModel), + static data => data.semanticModelAction.Action(data.context), + (semanticModelAction, context), + contextInfo, cancellationToken); } @@ -573,20 +594,25 @@ public void ExecuteSyntaxTreeActions( var diagReporter = GetAddSyntaxDiagnostic(file, analyzer, cancellationToken); - using var _ = PooledDelegates.GetPooledFunction((d, ct, arg) => arg.self.IsSupportedDiagnostic(arg.analyzer, d, ct), (self: this, analyzer), out Func isSupportedDiagnostic); + using var _ = PooledDelegates.GetPooledFunction( + static (d, ct, arg) => arg.self.IsSupportedDiagnostic(arg.analyzer, d, ct), + (self: this, analyzer), + out Func isSupportedDiagnostic); + + // This context doesn't build up any state as we pass it to the Action method of the analyzer. As such, we + // can use the same instance across all actions. + var context = new SyntaxTreeAnalysisContext( + tree, AnalyzerOptions, diagReporter.AddDiagnosticAction, isSupportedDiagnostic, + Compilation, filterSpan, isGeneratedCode, cancellationToken); + var contextInfo = new AnalysisContextInfo(Compilation, file); foreach (var syntaxTreeAction in syntaxTreeActions) { - cancellationToken.ThrowIfCancellationRequested(); - - var context = new SyntaxTreeAnalysisContext(tree, AnalyzerOptions, diagReporter.AddDiagnosticAction, isSupportedDiagnostic, Compilation, filterSpan, isGeneratedCode, cancellationToken); - - // Catch Exception from action. ExecuteAndCatchIfThrows( syntaxTreeAction.Analyzer, - data => data.action(data.context), - (action: syntaxTreeAction.Action, context), - new AnalysisContextInfo(Compilation, file), + static data => data.syntaxTreeAction.Action(data.context), + (syntaxTreeAction, context), + contextInfo, cancellationToken); } @@ -613,19 +639,25 @@ public void ExecuteAdditionalFileActions( var diagReporter = GetAddSyntaxDiagnostic(file, analyzer, cancellationToken); - using var _ = PooledDelegates.GetPooledFunction((d, ct, arg) => arg.self.IsSupportedDiagnostic(arg.analyzer, d, ct), (self: this, analyzer), out Func isSupportedDiagnostic); - foreach (var additionalFileAction in additionalFileActions) - { - cancellationToken.ThrowIfCancellationRequested(); + using var _ = PooledDelegates.GetPooledFunction( + static (d, ct, arg) => arg.self.IsSupportedDiagnostic(arg.analyzer, d, ct), + (self: this, analyzer), + out Func isSupportedDiagnostic); - var context = new AdditionalFileAnalysisContext(additionalFile, AnalyzerOptions, diagReporter.AddDiagnosticAction, isSupportedDiagnostic, Compilation, filterSpan, cancellationToken); + // This context doesn't build up any state as we pass it to the Action method of the analyzer. As such, we + // can use the same instance across all actions. + var context = new AdditionalFileAnalysisContext( + additionalFile, AnalyzerOptions, diagReporter.AddDiagnosticAction, isSupportedDiagnostic, + Compilation, filterSpan, cancellationToken); + var contextInfo = new AnalysisContextInfo(Compilation, file); - // Catch Exception from action. + foreach (var additionalFileAction in additionalFileActions) + { ExecuteAndCatchIfThrows( additionalFileAction.Analyzer, - data => data.action(data.context), - (action: additionalFileAction.Action, context), - new AnalysisContextInfo(Compilation, file), + static data => data.additionalFileAction.Action(data.context), + (additionalFileAction, context), + contextInfo, cancellationToken); } @@ -635,25 +667,23 @@ public void ExecuteAdditionalFileActions( private void ExecuteSyntaxNodeAction( SyntaxNodeAnalyzerAction syntaxNodeAction, SyntaxNode node, - ISymbol containingSymbol, - SemanticModel semanticModel, + ExecutionData executionData, Action addDiagnostic, Func isSupportedDiagnostic, - TextSpan? filterSpan, - bool isGeneratedCode, CancellationToken cancellationToken) where TLanguageKindEnum : struct { - Debug.Assert(!isGeneratedCode || !_shouldSkipAnalysisOnGeneratedCode(syntaxNodeAction.Analyzer)); + Debug.Assert(!executionData.IsGeneratedCode || !_shouldSkipAnalysisOnGeneratedCode(syntaxNodeAction.Analyzer)); Debug.Assert(!IsAnalyzerSuppressedForTree(syntaxNodeAction.Analyzer, node.SyntaxTree, cancellationToken)); - var syntaxNodeContext = new SyntaxNodeAnalysisContext(node, containingSymbol, semanticModel, AnalyzerOptions, addDiagnostic, - isSupportedDiagnostic, filterSpan, isGeneratedCode, cancellationToken); + var syntaxNodeContext = new SyntaxNodeAnalysisContext( + node, executionData.DeclaredSymbol, executionData.SemanticModel, AnalyzerOptions, addDiagnostic, + isSupportedDiagnostic, executionData.FilterSpan, executionData.IsGeneratedCode, cancellationToken); ExecuteAndCatchIfThrows( syntaxNodeAction.Analyzer, - data => data.action(data.context), - (action: syntaxNodeAction.Action, context: syntaxNodeContext), + static data => data.syntaxNodeAction.Action(data.syntaxNodeContext), + (syntaxNodeAction, syntaxNodeContext), new AnalysisContextInfo(Compilation, node), cancellationToken); } @@ -661,34 +691,48 @@ private void ExecuteSyntaxNodeAction( private void ExecuteOperationAction( OperationAnalyzerAction operationAction, IOperation operation, - ISymbol containingSymbol, - SemanticModel semanticModel, + ExecutionData executionData, Action addDiagnostic, Func isSupportedDiagnostic, - TextSpan? filterSpan, - bool isGeneratedCode, CancellationToken cancellationToken) { - Debug.Assert(!isGeneratedCode || !_shouldSkipAnalysisOnGeneratedCode(operationAction.Analyzer)); - Debug.Assert(!IsAnalyzerSuppressedForTree(operationAction.Analyzer, semanticModel.SyntaxTree, cancellationToken)); + Debug.Assert(!executionData.IsGeneratedCode || !_shouldSkipAnalysisOnGeneratedCode(operationAction.Analyzer)); + Debug.Assert(!IsAnalyzerSuppressedForTree(operationAction.Analyzer, executionData.SemanticModel.SyntaxTree, cancellationToken)); + + var operationContext = new OperationAnalysisContext( + operation, executionData.DeclaredSymbol, executionData.SemanticModel.Compilation, + AnalyzerOptions, addDiagnostic, isSupportedDiagnostic, GetControlFlowGraph, + executionData.FilterSpan, executionData.IsGeneratedCode, cancellationToken); - var operationContext = new OperationAnalysisContext(operation, containingSymbol, semanticModel.Compilation, - AnalyzerOptions, addDiagnostic, isSupportedDiagnostic, GetControlFlowGraph, filterSpan, isGeneratedCode, cancellationToken); ExecuteAndCatchIfThrows( operationAction.Analyzer, - data => data.action(data.context), - (action: operationAction.Action, context: operationContext), + static data => data.operationAction.Action(data.operationContext), + (operationAction, operationContext), new AnalysisContextInfo(Compilation, operation), cancellationToken); } + private readonly struct ExecutionData( + DiagnosticAnalyzer analyzer, + ISymbol declaredSymbol, + SemanticModel semanticModel, + TextSpan? filterSpan, + bool isGeneratedCode) + { + public readonly DiagnosticAnalyzer Analyzer = analyzer; + public readonly ISymbol DeclaredSymbol = declaredSymbol; + public readonly SemanticModel SemanticModel = semanticModel; + public readonly TextSpan? FilterSpan = filterSpan; + public readonly bool IsGeneratedCode = isGeneratedCode; + } + /// /// Execute code block actions for the given analyzer for the given declaration. /// public void ExecuteCodeBlockActions( - IEnumerable> codeBlockStartActions, - IEnumerable codeBlockActions, - IEnumerable codeBlockEndActions, + ImmutableArray> startActions, + ImmutableArray actions, + ImmutableArray endActions, DiagnosticAnalyzer analyzer, SyntaxNode declaredNode, ISymbol declaredSymbol, @@ -700,32 +744,98 @@ public void ExecuteCodeBlockActions( CancellationToken cancellationToken) where TLanguageKindEnum : struct { - ExecuteBlockActionsCore, CodeBlockAnalyzerAction, SyntaxNodeAnalyzerAction, SyntaxNode, TLanguageKindEnum>( - codeBlockStartActions, codeBlockActions, codeBlockEndActions, analyzer, - declaredNode, declaredSymbol, executableCodeBlocks, (codeBlocks) => codeBlocks.SelectMany( - cb => + Debug.Assert(!executableCodeBlocks.IsEmpty); + + // The actions we discover in 'addActions' and then execute in 'executeActions'. + var ephemeralActions = ArrayBuilder>.GetInstance(); + ExecuteBlockActionsCore( + startActions, + actions, + endActions, + declaredNode, + new ExecutionData(analyzer, declaredSymbol, semanticModel, filterSpan, isGeneratedCode), + addActions: static (startAction, endActions, executionData, args, cancellationToken) => + { + var (@this, startActions, executableCodeBlocks, declaredNode, getKind, ephemeralActions) = args; + + var scope = new HostCodeBlockStartAnalysisScope(startAction.Analyzer); + var startContext = new AnalyzerCodeBlockStartAnalysisContext( + scope, declaredNode, executionData.DeclaredSymbol, executionData.SemanticModel, + @this.AnalyzerOptions, executionData.FilterSpan, executionData.IsGeneratedCode, cancellationToken); + + // Catch Exception from the start action. + @this.ExecuteAndCatchIfThrows( + startAction.Analyzer, + static args => args.startAction.Action(args.startContext), + argument: (startAction, startContext), + new AnalysisContextInfo(@this.Compilation, executionData.DeclaredSymbol, declaredNode), + cancellationToken); + + endActions.AddAll(scope.CodeBlockEndActions); + ephemeralActions.AddRange(scope.SyntaxNodeActions); + }, + executeActions: static (diagReporter, isSupportedDiagnostic, executionData, args, cancellationToken) => + { + var (@this, startActions, executableCodeBlocks, declaredNode, getKind, ephemeralActions) = args; + if (ephemeralActions.Any()) { - var filter = semanticModel.GetSyntaxNodesToAnalyzeFilter(cb, declaredSymbol); + var executableNodeActionsByKind = GetNodeActionsByKind(ephemeralActions); + var syntaxNodesToAnalyze = ArrayBuilder.GetInstance(); - if (filter is object) - { - return cb.DescendantNodesAndSelf(descendIntoChildren: filter).Where(filter); - } - else + foreach (var block in executableCodeBlocks) { - return cb.DescendantNodesAndSelf(); + var filter = executionData.SemanticModel.GetSyntaxNodesToAnalyzeFilter(block, executionData.DeclaredSymbol); + if (filter is not null) + { + foreach (var descendantNode in block.DescendantNodesAndSelf(descendIntoChildren: filter)) + { + if (filter(descendantNode)) + syntaxNodesToAnalyze.Add(descendantNode); + } + } + else + { + syntaxNodesToAnalyze.AddRange(block.DescendantNodesAndSelf()); + } } - }), - semanticModel, getKind, filterSpan, isGeneratedCode, cancellationToken); + + @this.ExecuteSyntaxNodeActions( + syntaxNodesToAnalyze, executableNodeActionsByKind, executionData, + getKind, diagReporter, isSupportedDiagnostic, + hasCodeBlockStartOrSymbolStartActions: startActions.Any(), + cancellationToken); + syntaxNodesToAnalyze.Free(); + } + }, + executeBlockActions: static (blockActions, diagReporter, isSupportedDiagnostic, executionData, args, cancellationToken) => + { + var (@this, startActions, executableCodeBlocks, declaredNode, getKind, ephemeralActions) = args; + + var context = new CodeBlockAnalysisContext(declaredNode, executionData.DeclaredSymbol, executionData.SemanticModel, + @this.AnalyzerOptions, diagReporter.AddDiagnosticAction, isSupportedDiagnostic, executionData.FilterSpan, executionData.IsGeneratedCode, cancellationToken); + + foreach (var blockAction in blockActions) + { + @this.ExecuteAndCatchIfThrows( + blockAction.Analyzer, + static data => data.blockAction.Action(data.context), + (blockAction, context), + new AnalysisContextInfo(@this.Compilation, executionData.DeclaredSymbol, declaredNode), + cancellationToken); + } + }, + argument: (@this: this, startActions, executableCodeBlocks, declaredNode, getKind, ephemeralActions), + cancellationToken); + ephemeralActions.Free(); } /// /// Execute operation block actions for the given analyzer for the given declaration. /// public void ExecuteOperationBlockActions( - IEnumerable operationBlockStartActions, - IEnumerable operationBlockActions, - IEnumerable operationBlockEndActions, + ImmutableArray startActions, + ImmutableArray actions, + ImmutableArray endActions, DiagnosticAnalyzer analyzer, SyntaxNode declaredNode, ISymbol declaredSymbol, @@ -736,39 +846,92 @@ public void ExecuteOperationBlockActions( bool isGeneratedCode, CancellationToken cancellationToken) { - ExecuteBlockActionsCore( - operationBlockStartActions, operationBlockActions, operationBlockEndActions, analyzer, - declaredNode, declaredSymbol, operationBlocks, (blocks) => operations, semanticModel, - getKind: null, filterSpan, isGeneratedCode, cancellationToken); + Debug.Assert(!operationBlocks.IsEmpty); + + // The actions we discover in 'addActions' and then execute in 'executeActions'. + var ephemeralActions = ArrayBuilder.GetInstance(); + ExecuteBlockActionsCore( + startActions, + actions, + endActions, + declaredNode, + new ExecutionData(analyzer, declaredSymbol, semanticModel, filterSpan, isGeneratedCode), + addActions: static (startAction, endActions, executionData, args, cancellationToken) => + { + var (@this, startActions, declaredNode, operationBlocks, operations, ephemeralActions) = args; + var scope = new HostOperationBlockStartAnalysisScope(startAction.Analyzer); + var startContext = new AnalyzerOperationBlockStartAnalysisContext( + scope, operationBlocks, executionData.DeclaredSymbol, executionData.SemanticModel.Compilation, @this.AnalyzerOptions, + @this.GetControlFlowGraph, declaredNode.SyntaxTree, executionData.FilterSpan, executionData.IsGeneratedCode, cancellationToken); + + // Catch Exception from the start action. + @this.ExecuteAndCatchIfThrows( + startAction.Analyzer, + static args => args.startAction.Action(args.startContext), + argument: (startAction, startContext), + new AnalysisContextInfo(@this.Compilation, executionData.DeclaredSymbol), + cancellationToken); + + endActions.AddAll(scope.OperationBlockEndActions); + ephemeralActions.AddRange(scope.OperationActions); + }, + executeActions: static (diagReporter, isSupportedDiagnostic, executionData, args, cancellationToken) => + { + var (@this, startActions, declaredNode, operationBlocks, operations, ephemeralActions) = args; + if (ephemeralActions.Any()) + { + @this.ExecuteOperationActions( + operations, GetOperationActionsByKind(ephemeralActions), + executionData, diagReporter, isSupportedDiagnostic, + hasOperationBlockStartOrSymbolStartActions: startActions.Any(), + cancellationToken); + } + }, + executeBlockActions: static (blockActions, diagReporter, isSupportedDiagnostic, executionData, args, cancellationToken) => + { + var (@this, startActions, declaredNode, operationBlocks, operations, ephemeralActions) = args; + + var context = new OperationBlockAnalysisContext(operationBlocks, executionData.DeclaredSymbol, @this.Compilation, + @this.AnalyzerOptions, diagReporter.AddDiagnosticAction, isSupportedDiagnostic, @this.GetControlFlowGraph, declaredNode.SyntaxTree, + executionData.FilterSpan, executionData.IsGeneratedCode, cancellationToken); + + foreach (var blockAction in blockActions) + { + @this.ExecuteAndCatchIfThrows( + blockAction.Analyzer, + static data => data.blockAction.Action(data.context), + (blockAction, context), + new AnalysisContextInfo(@this.Compilation, executionData.DeclaredSymbol), + cancellationToken); + } + }, + argument: (@this: this, startActions, declaredNode, operationBlocks, operations, ephemeralActions), + cancellationToken); + ephemeralActions.Free(); } - private void ExecuteBlockActionsCore( - IEnumerable startActions, - IEnumerable actions, - IEnumerable endActions, - DiagnosticAnalyzer analyzer, - SyntaxNode declaredNode, - ISymbol declaredSymbol, - ImmutableArray executableBlocks, - Func, IEnumerable> getNodesToAnalyze, - SemanticModel semanticModel, - Func? getKind, - TextSpan? filterSpan, - bool isGeneratedCode, - CancellationToken cancellationToken) - where TLanguageKindEnum : struct - where TBlockStartAction : AnalyzerAction - where TBlockAction : AnalyzerAction - where TNodeAction : AnalyzerAction + private void ExecuteBlockActionsCore( + ImmutableArray startActions, + ImmutableArray actions, + ImmutableArray endActions, + SyntaxNode declaredNode, + ExecutionData executionData, + Action, ExecutionData, TArgs, CancellationToken> addActions, + Action, ExecutionData, TArgs, CancellationToken> executeActions, + Action, AnalyzerDiagnosticReporter, Func, ExecutionData, TArgs, CancellationToken> executeBlockActions, + TArgs argument, + CancellationToken cancellationToken) + where TBlockStartAction : AnalyzerAction + where TBlockAction : AnalyzerAction + where TArgs : struct { Debug.Assert(declaredNode != null); - Debug.Assert(declaredSymbol != null); - Debug.Assert(CanHaveExecutableCodeBlock(declaredSymbol)); + Debug.Assert(executionData.DeclaredSymbol != null); + Debug.Assert(CanHaveExecutableCodeBlock(executionData.DeclaredSymbol)); Debug.Assert(startActions.Any() || endActions.Any() || actions.Any()); - Debug.Assert(!executableBlocks.IsEmpty); - if (isGeneratedCode && _shouldSkipAnalysisOnGeneratedCode(analyzer) || - IsAnalyzerSuppressedForTree(analyzer, declaredNode.SyntaxTree, cancellationToken)) + if (executionData.IsGeneratedCode && _shouldSkipAnalysisOnGeneratedCode(executionData.Analyzer) || + IsAnalyzerSuppressedForTree(executionData.Analyzer, declaredNode.SyntaxTree, cancellationToken)) { return; } @@ -777,10 +940,6 @@ private void ExecuteBlockActionsCore.GetInstance(); var blockActions = PooledHashSet.GetInstance(); - var executableNodeActions = ArrayBuilder.GetInstance(); - var syntaxNodeActions = executableNodeActions as ArrayBuilder>; - var operationActions = executableNodeActions as ArrayBuilder; - ImmutableArray operationBlocks = executableBlocks[0] is IOperation ? (ImmutableArray)(object)executableBlocks : ImmutableArray.Empty; // Include the code block actions. blockActions.AddAll(actions); @@ -788,170 +947,53 @@ private void ExecuteBlockActionsCore codeBlockStartAction) - { - var codeBlockEndActions = blockEndActions as PooledHashSet; - var codeBlockScope = new HostCodeBlockStartAnalysisScope(startAction.Analyzer); - var blockStartContext = new AnalyzerCodeBlockStartAnalysisContext( - codeBlockScope, declaredNode, declaredSymbol, semanticModel, AnalyzerOptions, filterSpan, isGeneratedCode, cancellationToken); - - // Catch Exception from the start action. - ExecuteAndCatchIfThrows( - startAction.Analyzer, - data => - { - data.action(data.context); - data.blockEndActions?.AddAll(data.scope.CodeBlockEndActions); - data.syntaxNodeActions?.AddRange(data.scope.SyntaxNodeActions); - }, - (action: codeBlockStartAction.Action, context: blockStartContext, scope: codeBlockScope, blockEndActions: codeBlockEndActions, syntaxNodeActions), - new AnalysisContextInfo(Compilation, declaredSymbol, declaredNode), - cancellationToken); - } - else - { - if (startAction is OperationBlockStartAnalyzerAction operationBlockStartAction) - { - var operationBlockEndActions = blockEndActions as PooledHashSet; - var operationBlockScope = new HostOperationBlockStartAnalysisScope(startAction.Analyzer); - var operationStartContext = new AnalyzerOperationBlockStartAnalysisContext( - operationBlockScope, operationBlocks, declaredSymbol, semanticModel.Compilation, AnalyzerOptions, - GetControlFlowGraph, declaredNode.SyntaxTree, filterSpan, isGeneratedCode, cancellationToken); - - // Catch Exception from the start action. - ExecuteAndCatchIfThrows( - startAction.Analyzer, - data => - { - data.action(data.context); - data.blockEndActions?.AddAll(data.scope.OperationBlockEndActions); - data.operationActions?.AddRange(data.scope.OperationActions); - }, - (action: operationBlockStartAction.Action, context: operationStartContext, scope: operationBlockScope, blockEndActions: operationBlockEndActions, operationActions: operationActions), - new AnalysisContextInfo(Compilation, declaredSymbol), - cancellationToken); - } - } - } + addActions(startAction, blockEndActions, executionData, argument, cancellationToken); - using var _ = PooledDelegates.GetPooledFunction((d, ct, arg) => arg.self.IsSupportedDiagnostic(arg.analyzer, d, ct), (self: this, analyzer), out Func isSupportedDiagnostic); + using var _ = PooledDelegates.GetPooledFunction( + static (d, ct, arg) => arg.self.IsSupportedDiagnostic(arg.Analyzer, d, ct), + (self: this, executionData.Analyzer), + out Func isSupportedDiagnostic); // Execute stateful executable node analyzers, if any. - if (executableNodeActions.Any()) - { - if (syntaxNodeActions != null) - { - Debug.Assert(getKind != null); - - var executableNodeActionsByKind = GetNodeActionsByKind(syntaxNodeActions); - var syntaxNodesToAnalyze = (IEnumerable)getNodesToAnalyze(executableBlocks); - ExecuteSyntaxNodeActions(syntaxNodesToAnalyze, executableNodeActionsByKind, analyzer, declaredSymbol, semanticModel, getKind, diagReporter, isSupportedDiagnostic, filterSpan, isGeneratedCode, hasCodeBlockStartOrSymbolStartActions: startActions.Any(), cancellationToken); - } - else if (operationActions != null) - { - var operationActionsByKind = GetOperationActionsByKind(operationActions); - var operationsToAnalyze = (IEnumerable)getNodesToAnalyze(executableBlocks); - ExecuteOperationActions(operationsToAnalyze, operationActionsByKind, analyzer, declaredSymbol, semanticModel, diagReporter, isSupportedDiagnostic, filterSpan, isGeneratedCode, hasOperationBlockStartOrSymbolStartActions: startActions.Any(), cancellationToken); - } - } - - executableNodeActions.Free(); + executeActions(diagReporter, isSupportedDiagnostic, executionData, argument, cancellationToken); - ExecuteBlockActions(blockActions, declaredNode, declaredSymbol, analyzer, semanticModel, operationBlocks, diagReporter.AddDiagnosticAction, isSupportedDiagnostic, filterSpan, isGeneratedCode, cancellationToken); - ExecuteBlockActions(blockEndActions, declaredNode, declaredSymbol, analyzer, semanticModel, operationBlocks, diagReporter.AddDiagnosticAction, isSupportedDiagnostic, filterSpan, isGeneratedCode, cancellationToken); + executeBlockActions(blockActions, diagReporter, isSupportedDiagnostic, executionData, argument, cancellationToken); + executeBlockActions(blockEndActions, diagReporter, isSupportedDiagnostic, executionData, argument, cancellationToken); diagReporter.Free(); - } - - private void ExecuteBlockActions( - PooledHashSet blockActions, - SyntaxNode declaredNode, - ISymbol declaredSymbol, - DiagnosticAnalyzer analyzer, - SemanticModel semanticModel, - ImmutableArray operationBlocks, - Action addDiagnostic, - Func isSupportedDiagnostic, - TextSpan? filterSpan, - bool isGeneratedCode, - CancellationToken cancellationToken) - where TBlockAction : AnalyzerAction - { - Debug.Assert(!isGeneratedCode || !_shouldSkipAnalysisOnGeneratedCode(analyzer)); - Debug.Assert(!IsAnalyzerSuppressedForTree(analyzer, declaredNode.SyntaxTree, cancellationToken)); - - foreach (var blockAction in blockActions) - { - var codeBlockAction = blockAction as CodeBlockAnalyzerAction; - if (codeBlockAction != null) - { - var context = new CodeBlockAnalysisContext(declaredNode, declaredSymbol, semanticModel, - AnalyzerOptions, addDiagnostic, isSupportedDiagnostic, filterSpan, isGeneratedCode, cancellationToken); - - ExecuteAndCatchIfThrows( - codeBlockAction.Analyzer, - data => data.action(data.context), - (action: codeBlockAction.Action, context: context), - new AnalysisContextInfo(Compilation, declaredSymbol, declaredNode), - cancellationToken); - } - else - { - var operationBlockAction = blockAction as OperationBlockAnalyzerAction; - if (operationBlockAction != null) - { - var context = new OperationBlockAnalysisContext(operationBlocks, declaredSymbol, semanticModel.Compilation, - AnalyzerOptions, addDiagnostic, isSupportedDiagnostic, GetControlFlowGraph, declaredNode.SyntaxTree, filterSpan, isGeneratedCode, cancellationToken); - - ExecuteAndCatchIfThrows( - operationBlockAction.Analyzer, - data => data.action(data.context), - (action: operationBlockAction.Action, context), - new AnalysisContextInfo(Compilation, declaredSymbol), - cancellationToken); - } - } - } - blockActions.Free(); + blockEndActions.Free(); } internal static ImmutableSegmentedDictionary>> GetNodeActionsByKind( - IEnumerable> nodeActions) + ArrayBuilder> nodeActions) where TLanguageKindEnum : struct { - Debug.Assert(nodeActions != null && nodeActions.Any()); + if (nodeActions.IsEmpty) + return ImmutableSegmentedDictionary>>.Empty; var nodeActionsByKind = PooledDictionary>>.GetInstance(); foreach (var nodeAction in nodeActions) { foreach (var kind in nodeAction.Kinds) { - if (!nodeActionsByKind.TryGetValue(kind, out var actionsForKind)) - { - nodeActionsByKind.Add(kind, actionsForKind = ArrayBuilder>.GetInstance()); - } - - actionsForKind.Add(nodeAction); + nodeActionsByKind.AddPooled(kind, nodeAction); } } - var tuples = nodeActionsByKind.Select(kvp => KeyValuePairUtil.Create(kvp.Key, kvp.Value.ToImmutableAndFree())); - var map = ImmutableSegmentedDictionary.CreateRange(tuples); - nodeActionsByKind.Free(); - return map; + return nodeActionsByKind.ToImmutableSegmentedDictionaryAndFree(); } /// /// Execute syntax node actions for the given analyzer for the given declaration. /// public void ExecuteSyntaxNodeActions( - IEnumerable nodesToAnalyze, + ArrayBuilder nodesToAnalyze, ImmutableSegmentedDictionary>> nodeActionsByKind, DiagnosticAnalyzer analyzer, SemanticModel model, @@ -972,29 +1014,33 @@ public void ExecuteSyntaxNodeActions( var diagReporter = GetAddSemanticDiagnostic(model.SyntaxTree, spanForContainingTopmostNodeForAnalysis, analyzer, cancellationToken); - using var _ = PooledDelegates.GetPooledFunction((d, ct, arg) => arg.self.IsSupportedDiagnostic(arg.analyzer, d, ct), (self: this, analyzer), out Func isSupportedDiagnostic); - ExecuteSyntaxNodeActions(nodesToAnalyze, nodeActionsByKind, analyzer, declaredSymbol, model, getKind, diagReporter, isSupportedDiagnostic, filterSpan, isGeneratedCode, hasCodeBlockStartOrSymbolStartActions, cancellationToken); + using var _ = PooledDelegates.GetPooledFunction( + static (d, ct, arg) => arg.self.IsSupportedDiagnostic(arg.analyzer, d, ct), + (self: this, analyzer), + out Func isSupportedDiagnostic); + + ExecuteSyntaxNodeActions( + nodesToAnalyze, nodeActionsByKind, + new ExecutionData(analyzer, declaredSymbol, model, filterSpan, isGeneratedCode), + getKind, diagReporter, isSupportedDiagnostic, hasCodeBlockStartOrSymbolStartActions, cancellationToken); + diagReporter.Free(); } private void ExecuteSyntaxNodeActions( - IEnumerable nodesToAnalyze, + ArrayBuilder nodesToAnalyze, ImmutableSegmentedDictionary>> nodeActionsByKind, - DiagnosticAnalyzer analyzer, - ISymbol containingSymbol, - SemanticModel model, + ExecutionData executionData, Func getKind, AnalyzerDiagnosticReporter diagReporter, Func isSupportedDiagnostic, - TextSpan? filterSpan, - bool isGeneratedCode, bool hasCodeBlockStartOrSymbolStartActions, CancellationToken cancellationToken) where TLanguageKindEnum : struct { Debug.Assert(nodeActionsByKind.Any()); - Debug.Assert(!isGeneratedCode || !_shouldSkipAnalysisOnGeneratedCode(analyzer)); - Debug.Assert(!IsAnalyzerSuppressedForTree(analyzer, model.SyntaxTree, cancellationToken)); + Debug.Assert(!executionData.IsGeneratedCode || !_shouldSkipAnalysisOnGeneratedCode(executionData.Analyzer)); + Debug.Assert(!IsAnalyzerSuppressedForTree(executionData.Analyzer, executionData.SemanticModel.SyntaxTree, cancellationToken)); foreach (var node in nodesToAnalyze) { @@ -1004,7 +1050,7 @@ private void ExecuteSyntaxNodeActions( if (nodeActionsByKind.TryGetValue(getKind(node), out var actionsForKind)) { RoslynDebug.Assert(!actionsForKind.IsEmpty, $"Unexpected empty action collection in {nameof(nodeActionsByKind)}"); - if (ShouldExecuteNode(node, analyzer, cancellationToken)) + if (ShouldExecuteNode(node, executionData.Analyzer, cancellationToken)) { // If analyzer hasn't registered any CodeBlockStart or SymbolStart actions, then update the filter span // for local diagnostics to be the callback node's full span. @@ -1015,35 +1061,29 @@ private void ExecuteSyntaxNodeActions( foreach (var action in actionsForKind) { - ExecuteSyntaxNodeAction(action, node, containingSymbol, model, diagReporter.AddDiagnosticAction, isSupportedDiagnostic, filterSpan, isGeneratedCode, cancellationToken); + ExecuteSyntaxNodeAction(action, node, executionData, diagReporter.AddDiagnosticAction, isSupportedDiagnostic, cancellationToken); } } } } } - internal static ImmutableSegmentedDictionary> GetOperationActionsByKind(IEnumerable operationActions) + internal static ImmutableSegmentedDictionary> GetOperationActionsByKind( + ArrayBuilder operationActions) { - Debug.Assert(operationActions.Any()); + if (operationActions.IsEmpty) + return ImmutableSegmentedDictionary>.Empty; var operationActionsByKind = PooledDictionary>.GetInstance(); foreach (var operationAction in operationActions) { foreach (var kind in operationAction.Kinds) { - if (!operationActionsByKind.TryGetValue(kind, out var actionsForKind)) - { - operationActionsByKind.Add(kind, actionsForKind = ArrayBuilder.GetInstance()); - } - - actionsForKind.Add(operationAction); + operationActionsByKind.AddPooled(kind, operationAction); } } - var tuples = operationActionsByKind.Select(kvp => KeyValuePairUtil.Create(kvp.Key, kvp.Value.ToImmutableAndFree())); - var map = ImmutableSegmentedDictionary.CreateRange(tuples); - operationActionsByKind.Free(); - return map; + return operationActionsByKind.ToImmutableSegmentedDictionaryAndFree(); } /// @@ -1054,7 +1094,7 @@ internal static ImmutableSegmentedDictionary public void ExecuteOperationActions( - IEnumerable operationsToAnalyze, + ImmutableArray operationsToAnalyze, ImmutableSegmentedDictionary> operationActionsByKind, DiagnosticAnalyzer analyzer, SemanticModel model, @@ -1073,28 +1113,32 @@ public void ExecuteOperationActions( var diagReporter = GetAddSemanticDiagnostic(model.SyntaxTree, spanForContainingOperationBlock, analyzer, cancellationToken); - using var _ = PooledDelegates.GetPooledFunction((d, ct, arg) => arg.self.IsSupportedDiagnostic(arg.analyzer, d, ct), (self: this, analyzer), out Func isSupportedDiagnostic); - ExecuteOperationActions(operationsToAnalyze, operationActionsByKind, analyzer, declaredSymbol, model, diagReporter, isSupportedDiagnostic, filterSpan, isGeneratedCode, hasOperationBlockStartOrSymbolStartActions, cancellationToken); + using var _ = PooledDelegates.GetPooledFunction( + static (d, ct, arg) => arg.self.IsSupportedDiagnostic(arg.analyzer, d, ct), + (self: this, analyzer), + out Func isSupportedDiagnostic); + + ExecuteOperationActions( + operationsToAnalyze, operationActionsByKind, + new ExecutionData(analyzer, declaredSymbol, model, filterSpan, isGeneratedCode), + diagReporter, isSupportedDiagnostic, hasOperationBlockStartOrSymbolStartActions, cancellationToken); + diagReporter.Free(); } private void ExecuteOperationActions( - IEnumerable operationsToAnalyze, + ImmutableArray operationsToAnalyze, ImmutableSegmentedDictionary> operationActionsByKind, - DiagnosticAnalyzer analyzer, - ISymbol containingSymbol, - SemanticModel model, + ExecutionData executionData, AnalyzerDiagnosticReporter diagReporter, Func isSupportedDiagnostic, - TextSpan? filterSpan, - bool isGeneratedCode, bool hasOperationBlockStartOrSymbolStartActions, CancellationToken cancellationToken) { Debug.Assert(operationActionsByKind != null); Debug.Assert(operationActionsByKind.Any()); - Debug.Assert(!isGeneratedCode || !_shouldSkipAnalysisOnGeneratedCode(analyzer)); - Debug.Assert(!IsAnalyzerSuppressedForTree(analyzer, model.SyntaxTree, cancellationToken)); + Debug.Assert(!executionData.IsGeneratedCode || !_shouldSkipAnalysisOnGeneratedCode(executionData.Analyzer)); + Debug.Assert(!IsAnalyzerSuppressedForTree(executionData.Analyzer, executionData.SemanticModel.SyntaxTree, cancellationToken)); foreach (var operation in operationsToAnalyze) { @@ -1104,7 +1148,7 @@ private void ExecuteOperationActions( if (operationActionsByKind.TryGetValue(operation.Kind, out var actionsForKind)) { RoslynDebug.Assert(!actionsForKind.IsEmpty, $"Unexpected empty action collection in {nameof(operationActionsByKind)}"); - if (ShouldExecuteOperation(operation, analyzer, cancellationToken)) + if (ShouldExecuteOperation(operation, executionData.Analyzer, cancellationToken)) { // If analyzer hasn't registered any OperationBlockStart or SymbolStart actions, then update // the filter span for local diagnostics to be the callback operation's full span. @@ -1115,7 +1159,7 @@ private void ExecuteOperationActions( foreach (var action in actionsForKind) { - ExecuteOperationAction(action, operation, containingSymbol, model, diagReporter.AddDiagnosticAction, isSupportedDiagnostic, filterSpan, isGeneratedCode, cancellationToken); + ExecuteOperationAction(action, operation, executionData, diagReporter.AddDiagnosticAction, isSupportedDiagnostic, cancellationToken); } } } @@ -1144,6 +1188,8 @@ internal static bool CanHaveExecutableCodeBlock(ISymbol symbol) internal void ExecuteAndCatchIfThrows(DiagnosticAnalyzer analyzer, Action analyze, TArg argument, AnalysisContextInfo? contextInfo, CancellationToken cancellationToken) { + cancellationToken.ThrowIfCancellationRequested(); + SharedStopwatch timer = default; if (_analyzerExecutionTimeMap != null) { @@ -1207,7 +1253,7 @@ internal static bool HandleAnalyzerException( Func? analyzerExceptionFilter, CancellationToken cancellationToken) { - if (!ExceptionFilter(exception, analyzerExceptionFilter, cancellationToken)) + if (!exceptionFilter(exception, analyzerExceptionFilter, cancellationToken)) { return false; } @@ -1225,7 +1271,7 @@ internal static bool HandleAnalyzerException( return true; - static bool ExceptionFilter(Exception ex, Func? analyzerExceptionFilter, CancellationToken cancellationToken) + static bool exceptionFilter(Exception ex, Func? analyzerExceptionFilter, CancellationToken cancellationToken) { if ((ex as OperationCanceledException)?.CancellationToken == cancellationToken) { diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerFileReference.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerFileReference.cs index fbbd8f4553645..2f1eafe06b16d 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerFileReference.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerFileReference.cs @@ -106,6 +106,9 @@ public bool Equals(AnalyzerReference? other) public override int GetHashCode() => Hash.Combine(RuntimeHelpers.GetHashCode(_assemblyLoader), FullPath.GetHashCode()); + public override string ToString() + => $"{nameof(AnalyzerFileReference)}({nameof(FullPath)} = {FullPath})"; + public override ImmutableArray GetAnalyzersForAllLanguages() { // This API returns duplicates of analyzers that support multiple languages. diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/CachingSemanticModelProvider.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/CachingSemanticModelProvider.cs index 573045bbf5733..4177c37847907 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/CachingSemanticModelProvider.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/CachingSemanticModelProvider.cs @@ -23,22 +23,26 @@ namespace Microsoft.CodeAnalysis.Diagnostics /// internal sealed class CachingSemanticModelProvider : SemanticModelProvider { + // Provide access to CachingSemanticModelProvider through a singleton. The inner CWT is static + // to avoid leak potential -- see https://github.com/dotnet/runtime/issues/12255. + // CachingSemanticModelProvider.s_providerCache -> PerCompilationProvider -> Compilation -> CachingSemanticModelProvider + public static CachingSemanticModelProvider Instance { get; } = new CachingSemanticModelProvider(); + private static readonly ConditionalWeakTable.CreateValueCallback s_createProviderCallback = new ConditionalWeakTable.CreateValueCallback(compilation => new PerCompilationProvider(compilation)); - private readonly ConditionalWeakTable _providerCache; + private static readonly ConditionalWeakTable s_providerCache = new ConditionalWeakTable(); - public CachingSemanticModelProvider() + private CachingSemanticModelProvider() { - _providerCache = new ConditionalWeakTable(); } public override SemanticModel GetSemanticModel(SyntaxTree tree, Compilation compilation, SemanticModelOptions options = default) - => _providerCache.GetValue(compilation, s_createProviderCallback).GetSemanticModel(tree, options); + => s_providerCache.GetValue(compilation, s_createProviderCallback).GetSemanticModel(tree, options); internal void ClearCache(SyntaxTree tree, Compilation compilation) { - if (_providerCache.TryGetValue(compilation, out var provider)) + if (s_providerCache.TryGetValue(compilation, out var provider)) { provider.ClearCachedSemanticModel(tree); } @@ -46,7 +50,7 @@ internal void ClearCache(SyntaxTree tree, Compilation compilation) internal void ClearCache(Compilation compilation) { - _providerCache.Remove(compilation); + s_providerCache.Remove(compilation); } private sealed class PerCompilationProvider diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs index 45e7418d5887a..67c47debe0336 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs @@ -97,7 +97,7 @@ public CompilationWithAnalyzers(Compilation compilation, ImmutableArray()); _compilation = compilation; _analyzers = analyzers; @@ -723,7 +723,7 @@ private async Task ComputeAnalyzerDiagnosticsAsync(AnalysisScope? analysisScope, // subsequently discard this compilation. var compilation = analysisScope.IsSingleFileAnalysisForCompilerAnalyzer ? _compilation - : _compilation.WithSemanticModelProvider(new CachingSemanticModelProvider()).WithEventQueue(new AsyncQueue()); + : _compilation.WithSemanticModelProvider(CachingSemanticModelProvider.Instance).WithEventQueue(new AsyncQueue()); // Get the analyzer driver to execute analysis. using var driver = await CreateAndInitializeDriverAsync(compilation, _analysisOptions, analysisScope, _suppressors, categorizeDiagnostics: true, cancellationToken).ConfigureAwait(false); @@ -1188,7 +1188,7 @@ private static IEnumerable GetEffectiveDiagnosticsImpl(ImmutableArra if (compilation.SemanticModelProvider == null) { - compilation = compilation.WithSemanticModelProvider(new CachingSemanticModelProvider()); + compilation = compilation.WithSemanticModelProvider(CachingSemanticModelProvider.Instance); } var suppressMessageState = new SuppressMessageAttributeState(compilation); diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/DefaultAnalyzerAssemblyLoader.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/DefaultAnalyzerAssemblyLoader.cs deleted file mode 100644 index 40f7afa19d91f..0000000000000 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/DefaultAnalyzerAssemblyLoader.cs +++ /dev/null @@ -1,80 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Runtime.InteropServices; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis -{ - internal sealed class DefaultAnalyzerAssemblyLoader : AnalyzerAssemblyLoader - { - internal DefaultAnalyzerAssemblyLoader() - : base([]) - { - } - - internal DefaultAnalyzerAssemblyLoader(ImmutableArray externalResolvers) - : base(externalResolvers) - { - } - -#if NET - - internal DefaultAnalyzerAssemblyLoader(System.Runtime.Loader.AssemblyLoadContext? compilerLoadContext = null, AnalyzerLoadOption loadOption = AnalyzerLoadOption.LoadFromDisk, ImmutableArray? externalResolvers = null) - : base(compilerLoadContext, loadOption, externalResolvers ?? []) - { - } - -#endif - - /// - /// The default implementation is to simply load in place. - /// - protected override string PreparePathToLoad(string fullPath) => fullPath; - - /// - /// The default implementation is to simply load in place. - /// - protected override string PrepareSatelliteAssemblyToLoad(string assemblyFilePath, string cultureName) - { - var directory = Path.GetDirectoryName(assemblyFilePath)!; - var fileName = GetSatelliteFileName(Path.GetFileName(assemblyFilePath)); - - return Path.Combine(directory, cultureName, fileName); - } - - /// - /// Return an which does not lock assemblies on disk that is - /// most appropriate for the current platform. - /// - /// A shadow copy path will be created on Windows and this value - /// will be the base directory where shadow copy assemblies are stored. - internal static IAnalyzerAssemblyLoaderInternal CreateNonLockingLoader(string windowsShadowPath, ImmutableArray? externalResolvers = null) - { -#if NET - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - return new DefaultAnalyzerAssemblyLoader(loadOption: AnalyzerLoadOption.LoadFromStream, externalResolvers: externalResolvers); - } -#endif - - // The shadow copy analyzer should only be created on Windows. To create on Linux we cannot use - // GetTempPath as it's not per-user. Generally there is no need as LoadFromStream achieves the same - // effect - if (!Path.IsPathRooted(windowsShadowPath)) - { - throw new ArgumentException("Must be a full path.", nameof(windowsShadowPath)); - } - - return new ShadowCopyAnalyzerAssemblyLoader(windowsShadowPath, externalResolvers); - } - } -} diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/DiagnosticStartAnalysisScope.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/DiagnosticStartAnalysisScope.cs index fb6dcccfdfd45..ba5874c3d1d0a 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/DiagnosticStartAnalysisScope.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/DiagnosticStartAnalysisScope.cs @@ -820,14 +820,20 @@ internal readonly ImmutableArray return _codeBlockStartActions.OfType>().ToImmutableArray(); } - internal readonly ImmutableArray> GetSyntaxNodeActions() where TLanguageKindEnum : struct + internal readonly void AddSyntaxNodeActions( + ArrayBuilder> builder) where TLanguageKindEnum : struct { - return _syntaxNodeActions.OfType>().ToImmutableArray(); + foreach (var action in _syntaxNodeActions) + { + if (action is SyntaxNodeAnalyzerAction stronglyTypedAction) + builder.Add(stronglyTypedAction); + } } - internal readonly ImmutableArray> GetSyntaxNodeActions(DiagnosticAnalyzer analyzer) where TLanguageKindEnum : struct + internal readonly void AddSyntaxNodeActions( + DiagnosticAnalyzer analyzer, + ArrayBuilder> builder) where TLanguageKindEnum : struct { - var builder = ArrayBuilder>.GetInstance(); foreach (var action in _syntaxNodeActions) { if (action.Analyzer == analyzer && @@ -836,8 +842,6 @@ internal readonly ImmutableArray> Ge builder.Add(syntaxNodeAction); } } - - return builder.ToImmutableAndFree(); } internal readonly ImmutableArray OperationBlockActions diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/IAnalyzerAssemblyResolver.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/IAnalyzerAssemblyResolver.cs index 3041e458fa2c9..3f3228b8655a4 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/IAnalyzerAssemblyResolver.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/IAnalyzerAssemblyResolver.cs @@ -2,21 +2,39 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#if NET + using System.Reflection; +using System.Runtime.Loader; namespace Microsoft.CodeAnalysis { /// - /// Allows a host to override how assembly resolution is performed by the . + /// This interface allows hosts to control exactly how a given is resolved to an + /// instance. This is useful for hosts that need to load assemblies in a custom way like + /// Razor or stream based loading. /// internal interface IAnalyzerAssemblyResolver { /// - /// Attempts to resolve an assembly by name. + /// Resolve an for the given parameters. /// - /// The assembly to resolve. - /// The root directory the calling is configured with. - /// The resolved assembly, or - Assembly? ResolveAssembly(AssemblyName assemblyName, string rootDirectory); + /// + /// The will partition analyzers into the directories they live + /// in and will create a separate for each directory. That instance + /// and the directory name represent and . + /// + /// This is invoked as part of . Exceptions in + /// the implementation of this interface will escape from that method and be registered as the result + /// of load. + /// + /// The instance that is performing the load + /// The name of the assembly to be loaded + /// The for the + /// The resolved directory where the assembly is being loaded from + /// The resolved or null if it's not handled by this instance + Assembly? Resolve(AnalyzerAssemblyLoader loader, AssemblyName assemblyName, AssemblyLoadContext directoryContext, string directory); } } + +#endif diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/IAnalyzerPathResolver.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/IAnalyzerPathResolver.cs new file mode 100644 index 0000000000000..513b7fd7d20eb --- /dev/null +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/IAnalyzerPathResolver.cs @@ -0,0 +1,61 @@ + +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis +{ + /// + /// This interface gives the host the ability to control the actaul path used to load an analyzer into the + /// compiler. + /// + /// Instances of these types are considered in the order they are added to the . + /// The first instance to return true from will be considered to + /// be the owner of that path. From then on only that instance will be called for the other methods on this + /// interface. + /// + /// For example in a typical session: the will return true for + /// analyzer paths under C:\Program Files\dotnet. That means the , + /// which appears last on Windows, will never see these paths and hence won't shadow copy them. + /// + /// + /// Instances of this type will be accessed from multiple threads. All method implementations are expected + /// to be idempotent. + /// + internal interface IAnalyzerPathResolver + { + /// + /// Is this path handled by this instance? + /// + bool IsAnalyzerPathHandled(string analyzerPath); + + /// + /// This method is used to allow compiler hosts to intercept an analyzer path and redirect it to a + /// a different location. + /// + /// + /// This will only be called for paths that return true from . + /// + string GetResolvedAnalyzerPath(string originalAnalyzerPath); + + /// + /// This method is used to allow compiler hosts to intercept an analyzer satellite path and redirect it to a + /// a different location. A null return here means there is no available satellite assembly for that + /// culture. + /// + /// + /// This will only be called for paths that return true from . + /// + string? GetResolvedSatellitePath(string originalAnalyzerPath, CultureInfo cultureInfo); + } +} diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/ProgramFilesAnalyzerPathResolver.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/ProgramFilesAnalyzerPathResolver.cs new file mode 100644 index 0000000000000..fa04907b9fdb7 --- /dev/null +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/ProgramFilesAnalyzerPathResolver.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.Diagnostics; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Runtime.Versioning; +using System.Text; +using System.Threading.Tasks; + +namespace Microsoft.CodeAnalysis; + +/// +/// This implementation is used to handle analyzers that +/// exist in global install locations on Windows. These locations do not need to be shadow +/// copied because they are read-only and are not expected to be updated. Putting this resolver +/// before shadow copy will let them load in place. +/// +#if NET +[SupportedOSPlatform("windows")] +#endif +internal sealed class ProgramFilesAnalyzerPathResolver : IAnalyzerPathResolver +{ + internal static readonly IAnalyzerPathResolver Instance = new ProgramFilesAnalyzerPathResolver(); + + private string DotNetPath { get; } + + private ProgramFilesAnalyzerPathResolver() + { + var programFilesPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles); + DotNetPath = Path.Combine(programFilesPath, "dotnet"); + } + + public bool IsAnalyzerPathHandled(string analyzerPath) + => analyzerPath.StartsWith(DotNetPath, StringComparison.OrdinalIgnoreCase); + + public string GetResolvedAnalyzerPath(string originalAnalyzerPath) + { + Debug.Assert(IsAnalyzerPathHandled(originalAnalyzerPath)); + return originalAnalyzerPath; + } + + public string? GetResolvedSatellitePath(string originalAnalyzerPath, CultureInfo cultureInfo) + { + Debug.Assert(IsAnalyzerPathHandled(originalAnalyzerPath)); + return AnalyzerAssemblyLoader.GetSatelliteAssemblyPath(originalAnalyzerPath, cultureInfo); + } +} diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/ShadowCopyAnalyzerAssemblyLoader.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/ShadowCopyAnalyzerAssemblyLoader.cs index 1df2f9c6b5cf7..cbea7e7bfe02e 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/ShadowCopyAnalyzerAssemblyLoader.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/ShadowCopyAnalyzerAssemblyLoader.cs @@ -11,73 +11,93 @@ using Roslyn.Utilities; using System.Collections.Immutable; using System.Reflection; - -#if NET -using System.Runtime.Loader; -#endif +using System.Globalization; namespace Microsoft.CodeAnalysis { - internal sealed class ShadowCopyAnalyzerAssemblyLoader : AnalyzerAssemblyLoader + internal sealed class ShadowCopyAnalyzerPathResolver : IAnalyzerPathResolver { /// /// The base directory for shadow copies. Each instance of - /// gets its own + /// gets its own /// subdirectory under this directory. This is also the starting point /// for scavenge operations. /// - private readonly string _baseDirectory; + internal string BaseDirectory { get; } - internal readonly Task DeleteLeftoverDirectoriesTask; + internal string ShadowDirectory { get; } /// - /// The directory where this instance of - /// will shadow-copy assemblies, and the mutex created to mark that the owner of it is still active. + /// As long as this mutex is alive, other instances of this type will not try to clean + /// up the shadow directory. /// - private readonly Lazy<(string directory, Mutex)> _shadowCopyDirectoryAndMutex; + private Mutex Mutex { get; } - private readonly ConcurrentDictionary> _mvidPathMap = new ConcurrentDictionary>(); - private readonly ConcurrentDictionary<(Guid, string), Task> _mvidSatelliteAssemblyPathMap = new ConcurrentDictionary<(Guid, string), Task>(); + internal Task DeleteLeftoverDirectoriesTask { get; } - internal string BaseDirectory => _baseDirectory; + /// + /// This is a counter that is incremented each time a new shadow sub directory is created to ensure they + /// have unique names. + /// + private int _directoryCount; - internal int CopyCount => _mvidPathMap.Count; + /// + /// This is a map from the original directory name to the numbered directory name it + /// occupies in the shadow directory. + /// + private ConcurrentDictionary OriginalDirectoryMap { get; } = new(AnalyzerAssemblyLoader.OriginalPathComparer); -#if NET - public ShadowCopyAnalyzerAssemblyLoader(string baseDirectory, ImmutableArray? externalResolvers = null) - : this(null, baseDirectory, externalResolvers) - { - } + /// + /// This interface can be called from multiple threads for the same original assembly path. This + /// is a map between the original path and the Task that completes when the shadow copy for that + /// original path completes. + /// + private ConcurrentDictionary CopyMap { get; } = new(AnalyzerAssemblyLoader.OriginalPathComparer); + + /// + /// This is the number of shadow copies that have occurred in this instance. + /// + /// + /// This is used for testing, it should not be used for any other purpose. + /// + internal int CopyCount => CopyMap.Count; - public ShadowCopyAnalyzerAssemblyLoader(AssemblyLoadContext? compilerLoadContext, string baseDirectory, ImmutableArray? externalResolvers = null) - : base(compilerLoadContext, AnalyzerLoadOption.LoadFromDisk, externalResolvers ?? []) -#else - public ShadowCopyAnalyzerAssemblyLoader(string baseDirectory, ImmutableArray? externalResolvers = null) - : base(externalResolvers ?? []) -#endif + public ShadowCopyAnalyzerPathResolver(string baseDirectory) { if (baseDirectory is null) { throw new ArgumentNullException(nameof(baseDirectory)); } - _baseDirectory = baseDirectory; - _shadowCopyDirectoryAndMutex = new Lazy<(string directory, Mutex)>( - () => CreateUniqueDirectoryForProcess(), LazyThreadSafetyMode.ExecutionAndPublication); + // The shadow copy analyzer should only be created on Windows. To create on Linux we cannot use + // GetTempPath as it's not per-user. Generally there is no need as LoadFromStream achieves the same + // effect + if (!Path.IsPathRooted(baseDirectory)) + { + throw new ArgumentException($"Must be a full path: {baseDirectory}", nameof(baseDirectory)); + } + + BaseDirectory = baseDirectory; + var shadowDirectoryName = Guid.NewGuid().ToString("N").ToLowerInvariant(); + // The directory is deliberately _not_ created at this point. It will only be created when the first + // request comes in. This avoids creating unnecessary directories when no analyzers are loaded + // via the shadow layer. + ShadowDirectory = Path.Combine(BaseDirectory, shadowDirectoryName); + Mutex = new Mutex(initiallyOwned: false, name: shadowDirectoryName); DeleteLeftoverDirectoriesTask = Task.Run(DeleteLeftoverDirectories); } private void DeleteLeftoverDirectories() { // Avoid first chance exception - if (!Directory.Exists(_baseDirectory)) + if (!Directory.Exists(BaseDirectory)) return; IEnumerable subDirectories; try { - subDirectories = Directory.EnumerateDirectories(_baseDirectory); + subDirectories = Directory.EnumerateDirectories(BaseDirectory); } catch (DirectoryNotFoundException) { @@ -129,64 +149,64 @@ private void DeleteLeftoverDirectories() } } - protected override string PreparePathToLoad(string originalAnalyzerPath) - { - var mvid = AssemblyUtilities.ReadMvid(originalAnalyzerPath); - - return PrepareLoad(_mvidPathMap, mvid, copyAnalyzerContents); - - string copyAnalyzerContents() - { - var analyzerFileName = Path.GetFileName(originalAnalyzerPath); - var shadowDirectory = Path.Combine(_shadowCopyDirectoryAndMutex.Value.directory, mvid.ToString()); - var shadowAnalyzerPath = Path.Combine(shadowDirectory, analyzerFileName); - CopyFile(originalAnalyzerPath, shadowAnalyzerPath); + public bool IsAnalyzerPathHandled(string analyzerFilePath) => true; - return shadowAnalyzerPath; - } + public string GetResolvedAnalyzerPath(string originalAnalyzerPath) + { + var analyzerShadowDir = GetAnalyzerShadowDirectory(originalAnalyzerPath); + var analyzerShadowPath = Path.Combine(analyzerShadowDir, Path.GetFileName(originalAnalyzerPath)); + ShadowCopyFile(originalAnalyzerPath, analyzerShadowPath); + return analyzerShadowPath; } - protected override string PrepareSatelliteAssemblyToLoad(string originalAnalyzerPath, string cultureName) + public string? GetResolvedSatellitePath(string originalAnalyzerPath, CultureInfo cultureInfo) { - var mvid = AssemblyUtilities.ReadMvid(originalAnalyzerPath); - - return PrepareLoad(_mvidSatelliteAssemblyPathMap, (mvid, cultureName), copyAnalyzerContents); - - string copyAnalyzerContents() + var satelliteFilePath = AnalyzerAssemblyLoader.GetSatelliteAssemblyPath(originalAnalyzerPath, cultureInfo); + if (satelliteFilePath is null) { - var analyzerFileName = Path.GetFileName(originalAnalyzerPath); - var shadowDirectory = Path.Combine(_shadowCopyDirectoryAndMutex.Value.directory, mvid.ToString()); - var shadowAnalyzerPath = Path.Combine(shadowDirectory, analyzerFileName); - - var originalDirectory = Path.GetDirectoryName(originalAnalyzerPath)!; - var satelliteFileName = GetSatelliteFileName(analyzerFileName); + return null; + } - var originalSatellitePath = Path.Combine(originalDirectory, cultureName, satelliteFileName); - var shadowSatellitePath = Path.Combine(shadowDirectory, cultureName, satelliteFileName); - CopyFile(originalSatellitePath, shadowSatellitePath); + var analyzerShadowDir = GetAnalyzerShadowDirectory(originalAnalyzerPath); + var satelliteFileName = Path.GetFileName(satelliteFilePath); + var satelliteDirectoryName = Path.GetFileName(Path.GetDirectoryName(satelliteFilePath)); + var shadowSatellitePath = Path.Combine(analyzerShadowDir, satelliteDirectoryName!, satelliteFileName); + ShadowCopyFile(satelliteFilePath, shadowSatellitePath); + return shadowSatellitePath; + } - return shadowSatellitePath; - } + /// + /// Get the shadow directory for the given original analyzer file path. + /// + private string GetAnalyzerShadowDirectory(string analyzerFilePath) + { + var originalDirName = Path.GetDirectoryName(analyzerFilePath)!; + var shadowDirName = OriginalDirectoryMap.GetOrAdd(originalDirName, _ => Interlocked.Increment(ref _directoryCount)).ToString(); + return Path.Combine(ShadowDirectory, shadowDirName); } - private static string PrepareLoad(ConcurrentDictionary> mvidPathMap, TKey mvidKey, Func copyContents) - where TKey : notnull + /// + /// This type has to account for multiple threads calling into the various resolver APIs. To avoid two threads + /// writing at the same time this method is used to ensure only one thread _wins_ and both can wait for + /// that thread to complete the copy. + /// + private void ShadowCopyFile(string originalFilePath, string shadowCopyPath) { - if (mvidPathMap.TryGetValue(mvidKey, out Task? copyTask)) + if (CopyMap.TryGetValue(originalFilePath, out var copyTask)) { - return copyTask.Result; + copyTask.Wait(); + return; } - var tcs = new TaskCompletionSource(); - var task = mvidPathMap.GetOrAdd(mvidKey, tcs.Task); + var tcs = new TaskCompletionSource(); + var task = CopyMap.GetOrAdd(originalFilePath, tcs.Task); if (object.ReferenceEquals(task, tcs.Task)) { // This thread won and we need to do the copy. try { - var shadowAnalyzerPath = copyContents(); - tcs.SetResult(shadowAnalyzerPath); - return shadowAnalyzerPath; + copyFile(originalFilePath, shadowCopyPath); + tcs.SetResult(null); } catch (Exception ex) { @@ -197,21 +217,27 @@ private static string PrepareLoad(ConcurrentDictionary> else { // This thread lost and we need to wait for the winner to finish the copy. - return task.Result; + task.Wait(); } - } - private static void CopyFile(string originalPath, string shadowCopyPath) - { - var directory = Path.GetDirectoryName(shadowCopyPath); - if (directory is null) + static void copyFile(string originalPath, string shadowCopyPath) { - throw new ArgumentException($"Shadow copy path '{shadowCopyPath}' must not be the root directory"); - } + var directory = Path.GetDirectoryName(shadowCopyPath); + if (directory is null) + { + throw new ArgumentException($"Shadow copy path '{shadowCopyPath}' must not be the root directory"); + } + + _ = Directory.CreateDirectory(directory); - _ = Directory.CreateDirectory(directory); - File.Copy(originalPath, shadowCopyPath); - ClearReadOnlyFlagOnFile(new FileInfo(shadowCopyPath)); + // The shadow copy should only copy files that exist. For files that don't exist, this best + // emulates not having the shadow copy layer + if (File.Exists(originalPath)) + { + File.Copy(originalPath, shadowCopyPath); + ClearReadOnlyFlagOnFile(new FileInfo(shadowCopyPath)); + } + } } private static void ClearReadOnlyFlagOnFiles(string directoryPath) @@ -239,16 +265,5 @@ private static void ClearReadOnlyFlagOnFile(FileInfo fileInfo) } } - private (string directory, Mutex mutex) CreateUniqueDirectoryForProcess() - { - string guid = Guid.NewGuid().ToString("N").ToLowerInvariant(); - string directory = Path.Combine(_baseDirectory, guid); - - var mutex = new Mutex(initiallyOwned: false, name: guid); - - Directory.CreateDirectory(directory); - - return (directory, mutex); - } } } diff --git a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs index 1177f7add1a6d..44b8c70265965 100644 --- a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs +++ b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs @@ -906,7 +906,7 @@ private SynthesizedDefinitions GetOrAddSynthesizedDefinitions(TNamedTypeSymbol c return _synthesizedTypeMembers.GetOrAdd(container, _ => new SynthesizedDefinitions()); } - public void AddSynthesizedDefinition(TNamedTypeSymbol container, Cci.IMethodDefinition method) + public virtual void AddSynthesizedDefinition(TNamedTypeSymbol container, Cci.IMethodDefinition method) { Debug.Assert(method != null); @@ -919,7 +919,7 @@ public void AddSynthesizedDefinition(TNamedTypeSymbol container, Cci.IMethodDefi defs.Methods.Enqueue(method); } - public void AddSynthesizedDefinition(TNamedTypeSymbol container, Cci.IPropertyDefinition property) + public virtual void AddSynthesizedDefinition(TNamedTypeSymbol container, Cci.IPropertyDefinition property) { Debug.Assert(property != null); @@ -932,7 +932,7 @@ public void AddSynthesizedDefinition(TNamedTypeSymbol container, Cci.IPropertyDe defs.Properties.Enqueue(property); } - public void AddSynthesizedDefinition(TNamedTypeSymbol container, Cci.IFieldDefinition field) + public virtual void AddSynthesizedDefinition(TNamedTypeSymbol container, Cci.IFieldDefinition field) { Debug.Assert(field != null); @@ -945,7 +945,7 @@ public void AddSynthesizedDefinition(TNamedTypeSymbol container, Cci.IFieldDefin defs.Fields.Enqueue(field); } - public void AddSynthesizedDefinition(TNamedTypeSymbol container, Cci.INestedTypeDefinition nestedType) + public virtual void AddSynthesizedDefinition(TNamedTypeSymbol container, Cci.INestedTypeDefinition nestedType) { Debug.Assert(nestedType != null); diff --git a/src/Compilers/Core/Portable/Emit/EmitOptions.cs b/src/Compilers/Core/Portable/Emit/EmitOptions.cs index 07e92a2f3371e..fefce27c268cc 100644 --- a/src/Compilers/Core/Portable/Emit/EmitOptions.cs +++ b/src/Compilers/Core/Portable/Emit/EmitOptions.cs @@ -120,6 +120,8 @@ public sealed class EmitOptions : IEquatable /// private bool _testOnly_AllowLocalStateTracing; + internal Func, string>? TestOnly_DataToHexViaXxHash128 { get; init; } + // 1.2 BACKCOMPAT OVERLOAD -- DO NOT TOUCH public EmitOptions( bool metadataOnly, diff --git a/src/Compilers/Core/Portable/Emit/ErrorType.cs b/src/Compilers/Core/Portable/Emit/ErrorType.cs index f7d2ef047a65e..1c844f2f4484b 100644 --- a/src/Compilers/Core/Portable/Emit/ErrorType.cs +++ b/src/Compilers/Core/Portable/Emit/ErrorType.cs @@ -193,13 +193,13 @@ string Cci.INamedEntity.Name public sealed override bool Equals(object obj) { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } public sealed override int GetHashCode() { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } /// diff --git a/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedMember.cs b/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedMember.cs index f2ec63e12cd4f..114247c93730c 100644 --- a/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedMember.cs +++ b/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedMember.cs @@ -122,13 +122,13 @@ Cci.IDefinition Cci.IReference.AsDefinition(EmitContext context) public sealed override bool Equals(object obj) { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } public sealed override int GetHashCode() { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } } } diff --git a/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedParameter.cs b/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedParameter.cs index b8c27026b7500..0f751bbb4cc5e 100644 --- a/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedParameter.cs +++ b/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedParameter.cs @@ -274,13 +274,13 @@ public override string ToString() public sealed override bool Equals(object obj) { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } public sealed override int GetHashCode() { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } } } diff --git a/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedType.cs b/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedType.cs index d885927dfdd45..ea19ac97129ee 100644 --- a/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedType.cs +++ b/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedType.cs @@ -718,13 +718,13 @@ public override string ToString() public sealed override bool Equals(object obj) { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } public sealed override int GetHashCode() { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } } } diff --git a/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedTypeParameter.cs b/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedTypeParameter.cs index 1898e994606ea..b7d19bd66f3cf 100644 --- a/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedTypeParameter.cs +++ b/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedTypeParameter.cs @@ -239,13 +239,13 @@ Cci.IMethodReference Cci.IGenericMethodParameterReference.DefiningMethod public sealed override bool Equals(object obj) { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } public sealed override int GetHashCode() { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } } } diff --git a/src/Compilers/Core/Portable/Emit/NoPia/VtblGap.cs b/src/Compilers/Core/Portable/Emit/NoPia/VtblGap.cs index 696403f6dca06..12fe6d43652e7 100644 --- a/src/Compilers/Core/Portable/Emit/NoPia/VtblGap.cs +++ b/src/Compilers/Core/Portable/Emit/NoPia/VtblGap.cs @@ -259,13 +259,13 @@ Cci.ITypeReference Cci.ISignature.GetType(EmitContext context) public sealed override bool Equals(object obj) { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } public sealed override int GetHashCode() { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } } } diff --git a/src/Compilers/Core/Portable/FileSystem/FileUtilities.cs b/src/Compilers/Core/Portable/FileSystem/FileUtilities.cs index 66cd96adace05..be2435b56dfd5 100644 --- a/src/Compilers/Core/Portable/FileSystem/FileUtilities.cs +++ b/src/Compilers/Core/Portable/FileSystem/FileUtilities.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.IO; using System.Threading.Tasks; +using Microsoft.CodeAnalysis; namespace Roslyn.Utilities { diff --git a/src/Compilers/Core/Portable/InternalUtilities/EmptyComparer.cs b/src/Compilers/Core/Portable/InternalUtilities/EmptyComparer.cs index 71e3a791ee95b..0f61efb45d893 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/EmptyComparer.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/EmptyComparer.cs @@ -3,8 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Diagnostics; -using System.Runtime.CompilerServices; +using Microsoft.CodeAnalysis; namespace Roslyn.Utilities { diff --git a/src/Compilers/Core/Portable/InternalUtilities/ExceptionExtensions.cs b/src/Compilers/Core/Portable/InternalUtilities/ExceptionExtensions.cs new file mode 100644 index 0000000000000..92de8e4d05892 --- /dev/null +++ b/src/Compilers/Core/Portable/InternalUtilities/ExceptionExtensions.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.Threading; + +namespace Microsoft.CodeAnalysis; + +internal static class ExceptionExtensions +{ + /// + /// Determine if an exception was an , and that the provided token caused the cancellation. + /// + /// The exception to test. + /// Checked to see if the provided token was cancelled. + /// if the exception was an and the token was canceled. + internal static bool IsCurrentOperationBeingCancelled(this Exception exception, CancellationToken cancellationToken) + => exception is OperationCanceledException && cancellationToken.IsCancellationRequested; +} diff --git a/src/Compilers/Core/Portable/InternalUtilities/FatalError.cs b/src/Compilers/Core/Portable/InternalUtilities/FatalError.cs index a620bf64f1de7..49f1a5854a2e2 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/FatalError.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/FatalError.cs @@ -4,11 +4,9 @@ using System; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.CompilerServices; using System.Threading; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ErrorReporting { @@ -231,7 +229,7 @@ public static bool ReportAndCatchUnlessCanceled(Exception exception, Cancellatio private static readonly object s_reportedMarker = Guid.NewGuid(); // Do not allow this method to be inlined. That way when we have a dump we can see this frame in the stack and - // can examine things like s_reportedExceptionMessage. Without this, it's a lot tricker as FatalError is linked + // can examine things like s_reportedExceptionMessage. Without this, it's a lot trickier as FatalError is linked // into many assemblies and finding the right type can be much harder. [MethodImpl(MethodImplOptions.NoInlining)] private static void Report(Exception exception, ErrorSeverity severity = ErrorSeverity.Uncategorized, bool forceDump = false) diff --git a/src/Compilers/Core/Portable/InternalUtilities/ReaderWriterLockSlimExtensions.cs b/src/Compilers/Core/Portable/InternalUtilities/ReaderWriterLockSlimExtensions.cs index d75c522a02f6c..0516e0d67c7fc 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/ReaderWriterLockSlimExtensions.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/ReaderWriterLockSlimExtensions.cs @@ -4,6 +4,7 @@ using System; using System.Threading; +using Microsoft.CodeAnalysis; namespace Roslyn.Utilities { diff --git a/src/Compilers/Core/Portable/InternalUtilities/RoslynParallel.cs b/src/Compilers/Core/Portable/InternalUtilities/RoslynParallel.cs index 58ea9a75a47f7..b0d035b8f5ce8 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/RoslynParallel.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/RoslynParallel.cs @@ -5,6 +5,7 @@ using System; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.ErrorReporting; namespace Roslyn.Utilities diff --git a/src/Compilers/Core/Portable/InternalUtilities/SemaphoreSlimExtensions.cs b/src/Compilers/Core/Portable/InternalUtilities/SemaphoreSlimExtensions.cs index e8e057a8b950d..27fa928fab65c 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/SemaphoreSlimExtensions.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/SemaphoreSlimExtensions.cs @@ -5,6 +5,7 @@ using System; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis; namespace Roslyn.Utilities { diff --git a/src/Compilers/Core/Portable/InternalUtilities/SingleInitNullable.cs b/src/Compilers/Core/Portable/InternalUtilities/SingleInitNullable.cs index 1e4633cee50bb..24299ce099285 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/SingleInitNullable.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/SingleInitNullable.cs @@ -4,6 +4,7 @@ using System; using System.Threading; +using Microsoft.CodeAnalysis; namespace Roslyn.Utilities; diff --git a/src/Compilers/Core/Portable/InternalUtilities/VoidResult.cs b/src/Compilers/Core/Portable/InternalUtilities/VoidResult.cs deleted file mode 100644 index ea481f9017836..0000000000000 --- a/src/Compilers/Core/Portable/InternalUtilities/VoidResult.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 System; - -namespace Roslyn.Utilities -{ - /// - /// Explicitly indicates result is void - /// - internal readonly struct VoidResult : IEquatable - { - public override bool Equals(object? obj) - => obj is VoidResult; - - public override int GetHashCode() - => 0; - - public bool Equals(VoidResult other) - => true; - } -} diff --git a/src/Compilers/Core/Portable/InternalUtilities/YieldAwaitableExtensions.cs b/src/Compilers/Core/Portable/InternalUtilities/YieldAwaitableExtensions.cs deleted file mode 100644 index dd62cb31b5d23..0000000000000 --- a/src/Compilers/Core/Portable/InternalUtilities/YieldAwaitableExtensions.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Runtime.CompilerServices; -using System.Threading.Tasks; - -namespace Roslyn.Utilities -{ - internal static class YieldAwaitableExtensions - { - /// - /// Implements ConfigureAwait(bool) for . The resulting behavior in asynchronous code - /// is the same as one would expect for . - /// - /// The awaitable provided by . - /// - /// An object used to await this yield. - public static ConfiguredYieldAwaitable ConfigureAwait(this YieldAwaitable awaitable, bool continueOnCapturedContext) - { - return new ConfiguredYieldAwaitable(awaitable, continueOnCapturedContext); - } - } -} diff --git a/src/Compilers/Core/Portable/MetadataReader/MetadataHelpers.cs b/src/Compilers/Core/Portable/MetadataReader/MetadataHelpers.cs index 29c428581833d..74cec5acf2eec 100644 --- a/src/Compilers/Core/Portable/MetadataReader/MetadataHelpers.cs +++ b/src/Compilers/Core/Portable/MetadataReader/MetadataHelpers.cs @@ -2,12 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using System.Reflection.Metadata; @@ -39,24 +38,24 @@ internal static class MetadataHelpers internal readonly struct AssemblyQualifiedTypeName { - internal readonly string TopLevelType; - internal readonly string[] NestedTypes; - internal readonly AssemblyQualifiedTypeName[] TypeArguments; + internal readonly string? TopLevelType; + internal readonly string[]? NestedTypes; + internal readonly AssemblyQualifiedTypeName[]? TypeArguments; internal readonly int PointerCount; /// /// Rank equal 0 is used to denote an SzArray, rank equal 1 denotes multi-dimensional array of rank 1. /// - internal readonly int[] ArrayRanks; - internal readonly string AssemblyName; + internal readonly int[]? ArrayRanks; + internal readonly string? AssemblyName; internal AssemblyQualifiedTypeName( - string topLevelType, - string[] nestedTypes, - AssemblyQualifiedTypeName[] typeArguments, + string? topLevelType, + string[]? nestedTypes, + AssemblyQualifiedTypeName[]? typeArguments, int pointerCount, - int[] arrayRanks, - string assemblyName) + int[]? arrayRanks, + string? assemblyName) { this.TopLevelType = topLevelType; this.NestedTypes = nestedTypes; @@ -132,12 +131,12 @@ internal AssemblyQualifiedTypeName DecodeTypeName(bool isTypeArgument = false, b { Debug.Assert(!isTypeArgumentWithAssemblyName || isTypeArgument); - string topLevelType = null; - ArrayBuilder nestedTypesBuilder = null; - AssemblyQualifiedTypeName[] typeArguments = null; + string? topLevelType = null; + ArrayBuilder? nestedTypesBuilder = null; + AssemblyQualifiedTypeName[]? typeArguments = null; int pointerCount = 0; - ArrayBuilder arrayRanksBuilder = null; - string assemblyName = null; + ArrayBuilder? arrayRanksBuilder = null; + string? assemblyName = null; bool decodingTopLevelType = true; bool isGenericTypeName = false; @@ -276,7 +275,7 @@ internal AssemblyQualifiedTypeName DecodeTypeName(bool isTypeArgument = false, b assemblyName); } - private static void HandleDecodedTypeName(string decodedTypeName, bool decodingTopLevelType, ref string topLevelType, ref ArrayBuilder nestedTypesBuilder) + private static void HandleDecodedTypeName(string decodedTypeName, bool decodingTopLevelType, ref string? topLevelType, ref ArrayBuilder? nestedTypesBuilder) { if (decodedTypeName.Length != 0) { @@ -318,7 +317,7 @@ private string DecodeGenericName(int i) return _input.Substring(start, _offset - start); } - private AssemblyQualifiedTypeName[] DecodeTypeArguments() + private AssemblyQualifiedTypeName[]? DecodeTypeArguments() { if (EndOfInput) { @@ -380,7 +379,7 @@ private AssemblyQualifiedTypeName DecodeTypeArgument() return result; } - private string DecodeAssemblyName(bool isTypeArgumentWithAssemblyName) + private string? DecodeAssemblyName(bool isTypeArgumentWithAssemblyName) { if (EndOfInput) { @@ -409,7 +408,7 @@ private string DecodeAssemblyName(bool isTypeArgumentWithAssemblyName) /// /// Rank equal 0 is used to denote an SzArray, rank equal 1 denotes multi-dimensional array of rank 1. /// - private void DecodeArrayShape(StringBuilder typeNameBuilder, ref ArrayBuilder arrayRanksBuilder) + private void DecodeArrayShape(StringBuilder typeNameBuilder, ref ArrayBuilder? arrayRanksBuilder) { Debug.Assert(Current == '['); @@ -475,12 +474,10 @@ internal static string GetAritySuffix(int arity) return (arity <= 9) ? s_aritySuffixesOneToNine[arity - 1] : string.Concat(GenericTypeNameManglingString, arity.ToString(CultureInfo.InvariantCulture)); } -#nullable enable internal static string ComposeAritySuffixedMetadataName(string name, int arity, string? associatedFileIdentifier) { return associatedFileIdentifier + (arity == 0 ? name : name + GetAritySuffix(arity)); } -#nullable disable internal static int InferTypeArityFromMetadataName(string emittedTypeName) { @@ -714,7 +711,7 @@ internal static ReadOnlyMemory SplitQualifiedName( } internal static string BuildQualifiedName( - string qualifier, + string? qualifier, string name) { Debug.Assert(name != null); @@ -768,8 +765,8 @@ public static void GetInfoForImmediateNamespaceMembers( int namespaceNameLength, IEnumerable> typesByNS, StringComparer nameComparer, - out IEnumerable> types, - out IEnumerable>>> namespaces) + [NotNull] out IEnumerable>? types, + [NotNull] out IEnumerable>>>? namespaces) { Debug.Assert(typesByNS != null); Debug.Assert(namespaceNameLength >= 0); @@ -795,11 +792,11 @@ public static void GetInfoForImmediateNamespaceMembers( var pair = enumerator.Current; // Simple name of the last encountered child namespace. - string lastChildNamespaceName = null; + string? lastChildNamespaceName = null; // A list accumulating information about types within the last encountered child namespace. // The list is similar to the sequence passed to this function. - List> typesInLastChildNamespace = null; + List>? typesInLastChildNamespace = null; // if there are any types in this namespace, // they will be in the first several groups if their key length @@ -831,6 +828,11 @@ public static void GetInfoForImmediateNamespaceMembers( int cmp = nameComparer.Compare(lastChildNamespaceName, childNamespaceName); if (cmp == 0) { + // This cannot be null because the starting state for lastChildNamespaceName is null and + // hence we can't hit this branch in the first iteration. The else branch will always + // allocate this value. + Debug.Assert((object?)typesInLastChildNamespace != null); + // We are still processing the same child namespace typesInLastChildNamespace.Add(pair); } @@ -840,13 +842,14 @@ public static void GetInfoForImmediateNamespaceMembers( if (cmp > 0) { // The sort order is violated for child namespace names. Obfuscation is the likely reason for this. - Debug.Assert((object)lastChildNamespaceName != null); + Debug.Assert(lastChildNamespaceName != null); possiblyHavePairsWithDuplicateKey = true; } // Preserve information about previous child namespace. if (typesInLastChildNamespace != null) { + Debug.Assert(lastChildNamespaceName != null); Debug.Assert(typesInLastChildNamespace.Count != 0); nestedNamespaces.Add( new KeyValuePair>>( @@ -855,7 +858,6 @@ public static void GetInfoForImmediateNamespaceMembers( typesInLastChildNamespace = new List>(); lastChildNamespaceName = childNamespaceName; - Debug.Assert((object)lastChildNamespaceName != null); typesInLastChildNamespace.Add(pair); } @@ -865,6 +867,7 @@ public static void GetInfoForImmediateNamespaceMembers( // Preserve information about last child namespace. if (typesInLastChildNamespace != null) { + Debug.Assert(lastChildNamespaceName != null); Debug.Assert(typesInLastChildNamespace.Count != 0); nestedNamespaces.Add( new KeyValuePair>>( @@ -947,7 +950,7 @@ private static string ExtractSimpleNameOfChildNamespace( /// /// Determines whether given string can be used as a non-empty metadata identifier (a NUL-terminated UTF-8 string). /// - internal static bool IsValidMetadataIdentifier(string str) + internal static bool IsValidMetadataIdentifier(string? str) { return !string.IsNullOrEmpty(str) && str.IsValidUnicodeString() && str.IndexOf('\0') == -1; } @@ -955,19 +958,19 @@ internal static bool IsValidMetadataIdentifier(string str) /// /// True if the string doesn't contain incomplete surrogates. /// - internal static bool IsValidUnicodeString(string str) + internal static bool IsValidUnicodeString(string? str) { return str == null || str.IsValidUnicodeString(); } - internal static bool IsValidAssemblyOrModuleName(string name) + internal static bool IsValidAssemblyOrModuleName(string? name) { return GetAssemblyOrModuleNameErrorArgumentResourceName(name) == null; } internal static void CheckAssemblyOrModuleName(string name, CommonMessageProvider messageProvider, int code, DiagnosticBag diagnostics) { - string errorArgumentResourceId = GetAssemblyOrModuleNameErrorArgumentResourceName(name); + string? errorArgumentResourceId = GetAssemblyOrModuleNameErrorArgumentResourceName(name); if (errorArgumentResourceId != null) { diagnostics.Add( @@ -978,7 +981,7 @@ internal static void CheckAssemblyOrModuleName(string name, CommonMessageProvide internal static void CheckAssemblyOrModuleName(string name, CommonMessageProvider messageProvider, int code, ArrayBuilder builder) { - string errorArgumentResourceId = GetAssemblyOrModuleNameErrorArgumentResourceName(name); + string? errorArgumentResourceId = GetAssemblyOrModuleNameErrorArgumentResourceName(name); if (errorArgumentResourceId != null) { builder.Add( @@ -987,7 +990,7 @@ internal static void CheckAssemblyOrModuleName(string name, CommonMessageProvide } } - private static string GetAssemblyOrModuleNameErrorArgumentResourceName(string name) + private static string? GetAssemblyOrModuleNameErrorArgumentResourceName(string? name) { if (name == null) { diff --git a/src/Compilers/Core/Portable/MetadataReader/PEModule.cs b/src/Compilers/Core/Portable/MetadataReader/PEModule.cs index 7e2c6a5eae7f6..bdb30612ee7df 100644 --- a/src/Compilers/Core/Portable/MetadataReader/PEModule.cs +++ b/src/Compilers/Core/Portable/MetadataReader/PEModule.cs @@ -645,6 +645,8 @@ private IEnumerable GetTypeDefsOrThrow(bool topLevelOnly) } } +#nullable enable + /// /// The function groups types defined in the module by their fully-qualified namespace name. /// The case-sensitivity of the grouping depends upon the provided StringComparer. @@ -670,9 +672,11 @@ internal IEnumerable> GroupTypesByNamesp // merged, even if they are equal according to the provided comparer. This improves the error // experience because types retain their exact namespaces. - Dictionary> namespaces = new Dictionary>(); + Dictionary?> namespaces = new Dictionary?>(); - GetTypeNamespaceNamesOrThrow(namespaces); + // Note: the ! assertion here is for the ArrayBuilder values being non-null in this + // method. The dictionary is empty so this is trivially true. + GetTypeNamespaceNamesOrThrow(namespaces!); GetForwardedTypeNamespaceNamesOrThrow(namespaces); var result = new ArrayBuilder>(namespaces.Count); @@ -686,7 +690,7 @@ internal IEnumerable> GroupTypesByNamesp return result; } - internal class TypesByNamespaceSortComparer : IComparer> + internal sealed class TypesByNamespaceSortComparer : IComparer> { private readonly StringComparer _nameComparer; @@ -695,13 +699,23 @@ public TypesByNamespaceSortComparer(StringComparer nameComparer) _nameComparer = nameComparer; } - public int Compare(IGrouping left, IGrouping right) + public int Compare(IGrouping? left, IGrouping? right) { if (left == right) { return 0; } + if (left is null) + { + return -1; + } + + if (right is null) + { + return 1; + } + int result = _nameComparer.Compare(left.Key, right.Key); if (result == 0) @@ -745,7 +759,7 @@ private void GetTypeNamespaceNamesOrThrow(Dictionary builder; + ArrayBuilder? builder; if (namespaceHandles.TryGetValue(nsHandle, out builder)) { @@ -761,7 +775,7 @@ private void GetTypeNamespaceNamesOrThrow(Dictionary builder; + ArrayBuilder? builder; if (namespaces.TryGetValue(@namespace, out builder)) { @@ -816,7 +830,7 @@ public int GetHashCode(NamespaceDefinitionHandle obj) /// the qualifier). /// /// An exception from metadata reader. - private void GetForwardedTypeNamespaceNamesOrThrow(Dictionary> namespaces) + private void GetForwardedTypeNamespaceNamesOrThrow(Dictionary?> namespaces) { EnsureForwardTypeToAssemblyMap(); @@ -831,6 +845,8 @@ private void GetForwardedTypeNamespaceNamesOrThrow(DictionaryMicrosoft.CodeAnalysis true $(NetRoslynSourceBuild);netstandard2.0 - $(DefineConstants);COMPILERCORE + $(DefineConstants);COMPILERCORE;MICROSOFT_CODEANALYSIS_CONTRACTS_NO_CONTRACT + + + $(DefineConstants);MICROSOFT_CODEANALYSIS_POOLEDOBJECTS_NO_POOLED_DISPOSER + true full true @@ -115,4 +119,5 @@ + diff --git a/src/Compilers/Core/Portable/PEWriter/InheritedTypeParameter.cs b/src/Compilers/Core/Portable/PEWriter/InheritedTypeParameter.cs index a988641b3ca32..a90fc8b2212b8 100644 --- a/src/Compilers/Core/Portable/PEWriter/InheritedTypeParameter.cs +++ b/src/Compilers/Core/Portable/PEWriter/InheritedTypeParameter.cs @@ -2,10 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Reflection.Metadata; -using Roslyn.Utilities; +using Microsoft.CodeAnalysis; using EmitContext = Microsoft.CodeAnalysis.Emit.EmitContext; namespace Microsoft.Cci @@ -307,13 +306,13 @@ public bool IsGenericTypeInstance public sealed override bool Equals(object? obj) { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } public sealed override int GetHashCode() { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } } } diff --git a/src/Compilers/Core/Portable/PEWriter/Members.cs b/src/Compilers/Core/Portable/PEWriter/Members.cs index c1c2cd6e5ecc6..c15988d673d5b 100644 --- a/src/Compilers/Core/Portable/PEWriter/Members.cs +++ b/src/Compilers/Core/Portable/PEWriter/Members.cs @@ -1047,6 +1047,11 @@ public static bool ShouldInclude(this ITypeDefinitionMember member, EmitContext } } + if (method != null && (context.Module.PEEntryPoint == method || context.Module.DebugEntryPoint == method)) + { + return true; + } + return false; } } diff --git a/src/Compilers/Core/Portable/PEWriter/MetadataVisitor.cs b/src/Compilers/Core/Portable/PEWriter/MetadataVisitor.cs index ccb46b02b74f8..f92843a23a2b2 100644 --- a/src/Compilers/Core/Portable/PEWriter/MetadataVisitor.cs +++ b/src/Compilers/Core/Portable/PEWriter/MetadataVisitor.cs @@ -3,11 +3,11 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Diagnostics; -using Roslyn.Utilities; using System.Collections.Immutable; -using Microsoft.CodeAnalysis.Emit; +using System.Diagnostics; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeGen; +using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.Emit.EditAndContinue; namespace Microsoft.Cci diff --git a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs b/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs index da741a04c3d43..21c94065a09e0 100644 --- a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs +++ b/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs @@ -1869,7 +1869,7 @@ public PortablePdbBuilder GetPortablePdbBuilder(ImmutableArray typeSystemRo internal void GetEntryPoints(out MethodDefinitionHandle entryPointHandle, out MethodDefinitionHandle debugEntryPointHandle) { - if (IsFullMetadata && !MetadataOnly) + if (IsFullMetadata) { // PE entry point is set for executable programs IMethodReference entryPoint = module.PEEntryPoint; @@ -2343,7 +2343,7 @@ private void PopulateFieldRvaTableRows(out PooledBlobBuilder? mappedFieldDataWri mappedFieldDataWriter ??= PooledBlobBuilder.GetInstance(); - // The compiler always aligns each RVA data field to an 8-byte boundary; this accomodates the alignment + // The compiler always aligns each RVA data field to an 8-byte boundary; this accommodates the alignment // needs for all primitive types, regardless of which type is actually being used, at the expense of // potentially wasting up to 7 bytes per field if the alignment needs are less. In the future, this // potentially could be tightened to align each field only as much as is actually required by that diff --git a/src/Compilers/Core/Portable/PEWriter/MethodDefinitionBase.cs b/src/Compilers/Core/Portable/PEWriter/MethodDefinitionBase.cs index 2ecd2e3d02edf..712124d888ce8 100644 --- a/src/Compilers/Core/Portable/PEWriter/MethodDefinitionBase.cs +++ b/src/Compilers/Core/Portable/PEWriter/MethodDefinitionBase.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Reflection; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.Debugging; using Microsoft.CodeAnalysis.Emit; diff --git a/src/Compilers/Core/Portable/PEWriter/ModifiedTypeReference.cs b/src/Compilers/Core/Portable/PEWriter/ModifiedTypeReference.cs index 5d3d9b805dbe9..5dfc45e136099 100644 --- a/src/Compilers/Core/Portable/PEWriter/ModifiedTypeReference.cs +++ b/src/Compilers/Core/Portable/PEWriter/ModifiedTypeReference.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Reflection.Metadata; +using Microsoft.CodeAnalysis; using Roslyn.Utilities; using EmitContext = Microsoft.CodeAnalysis.Emit.EmitContext; @@ -150,13 +151,13 @@ void IReference.Dispatch(MetadataVisitor visitor) public sealed override bool Equals(object? obj) { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } public sealed override int GetHashCode() { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } } } diff --git a/src/Compilers/Core/Portable/PEWriter/ParameterDefinitionBase.cs b/src/Compilers/Core/Portable/PEWriter/ParameterDefinitionBase.cs index 1eceff4aa72e7..886b50dc0e8be 100644 --- a/src/Compilers/Core/Portable/PEWriter/ParameterDefinitionBase.cs +++ b/src/Compilers/Core/Portable/PEWriter/ParameterDefinitionBase.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Collections.Immutable; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.Symbols; @@ -36,12 +37,12 @@ internal abstract class ParameterDefinitionBase : Cci.IParameterDefinition public sealed override bool Equals(object? obj) { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } public sealed override int GetHashCode() { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } } diff --git a/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs b/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs index 9db1f14698f3a..e6f49eafe857a 100644 --- a/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs +++ b/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.Reflection.Metadata; using System.Runtime.InteropServices; +using Microsoft.CodeAnalysis; using Roslyn.Utilities; using EmitContext = Microsoft.CodeAnalysis.Emit.EmitContext; @@ -329,13 +330,13 @@ IDefinition IReference.AsDefinition(EmitContext context) public sealed override bool Equals(object? obj) { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } public sealed override int GetHashCode() { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } } } diff --git a/src/Compilers/Core/Portable/PEWriter/SequencePoint.cs b/src/Compilers/Core/Portable/PEWriter/SequencePoint.cs index fbe377f8b1775..57e996fd5a0e7 100644 --- a/src/Compilers/Core/Portable/PEWriter/SequencePoint.cs +++ b/src/Compilers/Core/Portable/PEWriter/SequencePoint.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis; using Roslyn.Utilities; namespace Microsoft.Cci diff --git a/src/Compilers/Core/Portable/PublicAPI.Shipped.txt b/src/Compilers/Core/Portable/PublicAPI.Shipped.txt index 45ef4235bb695..6bb0d05afefe7 100644 --- a/src/Compilers/Core/Portable/PublicAPI.Shipped.txt +++ b/src/Compilers/Core/Portable/PublicAPI.Shipped.txt @@ -4,6 +4,12 @@ [RSEXPERIMENTAL001]Microsoft.CodeAnalysis.SemanticModelOptions.DisableNullableAnalysis = 2 -> Microsoft.CodeAnalysis.SemanticModelOptions [RSEXPERIMENTAL001]Microsoft.CodeAnalysis.SemanticModelOptions.IgnoreAccessibility = 1 -> Microsoft.CodeAnalysis.SemanticModelOptions [RSEXPERIMENTAL001]Microsoft.CodeAnalysis.SemanticModelOptions.None = 0 -> Microsoft.CodeAnalysis.SemanticModelOptions +[RSEXPERIMENTAL004]Microsoft.CodeAnalysis.HostOutputProductionContext +[RSEXPERIMENTAL004]Microsoft.CodeAnalysis.HostOutputProductionContext.AddOutput(string! name, object! value) -> void +[RSEXPERIMENTAL004]Microsoft.CodeAnalysis.HostOutputProductionContext.CancellationToken.get -> System.Threading.CancellationToken +[RSEXPERIMENTAL004]Microsoft.CodeAnalysis.HostOutputProductionContext.HostOutputProductionContext() -> void +[RSEXPERIMENTAL004]Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.RegisterHostOutput(Microsoft.CodeAnalysis.IncrementalValueProvider source, System.Action! action) -> void +[RSEXPERIMENTAL004]Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.RegisterHostOutput(Microsoft.CodeAnalysis.IncrementalValuesProvider source, System.Action! action) -> void ~Microsoft.CodeAnalysis.IAnalyzerAssemblyLoader.AddDependencyLocation(string fullPath) -> void ~Microsoft.CodeAnalysis.IAnalyzerAssemblyLoader.LoadFromPath(string fullPath) -> System.Reflection.Assembly ~Microsoft.CodeAnalysis.ISymbol.ContainingAssembly.get -> Microsoft.CodeAnalysis.IAssemblySymbol @@ -511,6 +517,7 @@ Microsoft.CodeAnalysis.Compilation.CreateErrorTypeSymbol(Microsoft.CodeAnalysis. Microsoft.CodeAnalysis.Compilation.CreateFunctionPointerTypeSymbol(Microsoft.CodeAnalysis.ITypeSymbol! returnType, Microsoft.CodeAnalysis.RefKind returnRefKind, System.Collections.Immutable.ImmutableArray parameterTypes, System.Collections.Immutable.ImmutableArray parameterRefKinds, System.Reflection.Metadata.SignatureCallingConvention callingConvention = System.Reflection.Metadata.SignatureCallingConvention.Default, System.Collections.Immutable.ImmutableArray callingConventionTypes = default(System.Collections.Immutable.ImmutableArray)) -> Microsoft.CodeAnalysis.IFunctionPointerTypeSymbol! Microsoft.CodeAnalysis.Compilation.CreateNativeIntegerTypeSymbol(bool signed) -> Microsoft.CodeAnalysis.INamedTypeSymbol! Microsoft.CodeAnalysis.Compilation.CreatePointerTypeSymbol(Microsoft.CodeAnalysis.ITypeSymbol! pointedAtType) -> Microsoft.CodeAnalysis.IPointerTypeSymbol! +Microsoft.CodeAnalysis.Compilation.CreatePreprocessingSymbol(string! name) -> Microsoft.CodeAnalysis.IPreprocessingSymbol! Microsoft.CodeAnalysis.Compilation.CreateTupleTypeSymbol(Microsoft.CodeAnalysis.INamedTypeSymbol! underlyingType, System.Collections.Immutable.ImmutableArray elementNames = default(System.Collections.Immutable.ImmutableArray), System.Collections.Immutable.ImmutableArray elementLocations = default(System.Collections.Immutable.ImmutableArray), System.Collections.Immutable.ImmutableArray elementNullableAnnotations = default(System.Collections.Immutable.ImmutableArray)) -> Microsoft.CodeAnalysis.INamedTypeSymbol! Microsoft.CodeAnalysis.Compilation.CreateTupleTypeSymbol(Microsoft.CodeAnalysis.INamedTypeSymbol! underlyingType, System.Collections.Immutable.ImmutableArray elementNames, System.Collections.Immutable.ImmutableArray elementLocations) -> Microsoft.CodeAnalysis.INamedTypeSymbol! Microsoft.CodeAnalysis.Compilation.CreateTupleTypeSymbol(System.Collections.Immutable.ImmutableArray elementTypes, System.Collections.Immutable.ImmutableArray elementNames = default(System.Collections.Immutable.ImmutableArray), System.Collections.Immutable.ImmutableArray elementLocations = default(System.Collections.Immutable.ImmutableArray), System.Collections.Immutable.ImmutableArray elementNullableAnnotations = default(System.Collections.Immutable.ImmutableArray)) -> Microsoft.CodeAnalysis.INamedTypeSymbol! @@ -1051,8 +1058,10 @@ Microsoft.CodeAnalysis.Emit.MethodInstrumentation.Kinds.get -> System.Collection Microsoft.CodeAnalysis.Emit.MethodInstrumentation.Kinds.init -> void Microsoft.CodeAnalysis.Emit.MethodInstrumentation.MethodInstrumentation() -> void Microsoft.CodeAnalysis.Emit.RuntimeRudeEdit +Microsoft.CodeAnalysis.Emit.RuntimeRudeEdit.ErrorCode.get -> int Microsoft.CodeAnalysis.Emit.RuntimeRudeEdit.Message.get -> string! Microsoft.CodeAnalysis.Emit.RuntimeRudeEdit.RuntimeRudeEdit() -> void +Microsoft.CodeAnalysis.Emit.RuntimeRudeEdit.RuntimeRudeEdit(string! message, int errorCode) -> void Microsoft.CodeAnalysis.Emit.RuntimeRudeEdit.RuntimeRudeEdit(string! message) -> void Microsoft.CodeAnalysis.Emit.SemanticEdit Microsoft.CodeAnalysis.Emit.SemanticEdit.Equals(Microsoft.CodeAnalysis.Emit.SemanticEdit other) -> bool @@ -1201,12 +1210,16 @@ Microsoft.CodeAnalysis.GeneratorDriver.RemoveGenerators(System.Collections.Immut Microsoft.CodeAnalysis.GeneratorDriver.ReplaceAdditionalText(Microsoft.CodeAnalysis.AdditionalText! oldText, Microsoft.CodeAnalysis.AdditionalText! newText) -> Microsoft.CodeAnalysis.GeneratorDriver! Microsoft.CodeAnalysis.GeneratorDriver.ReplaceAdditionalTexts(System.Collections.Immutable.ImmutableArray newTexts) -> Microsoft.CodeAnalysis.GeneratorDriver! Microsoft.CodeAnalysis.GeneratorDriver.ReplaceGenerators(System.Collections.Immutable.ImmutableArray generators) -> Microsoft.CodeAnalysis.GeneratorDriver! -Microsoft.CodeAnalysis.GeneratorDriver.RunGenerators(Microsoft.CodeAnalysis.Compilation! compilation, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.GeneratorDriver! +Microsoft.CodeAnalysis.GeneratorDriver.RunGenerators(Microsoft.CodeAnalysis.Compilation! compilation, System.Func? generatorFilter, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.GeneratorDriver! +Microsoft.CodeAnalysis.GeneratorDriver.RunGenerators(Microsoft.CodeAnalysis.Compilation! compilation, System.Threading.CancellationToken cancellationToken) -> Microsoft.CodeAnalysis.GeneratorDriver! +Microsoft.CodeAnalysis.GeneratorDriver.RunGenerators(Microsoft.CodeAnalysis.Compilation! compilation) -> Microsoft.CodeAnalysis.GeneratorDriver! Microsoft.CodeAnalysis.GeneratorDriver.RunGeneratorsAndUpdateCompilation(Microsoft.CodeAnalysis.Compilation! compilation, out Microsoft.CodeAnalysis.Compilation! outputCompilation, out System.Collections.Immutable.ImmutableArray diagnostics, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.GeneratorDriver! Microsoft.CodeAnalysis.GeneratorDriver.WithUpdatedAnalyzerConfigOptions(Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptionsProvider! newOptions) -> Microsoft.CodeAnalysis.GeneratorDriver! Microsoft.CodeAnalysis.GeneratorDriver.WithUpdatedParseOptions(Microsoft.CodeAnalysis.ParseOptions! newOptions) -> Microsoft.CodeAnalysis.GeneratorDriver! Microsoft.CodeAnalysis.GeneratorDriverOptions +Microsoft.CodeAnalysis.GeneratorDriverOptions.BaseDirectory.get -> string? Microsoft.CodeAnalysis.GeneratorDriverOptions.GeneratorDriverOptions() -> void +Microsoft.CodeAnalysis.GeneratorDriverOptions.GeneratorDriverOptions(Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind disabledOutputs = Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind.None, bool trackIncrementalGeneratorSteps = false, string? baseDirectory = null) -> void Microsoft.CodeAnalysis.GeneratorDriverOptions.GeneratorDriverOptions(Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind disabledOutputs) -> void Microsoft.CodeAnalysis.GeneratorDriverOptions.GeneratorDriverOptions(Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind disabledOutputs, bool trackIncrementalGeneratorSteps) -> void Microsoft.CodeAnalysis.GeneratorDriverRunResult @@ -1230,6 +1243,10 @@ Microsoft.CodeAnalysis.GeneratorExecutionContext.ReportDiagnostic(Microsoft.Code Microsoft.CodeAnalysis.GeneratorExecutionContext.SyntaxContextReceiver.get -> Microsoft.CodeAnalysis.ISyntaxContextReceiver? Microsoft.CodeAnalysis.GeneratorExecutionContext.SyntaxReceiver.get -> Microsoft.CodeAnalysis.ISyntaxReceiver? Microsoft.CodeAnalysis.GeneratorExtensions +Microsoft.CodeAnalysis.GeneratorFilterContext +Microsoft.CodeAnalysis.GeneratorFilterContext.CancellationToken.get -> System.Threading.CancellationToken +Microsoft.CodeAnalysis.GeneratorFilterContext.Generator.get -> Microsoft.CodeAnalysis.ISourceGenerator! +Microsoft.CodeAnalysis.GeneratorFilterContext.GeneratorFilterContext() -> void Microsoft.CodeAnalysis.GeneratorInitializationContext Microsoft.CodeAnalysis.GeneratorInitializationContext.CancellationToken.get -> System.Threading.CancellationToken Microsoft.CodeAnalysis.GeneratorInitializationContext.GeneratorInitializationContext() -> void @@ -1247,6 +1264,7 @@ Microsoft.CodeAnalysis.GeneratorRunResult.Exception.get -> System.Exception? Microsoft.CodeAnalysis.GeneratorRunResult.GeneratedSources.get -> System.Collections.Immutable.ImmutableArray Microsoft.CodeAnalysis.GeneratorRunResult.Generator.get -> Microsoft.CodeAnalysis.ISourceGenerator! Microsoft.CodeAnalysis.GeneratorRunResult.GeneratorRunResult() -> void +Microsoft.CodeAnalysis.GeneratorRunResult.HostOutputs.get -> System.Collections.Immutable.ImmutableDictionary! Microsoft.CodeAnalysis.GeneratorRunResult.TrackedOutputSteps.get -> System.Collections.Immutable.ImmutableDictionary>! Microsoft.CodeAnalysis.GeneratorRunResult.TrackedSteps.get -> System.Collections.Immutable.ImmutableDictionary>! Microsoft.CodeAnalysis.GeneratorSyntaxContext @@ -1461,6 +1479,7 @@ Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.RegisterSourceO Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.RegisterSourceOutput(Microsoft.CodeAnalysis.IncrementalValuesProvider source, System.Action! action) -> void Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.SyntaxProvider.get -> Microsoft.CodeAnalysis.SyntaxValueProvider Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind +Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind.Host = 8 -> Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind.Implementation = 4 -> Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind.None = 0 -> Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind.PostInit = 2 -> Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind @@ -1548,6 +1567,7 @@ Microsoft.CodeAnalysis.IPropertySymbol Microsoft.CodeAnalysis.IPropertySymbol.ExplicitInterfaceImplementations.get -> System.Collections.Immutable.ImmutableArray Microsoft.CodeAnalysis.IPropertySymbol.GetMethod.get -> Microsoft.CodeAnalysis.IMethodSymbol? Microsoft.CodeAnalysis.IPropertySymbol.IsIndexer.get -> bool +Microsoft.CodeAnalysis.IPropertySymbol.IsPartialDefinition.get -> bool Microsoft.CodeAnalysis.IPropertySymbol.IsReadOnly.get -> bool Microsoft.CodeAnalysis.IPropertySymbol.IsRequired.get -> bool Microsoft.CodeAnalysis.IPropertySymbol.IsWithEvents.get -> bool @@ -1556,6 +1576,8 @@ Microsoft.CodeAnalysis.IPropertySymbol.NullableAnnotation.get -> Microsoft.CodeA Microsoft.CodeAnalysis.IPropertySymbol.OriginalDefinition.get -> Microsoft.CodeAnalysis.IPropertySymbol! Microsoft.CodeAnalysis.IPropertySymbol.OverriddenProperty.get -> Microsoft.CodeAnalysis.IPropertySymbol? Microsoft.CodeAnalysis.IPropertySymbol.Parameters.get -> System.Collections.Immutable.ImmutableArray +Microsoft.CodeAnalysis.IPropertySymbol.PartialDefinitionPart.get -> Microsoft.CodeAnalysis.IPropertySymbol? +Microsoft.CodeAnalysis.IPropertySymbol.PartialImplementationPart.get -> Microsoft.CodeAnalysis.IPropertySymbol? Microsoft.CodeAnalysis.IPropertySymbol.RefCustomModifiers.get -> System.Collections.Immutable.ImmutableArray Microsoft.CodeAnalysis.IPropertySymbol.RefKind.get -> Microsoft.CodeAnalysis.RefKind Microsoft.CodeAnalysis.IPropertySymbol.ReturnsByRef.get -> bool @@ -1610,6 +1632,7 @@ Microsoft.CodeAnalysis.ISyntaxContextReceiver.OnVisitSyntaxNode(Microsoft.CodeAn Microsoft.CodeAnalysis.ISyntaxReceiver Microsoft.CodeAnalysis.ISyntaxReceiver.OnVisitSyntaxNode(Microsoft.CodeAnalysis.SyntaxNode! syntaxNode) -> void Microsoft.CodeAnalysis.ITypeParameterSymbol +Microsoft.CodeAnalysis.ITypeParameterSymbol.AllowsRefLikeType.get -> bool Microsoft.CodeAnalysis.ITypeParameterSymbol.ConstraintNullableAnnotations.get -> System.Collections.Immutable.ImmutableArray Microsoft.CodeAnalysis.ITypeParameterSymbol.ConstraintTypes.get -> System.Collections.Immutable.ImmutableArray Microsoft.CodeAnalysis.ITypeParameterSymbol.DeclaringMethod.get -> Microsoft.CodeAnalysis.IMethodSymbol? @@ -2477,6 +2500,7 @@ Microsoft.CodeAnalysis.RuleSetInclude.LoadRuleSet(Microsoft.CodeAnalysis.RuleSet Microsoft.CodeAnalysis.RuleSetInclude.RuleSetInclude(string! includePath, Microsoft.CodeAnalysis.ReportDiagnostic action) -> void Microsoft.CodeAnalysis.RuntimeCapability Microsoft.CodeAnalysis.RuntimeCapability.ByRefFields = 1 -> Microsoft.CodeAnalysis.RuntimeCapability +Microsoft.CodeAnalysis.RuntimeCapability.ByRefLikeGenerics = 8 -> Microsoft.CodeAnalysis.RuntimeCapability Microsoft.CodeAnalysis.RuntimeCapability.CovariantReturnsOfClasses = 2 -> Microsoft.CodeAnalysis.RuntimeCapability Microsoft.CodeAnalysis.RuntimeCapability.DefaultImplementationsOfInterfaces = 3 -> Microsoft.CodeAnalysis.RuntimeCapability Microsoft.CodeAnalysis.RuntimeCapability.InlineArrayTypes = 7 -> Microsoft.CodeAnalysis.RuntimeCapability @@ -3620,7 +3644,9 @@ static Microsoft.CodeAnalysis.FlowAnalysis.ControlFlowGraph.Create(Microsoft.Cod static Microsoft.CodeAnalysis.FlowAnalysis.ControlFlowGraph.Create(Microsoft.CodeAnalysis.SyntaxNode! node, Microsoft.CodeAnalysis.SemanticModel! semanticModel, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.FlowAnalysis.ControlFlowGraph? static Microsoft.CodeAnalysis.FlowAnalysis.ControlFlowGraphExtensions.GetAnonymousFunctionControlFlowGraphInScope(this Microsoft.CodeAnalysis.FlowAnalysis.ControlFlowGraph! controlFlowGraph, Microsoft.CodeAnalysis.FlowAnalysis.IFlowAnonymousFunctionOperation! anonymousFunction, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.FlowAnalysis.ControlFlowGraph! static Microsoft.CodeAnalysis.FlowAnalysis.ControlFlowGraphExtensions.GetLocalFunctionControlFlowGraphInScope(this Microsoft.CodeAnalysis.FlowAnalysis.ControlFlowGraph! controlFlowGraph, Microsoft.CodeAnalysis.IMethodSymbol! localFunction, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.FlowAnalysis.ControlFlowGraph! +static Microsoft.CodeAnalysis.GeneratorExtensions.AsIncrementalGenerator(this Microsoft.CodeAnalysis.ISourceGenerator! sourceGenerator) -> Microsoft.CodeAnalysis.IIncrementalGenerator! static Microsoft.CodeAnalysis.GeneratorExtensions.AsSourceGenerator(this Microsoft.CodeAnalysis.IIncrementalGenerator! incrementalGenerator) -> Microsoft.CodeAnalysis.ISourceGenerator! +static Microsoft.CodeAnalysis.GeneratorExtensions.GetGeneratorType(this Microsoft.CodeAnalysis.IIncrementalGenerator! generator) -> System.Type! static Microsoft.CodeAnalysis.GeneratorExtensions.GetGeneratorType(this Microsoft.CodeAnalysis.ISourceGenerator! generator) -> System.Type! static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.Collect(this Microsoft.CodeAnalysis.IncrementalValuesProvider source) -> Microsoft.CodeAnalysis.IncrementalValueProvider> static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.Combine(this Microsoft.CodeAnalysis.IncrementalValueProvider provider1, Microsoft.CodeAnalysis.IncrementalValueProvider provider2) -> Microsoft.CodeAnalysis.IncrementalValueProvider<(TLeft Left, TRight Right)> diff --git a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt index 5ed8ac837d3b4..aa38408099847 100644 --- a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt @@ -1,29 +1,9 @@ -Microsoft.CodeAnalysis.Emit.RuntimeRudeEdit.ErrorCode.get -> int -Microsoft.CodeAnalysis.Emit.RuntimeRudeEdit.RuntimeRudeEdit(string! message, int errorCode) -> void -Microsoft.CodeAnalysis.GeneratorDriver.RunGenerators(Microsoft.CodeAnalysis.Compilation! compilation) -> Microsoft.CodeAnalysis.GeneratorDriver! -Microsoft.CodeAnalysis.GeneratorDriver.RunGenerators(Microsoft.CodeAnalysis.Compilation! compilation, System.Func? generatorFilter, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.GeneratorDriver! -Microsoft.CodeAnalysis.GeneratorDriver.RunGenerators(Microsoft.CodeAnalysis.Compilation! compilation, System.Threading.CancellationToken cancellationToken) -> Microsoft.CodeAnalysis.GeneratorDriver! -*REMOVED*Microsoft.CodeAnalysis.GeneratorDriver.RunGenerators(Microsoft.CodeAnalysis.Compilation! compilation, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.GeneratorDriver! -Microsoft.CodeAnalysis.GeneratorDriverOptions.BaseDirectory.get -> string? -Microsoft.CodeAnalysis.GeneratorDriverOptions.GeneratorDriverOptions(Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind disabledOutputs = Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind.None, bool trackIncrementalGeneratorSteps = false, string? baseDirectory = null) -> void -Microsoft.CodeAnalysis.GeneratorFilterContext -Microsoft.CodeAnalysis.GeneratorFilterContext.CancellationToken.get -> System.Threading.CancellationToken -Microsoft.CodeAnalysis.GeneratorFilterContext.Generator.get -> Microsoft.CodeAnalysis.ISourceGenerator! -Microsoft.CodeAnalysis.GeneratorFilterContext.GeneratorFilterContext() -> void -Microsoft.CodeAnalysis.GeneratorRunResult.HostOutputs.get -> System.Collections.Immutable.ImmutableDictionary! -Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind.Host = 8 -> Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind +Microsoft.CodeAnalysis.IEventSymbol.IsPartialDefinition.get -> bool +Microsoft.CodeAnalysis.IEventSymbol.PartialDefinitionPart.get -> Microsoft.CodeAnalysis.IEventSymbol? +Microsoft.CodeAnalysis.IEventSymbol.PartialImplementationPart.get -> Microsoft.CodeAnalysis.IEventSymbol? Microsoft.CodeAnalysis.IncrementalGeneratorPostInitializationContext.AddEmbeddedAttributeDefinition() -> void -Microsoft.CodeAnalysis.IPropertySymbol.PartialDefinitionPart.get -> Microsoft.CodeAnalysis.IPropertySymbol? -Microsoft.CodeAnalysis.IPropertySymbol.PartialImplementationPart.get -> Microsoft.CodeAnalysis.IPropertySymbol? -Microsoft.CodeAnalysis.IPropertySymbol.IsPartialDefinition.get -> bool -Microsoft.CodeAnalysis.ITypeParameterSymbol.AllowsRefLikeType.get -> bool -Microsoft.CodeAnalysis.RuntimeCapability.ByRefLikeGenerics = 8 -> Microsoft.CodeAnalysis.RuntimeCapability -static Microsoft.CodeAnalysis.GeneratorExtensions.AsIncrementalGenerator(this Microsoft.CodeAnalysis.ISourceGenerator! sourceGenerator) -> Microsoft.CodeAnalysis.IIncrementalGenerator! -static Microsoft.CodeAnalysis.GeneratorExtensions.GetGeneratorType(this Microsoft.CodeAnalysis.IIncrementalGenerator! generator) -> System.Type! -Microsoft.CodeAnalysis.Compilation.CreatePreprocessingSymbol(string! name) -> Microsoft.CodeAnalysis.IPreprocessingSymbol! -[RSEXPERIMENTAL004]Microsoft.CodeAnalysis.HostOutputProductionContext -[RSEXPERIMENTAL004]Microsoft.CodeAnalysis.HostOutputProductionContext.AddOutput(string! name, object! value) -> void -[RSEXPERIMENTAL004]Microsoft.CodeAnalysis.HostOutputProductionContext.CancellationToken.get -> System.Threading.CancellationToken -[RSEXPERIMENTAL004]Microsoft.CodeAnalysis.HostOutputProductionContext.HostOutputProductionContext() -> void -[RSEXPERIMENTAL004]Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.RegisterHostOutput(Microsoft.CodeAnalysis.IncrementalValueProvider source, System.Action! action) -> void -[RSEXPERIMENTAL004]Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.RegisterHostOutput(Microsoft.CodeAnalysis.IncrementalValuesProvider source, System.Action! action) -> void +override Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.ToString() -> string! + +Microsoft.CodeAnalysis.ITypeSymbol.IsExtension.get -> bool +Microsoft.CodeAnalysis.TypeKind.Extension = 14 -> Microsoft.CodeAnalysis.TypeKind +Microsoft.CodeAnalysis.ITypeSymbol.ExtensionParameter.get -> Microsoft.CodeAnalysis.IParameterSymbol? diff --git a/src/Compilers/Core/Portable/SpecialTypeExtensions.cs b/src/Compilers/Core/Portable/SpecialTypeExtensions.cs index 93d075bf02263..bcca9e8a5250d 100644 --- a/src/Compilers/Core/Portable/SpecialTypeExtensions.cs +++ b/src/Compilers/Core/Portable/SpecialTypeExtensions.cs @@ -267,7 +267,7 @@ public static int VBForToShiftBits(this SpecialType specialType) case SpecialType.System_Int64: return 63; default: - throw Roslyn.Utilities.ExceptionUtilities.UnexpectedValue(specialType); + throw ExceptionUtilities.UnexpectedValue(specialType); } } diff --git a/src/Compilers/Core/Portable/Symbols/IEventSymbol.cs b/src/Compilers/Core/Portable/Symbols/IEventSymbol.cs index 962e396bec592..7c573dd430c62 100644 --- a/src/Compilers/Core/Portable/Symbols/IEventSymbol.cs +++ b/src/Compilers/Core/Portable/Symbols/IEventSymbol.cs @@ -65,5 +65,20 @@ public interface IEventSymbol : ISymbol /// Properties imported from metadata can explicitly implement more than one event. /// ImmutableArray ExplicitInterfaceImplementations { get; } + + /// + /// If this is a partial event implementation part, returns the corresponding definition part, otherwise . + /// + IEventSymbol? PartialDefinitionPart { get; } + + /// + /// If this is a partial event definition part, returns the corresponding implementation part, otherwise . + /// + IEventSymbol? PartialImplementationPart { get; } + + /// + /// Returns if this is a partial definition part, otherwise . + /// + bool IsPartialDefinition { get; } } } diff --git a/src/Compilers/Core/Portable/Symbols/INamedTypeSymbol.cs b/src/Compilers/Core/Portable/Symbols/INamedTypeSymbol.cs index 2a6a9ceb1ff8c..a5a2d685d6da5 100644 --- a/src/Compilers/Core/Portable/Symbols/INamedTypeSymbol.cs +++ b/src/Compilers/Core/Portable/Symbols/INamedTypeSymbol.cs @@ -150,7 +150,7 @@ public interface INamedTypeSymbol : ITypeSymbol ImmutableArray StaticConstructors { get; } /// - /// Get the both instance and static constructors for this type. + /// Get both instance and static constructors for this type. /// ImmutableArray Constructors { get; } diff --git a/src/Compilers/Core/Portable/Symbols/ITypeSymbol.cs b/src/Compilers/Core/Portable/Symbols/ITypeSymbol.cs index e50c977543812..a27a5547b229d 100644 --- a/src/Compilers/Core/Portable/Symbols/ITypeSymbol.cs +++ b/src/Compilers/Core/Portable/Symbols/ITypeSymbol.cs @@ -81,6 +81,16 @@ public interface ITypeSymbol : INamespaceOrTypeSymbol /// bool IsNativeIntegerType { get; } + /// + /// Is this a symbol for an extension declaration. + /// + bool IsExtension { get; } + + /// + /// The extension parameter if this is an extension declaration ( is true). + /// + IParameterSymbol? ExtensionParameter { get; } + /// /// The original definition of this symbol. If this symbol is constructed from another /// symbol by type substitution then gets the original symbol as it was defined in diff --git a/src/Compilers/Core/Portable/Symbols/TypeKind.cs b/src/Compilers/Core/Portable/Symbols/TypeKind.cs index e0e2aec8b5165..d695bc1793681 100644 --- a/src/Compilers/Core/Portable/Symbols/TypeKind.cs +++ b/src/Compilers/Core/Portable/Symbols/TypeKind.cs @@ -86,6 +86,11 @@ public enum TypeKind : byte /// Type is a function pointer. /// FunctionPointer = 13, + + /// + /// Type is an extension container. + /// + Extension = 14, } internal static class TypeKindInternal diff --git a/src/Compilers/Core/Portable/Symbols/WellKnownMemberNames.cs b/src/Compilers/Core/Portable/Symbols/WellKnownMemberNames.cs index 85feb4e5a2da5..e7fb022842297 100644 --- a/src/Compilers/Core/Portable/Symbols/WellKnownMemberNames.cs +++ b/src/Compilers/Core/Portable/Symbols/WellKnownMemberNames.cs @@ -406,5 +406,10 @@ public static class WellKnownMemberNames internal const string CastUpMethodName = "CastUp"; internal const string MemoryExtensionsTypeFullName = "System.MemoryExtensions"; internal const string AsSpanMethodName = "AsSpan"; + + /// + /// The name of marker method for an extension type. + /// + internal const string ExtensionMarkerMethodName = "$"; } } diff --git a/src/Compilers/Core/Portable/Text/CompositeText.cs b/src/Compilers/Core/Portable/Text/CompositeText.cs index b4fdc92beec36..41c20d8861fc6 100644 --- a/src/Compilers/Core/Portable/Text/CompositeText.cs +++ b/src/Compilers/Core/Portable/Text/CompositeText.cs @@ -208,7 +208,7 @@ private static void RemoveSplitLineBreaksAndEmptySegments(ArrayBuilder 1) { // Remove empty segments before checking for split line breaks - segments.RemoveWhere(static (s, _, _) => s.Length == 0, default(VoidResult)); + segments.RemoveWhere(static (s, _, _) => s.Length == 0, arg: 0); var splitLineBreakFound = false; for (int i = 1; i < segments.Count; i++) @@ -230,7 +230,7 @@ private static void RemoveSplitLineBreaksAndEmptySegments(ArrayBuilder s.Length == 0, default(VoidResult)); + segments.RemoveWhere(static (s, _, _) => s.Length == 0, arg: 0); } } } diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.cs.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.cs.xlf index 8c78a670fca3d..f1a880f6bfadf 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.cs.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.cs.xlf @@ -19,7 +19,7 @@ attribute - attribute + atribut @@ -89,7 +89,7 @@ {0}; file may be locked by {1} - {0}; file may be locked by {1} + {0}; soubor může být uzamčen {1} @@ -275,7 +275,7 @@ Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}. - Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}. + Nejde vygenerovat nativní soubor PDB pro '{0}' metody, protože jeho velikost metadat ladění {1} překračuje limit {2}. @@ -285,7 +285,7 @@ '{0}' type does not have the expected constructor - '{0}' type does not have the expected constructor + typ '{0}' nemá očekávaný konstruktor. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.de.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.de.xlf index 09105c3c8acdc..beb107a2c31ea 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.de.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.de.xlf @@ -19,7 +19,7 @@ attribute - attribute + Attribut @@ -89,7 +89,7 @@ {0}; file may be locked by {1} - {0}; file may be locked by {1} + {0}; Die Datei ist möglicherweise durch {1} gesperrt. @@ -275,7 +275,7 @@ Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}. - Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}. + Native PDB für Methode '{0}' kann nicht ausgeben werden, da die Größe der Debugmetadaten {1} den Grenzwert {2} überschreitet. @@ -285,7 +285,7 @@ '{0}' type does not have the expected constructor - '{0}' type does not have the expected constructor + '{0}' Typ weist nicht den erwarteten Konstruktor auf. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.es.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.es.xlf index 464d9582d2581..bfc0c93a84277 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.es.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.es.xlf @@ -19,7 +19,7 @@ attribute - attribute + atributo @@ -89,7 +89,7 @@ {0}; file may be locked by {1} - {0}; file may be locked by {1} + {0}; archivo puede estar bloqueado por {1} @@ -275,7 +275,7 @@ Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}. - Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}. + No se puede emitir un archivo PDB nativo para el método '{0}' porque su tamaño de metadatos de depuración {1} supera el límite {2}. @@ -285,7 +285,7 @@ '{0}' type does not have the expected constructor - '{0}' type does not have the expected constructor + '{0}' tipo no tiene el constructor esperado diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.fr.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.fr.xlf index cd0e0e2f40022..a2507418ec6cd 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.fr.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.fr.xlf @@ -19,7 +19,7 @@ attribute - attribute + attribut @@ -89,7 +89,7 @@ {0}; file may be locked by {1} - {0}; file may be locked by {1} + {0} ; le fichier est peut-être verrouillé par {1} @@ -275,7 +275,7 @@ Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}. - Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}. + Impossible d’émettre un fichier PDB natif pour la méthode '{0}', car sa taille des métadonnées de débogage {1} dépasse la limite {2}. @@ -285,7 +285,7 @@ '{0}' type does not have the expected constructor - '{0}' type does not have the expected constructor + '{0}' type n’a pas le constructeur attendu diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.it.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.it.xlf index 9bff0aac1c488..f20131ad127a9 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.it.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.it.xlf @@ -19,7 +19,7 @@ attribute - attribute + attributo @@ -89,7 +89,7 @@ {0}; file may be locked by {1} - {0}; file may be locked by {1} + {0}; file bloccato da {1} @@ -275,7 +275,7 @@ Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}. - Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}. + Non è possibile creare il PDB nativo per il metodo '{0}' perché le dimensioni dei metadati di debug {1} superano il limite {2}. @@ -285,7 +285,7 @@ '{0}' type does not have the expected constructor - '{0}' type does not have the expected constructor + '{0}' tipo non ha il costruttore previsto diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ja.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ja.xlf index 7e6eaf727cd1d..e1e1e66987841 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ja.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ja.xlf @@ -19,7 +19,7 @@ attribute - attribute + 属性 @@ -89,7 +89,7 @@ {0}; file may be locked by {1} - {0}; file may be locked by {1} + {0};ファイルが {1} によってロックされている可能性があります @@ -275,7 +275,7 @@ Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}. - Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}. + メソッド '{0}' のネイティブ PDB を生成できません。デバッグ メタデータ のサイズ {1} が制限 {2} を超えています。 @@ -285,7 +285,7 @@ '{0}' type does not have the expected constructor - '{0}' type does not have the expected constructor + '{0}' 型に必要なコンストラクターがありません diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ko.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ko.xlf index b974f0d815418..b7628cccaebd3 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ko.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ko.xlf @@ -19,7 +19,7 @@ attribute - attribute + 특성 @@ -89,7 +89,7 @@ {0}; file may be locked by {1} - {0}; file may be locked by {1} + {0}; 파일이 {1} 잠겼을 수 있습니다. @@ -275,7 +275,7 @@ Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}. - Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}. + 디버그 메타데이터 크기 {1} 제한 {2} 초과하여 메서드 '{0}' 네이티브 PDB를 내보낼 수 없습니다. @@ -285,7 +285,7 @@ '{0}' type does not have the expected constructor - '{0}' type does not have the expected constructor + '{0}' 형식에 필요한 생성자가 없습니다. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pl.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pl.xlf index 8afb64f762d90..fd64081f69df9 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pl.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pl.xlf @@ -19,7 +19,7 @@ attribute - attribute + atrybut @@ -89,7 +89,7 @@ {0}; file may be locked by {1} - {0}; file may be locked by {1} + {0}; plik może być zablokowany przez {1} @@ -275,7 +275,7 @@ Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}. - Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}. + Nie można wyemitować natywnego pliku PDB dla metody '{0}', ponieważ jego rozmiar metadanych debugowania {1} przekracza limit {2}. @@ -285,7 +285,7 @@ '{0}' type does not have the expected constructor - '{0}' type does not have the expected constructor + typ '{0}' nie ma oczekiwanego konstruktora diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pt-BR.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pt-BR.xlf index 667da8fa8a4ff..7d5851d87ecbf 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pt-BR.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pt-BR.xlf @@ -19,7 +19,7 @@ attribute - attribute + atributo @@ -89,7 +89,7 @@ {0}; file may be locked by {1} - {0}; file may be locked by {1} + {0}; arquivo pode ser bloqueado por {1} @@ -275,7 +275,7 @@ Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}. - Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}. + Não é possível emitir PDB nativo para o método '{0}' porque seu tamanho de metadados de depuração {1} está acima do limite {2}. @@ -285,7 +285,7 @@ '{0}' type does not have the expected constructor - '{0}' type does not have the expected constructor + '{0}' tipo não tem o construtor esperado diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ru.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ru.xlf index d73c99504d656..258301fccc197 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ru.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ru.xlf @@ -19,7 +19,7 @@ attribute - attribute + атрибут @@ -89,7 +89,7 @@ {0}; file may be locked by {1} - {0}; file may be locked by {1} + {0}; файл может быть заблокирован {1} @@ -275,7 +275,7 @@ Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}. - Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}. + Не удается создать собственный PDB-файл для '{0}', так как размер метаданных отладки {1} превышает ограничение {2}. @@ -285,7 +285,7 @@ '{0}' type does not have the expected constructor - '{0}' type does not have the expected constructor + '{0}' тип не имеет ожидаемого конструктора diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.tr.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.tr.xlf index 7b5f10d12a00d..1a7ac4a934b14 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.tr.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.tr.xlf @@ -19,7 +19,7 @@ attribute - attribute + öznitelik @@ -89,7 +89,7 @@ {0}; file may be locked by {1} - {0}; file may be locked by {1} + {0}; dosya dosya tarafından kilitlenmiş {1} @@ -275,7 +275,7 @@ Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}. - Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}. + Hata ayıklama meta veri boyutu '{0}' sınırı aşıldığından yöntem {1} için yerel PDB {2}. @@ -285,7 +285,7 @@ '{0}' type does not have the expected constructor - '{0}' type does not have the expected constructor + '{0}' türü beklenen oluşturucuya sahip değil diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hans.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hans.xlf index db00dcb951da4..e775c507b897a 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hans.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hans.xlf @@ -19,7 +19,7 @@ attribute - attribute + 属性 @@ -89,7 +89,7 @@ {0}; file may be locked by {1} - {0}; file may be locked by {1} + {0};文件可能被 {1} 锁定 @@ -275,7 +275,7 @@ Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}. - Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}. + 无法发出方法 '{0}' 的本机 PDB,因为其调试元数据大小 {1} 超过 {2} 限制。 @@ -285,7 +285,7 @@ '{0}' type does not have the expected constructor - '{0}' type does not have the expected constructor + '{0}' 类型没有所需的构造函数 diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hant.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hant.xlf index 15e41de1aac64..a7062ea1f56b0 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hant.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hant.xlf @@ -19,7 +19,7 @@ attribute - attribute + 屬性 @@ -89,7 +89,7 @@ {0}; file may be locked by {1} - {0}; file may be locked by {1} + {0};檔案可能被 {1} 鎖定 @@ -275,7 +275,7 @@ Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}. - Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}. + 無法發出方法 '{0}' 的原生 PDB,因為其偵錯元數據大小 {1} 超過限制 {2}。 @@ -285,7 +285,7 @@ '{0}' type does not have the expected constructor - '{0}' type does not have the expected constructor + '{0}' 類型沒有預期的建構函式 diff --git a/src/Compilers/Core/RebuildTest/DeterministicKeyBuilderTests.Helpers.cs b/src/Compilers/Core/RebuildTest/DeterministicKeyBuilderTests.Helpers.cs index 101aa11f3b4a1..3ea136dda94f3 100644 --- a/src/Compilers/Core/RebuildTest/DeterministicKeyBuilderTests.Helpers.cs +++ b/src/Compilers/Core/RebuildTest/DeterministicKeyBuilderTests.Helpers.cs @@ -54,5 +54,10 @@ private sealed class Generator2 : ISourceGenerator public void Initialize(GeneratorInitializationContext context) => throw new NotImplementedException(); } + + private sealed class Generator3 : IIncrementalGenerator + { + public void Initialize(IncrementalGeneratorInitializationContext context) => throw new NotImplementedException(); + } } } diff --git a/src/Compilers/Core/RebuildTest/DeterministicKeyBuilderTests.cs b/src/Compilers/Core/RebuildTest/DeterministicKeyBuilderTests.cs index 6a5c441267e7c..da69156710812 100644 --- a/src/Compilers/Core/RebuildTest/DeterministicKeyBuilderTests.cs +++ b/src/Compilers/Core/RebuildTest/DeterministicKeyBuilderTests.cs @@ -803,7 +803,8 @@ public void Generators() var array = GetGeneratorValues( CreateCompilation(Array.Empty()), new Generator(), - new Generator2()); + new Generator2(), + new Generator3().AsSourceGenerator()); var assembly = typeof(Generator).Assembly; var expected = @$" @@ -817,6 +818,11 @@ public void Generators() ""fullName"": ""{typeof(Generator2).FullName}"", ""assemblyName"": ""{assembly.FullName}"", ""mvid"": ""{DeterministicKeyBuilder.GetGuidValue(assembly.ManifestModule.ModuleVersionId)}"" + }}, + {{ + ""fullName"": ""{typeof(Generator3).FullName}"", + ""assemblyName"": ""{assembly.FullName}"", + ""mvid"": ""{DeterministicKeyBuilder.GetGuidValue(assembly.ManifestModule.ModuleVersionId)}"" }} ] "; diff --git a/src/Compilers/Core/RebuildTest/Microsoft.CodeAnalysis.Rebuild.UnitTests.csproj b/src/Compilers/Core/RebuildTest/Microsoft.CodeAnalysis.Rebuild.UnitTests.csproj index 52bbbb4a27ccb..22d08e4182578 100644 --- a/src/Compilers/Core/RebuildTest/Microsoft.CodeAnalysis.Rebuild.UnitTests.csproj +++ b/src/Compilers/Core/RebuildTest/Microsoft.CodeAnalysis.Rebuild.UnitTests.csproj @@ -7,9 +7,6 @@ true $(NetRoslyn);net472 - - - diff --git a/src/Compilers/Server/VBCSCompiler/CompilerRequestHandler.cs b/src/Compilers/Server/VBCSCompiler/CompilerRequestHandler.cs index 3b326885d17b9..39342ed3a16ad 100644 --- a/src/Compilers/Server/VBCSCompiler/CompilerRequestHandler.cs +++ b/src/Compilers/Server/VBCSCompiler/CompilerRequestHandler.cs @@ -72,7 +72,7 @@ internal CompilerServerHost(string clientDirectory, string? sdkDirectory, ICompi ClientDirectory = clientDirectory; SdkDirectory = sdkDirectory; Logger = logger; - AnalyzerAssemblyLoader = DefaultAnalyzerAssemblyLoader.CreateNonLockingLoader(Path.Combine(Path.GetTempPath(), "VBCSCompiler", "AnalyzerAssemblyLoader")); + AnalyzerAssemblyLoader = Microsoft.CodeAnalysis.AnalyzerAssemblyLoader.CreateNonLockingLoader(Path.Combine(Path.GetTempPath(), "VBCSCompiler", "AnalyzerAssemblyLoader")); } public bool TryCreateCompiler(in RunRequest request, BuildPaths buildPaths, [NotNullWhen(true)] out CommonCompiler? compiler) diff --git a/src/Compilers/Server/VBCSCompilerTests/AnalyzerConsistencyCheckerTests.cs b/src/Compilers/Server/VBCSCompilerTests/AnalyzerConsistencyCheckerTests.cs index 4c381c8dc8d4d..bdaf520454864 100644 --- a/src/Compilers/Server/VBCSCompilerTests/AnalyzerConsistencyCheckerTests.cs +++ b/src/Compilers/Server/VBCSCompilerTests/AnalyzerConsistencyCheckerTests.cs @@ -84,7 +84,7 @@ public void LoadLibraryWithMissingReference() { var directory = Temp.CreateDirectory(); _ = directory.CopyFile(TestFixture.Alpha); - var assemblyLoader = DefaultAnalyzerAssemblyLoader.CreateNonLockingLoader(directory.CreateDirectory("shadow").Path); + var assemblyLoader = AnalyzerAssemblyLoader.CreateNonLockingLoader(directory.CreateDirectory("shadow").Path); var analyzerReferences = ImmutableArray.Create(new CommandLineAnalyzerReference("Alpha.dll")); var result = AnalyzerConsistencyChecker.Check(directory.Path, analyzerReferences, assemblyLoader, Logger); @@ -95,7 +95,7 @@ public void LoadLibraryWithMissingReference() public void LoadLibraryAll() { var directory = Temp.CreateDirectory(); - var assemblyLoader = DefaultAnalyzerAssemblyLoader.CreateNonLockingLoader(directory.CreateDirectory("shadow").Path); + var assemblyLoader = AnalyzerAssemblyLoader.CreateNonLockingLoader(directory.CreateDirectory("shadow").Path); var analyzerReferences = ImmutableArray.Create( new CommandLineAnalyzerReference("Alpha.dll"), new CommandLineAnalyzerReference("Beta.dll"), @@ -110,7 +110,7 @@ public void LoadLibraryAll() public void DifferingMvidsDifferentDirectory() { var directory = Temp.CreateDirectory(); - var assemblyLoader = DefaultAnalyzerAssemblyLoader.CreateNonLockingLoader(directory.CreateDirectory("shadow").Path); + var assemblyLoader = AnalyzerAssemblyLoader.CreateNonLockingLoader(directory.CreateDirectory("shadow").Path); var key = NetStandard20.References.netstandard.GetAssemblyIdentity().PublicKey; var mvidAlpha1 = CreateNetStandardDll(directory.CreateDirectory("mvid1"), "MvidAlpha", "1.0.0.0", key, "class C { }"); @@ -135,7 +135,7 @@ public void DifferingMvidsDifferentDirectory() public void DifferingMvidsSameDirectory() { var directory = Temp.CreateDirectory(); - var assemblyLoader = DefaultAnalyzerAssemblyLoader.CreateNonLockingLoader(directory.CreateDirectory("shadow").Path); + var assemblyLoader = AnalyzerAssemblyLoader.CreateNonLockingLoader(directory.CreateDirectory("shadow").Path); var key = NetStandard20.References.netstandard.GetAssemblyIdentity().PublicKey; var mvidAlpha1 = CreateNetStandardDll(directory, "MvidAlpha", "1.0.0.0", key, "class C { }"); @@ -180,7 +180,7 @@ public void LoadingLibraryFromCompiler() // This test must use the DefaultAnalyzerAssemblyLoader as we want assembly binding redirects // to take affect here. - var assemblyLoader = new DefaultAnalyzerAssemblyLoader(); + var assemblyLoader = new AnalyzerAssemblyLoader(); var analyzerReferences = ImmutableArray.Create( new CommandLineAnalyzerReference("System.Memory.dll")); @@ -203,7 +203,7 @@ public void LoadingLibraryFromRuntime() // This test must use the DefaultAnalyzerAssemblyLoader as we want assembly binding redirects // to take affect here. - var assemblyLoader = new DefaultAnalyzerAssemblyLoader(); + var assemblyLoader = new AnalyzerAssemblyLoader(); var analyzerReferences = ImmutableArray.Create( new CommandLineAnalyzerReference("System.Core.dll")); @@ -239,7 +239,7 @@ public void LoadingSimpleLibrary() var analyzerReferences = ImmutableArray.Create(new CommandLineAnalyzerReference(compFile.Path)); - var result = AnalyzerConsistencyChecker.Check(directory.Path, analyzerReferences, new DefaultAnalyzerAssemblyLoader(), Logger); + var result = AnalyzerConsistencyChecker.Check(directory.Path, analyzerReferences, new AnalyzerAssemblyLoader(), Logger); Assert.True(result); } diff --git a/src/Compilers/Server/VBCSCompilerTests/TouchedFileLoggingTests.cs b/src/Compilers/Server/VBCSCompilerTests/TouchedFileLoggingTests.cs index 81e45b441bc92..f6c4d1eada0a2 100644 --- a/src/Compilers/Server/VBCSCompilerTests/TouchedFileLoggingTests.cs +++ b/src/Compilers/Server/VBCSCompilerTests/TouchedFileLoggingTests.cs @@ -46,7 +46,7 @@ End Class [ConditionalFact(typeof(DesktopOnly))] public void CSharpTrivialMetadataCaching() { - var loader = DefaultAnalyzerAssemblyLoader.CreateNonLockingLoader(Temp.CreateDirectory().Path); + var loader = AnalyzerAssemblyLoader.CreateNonLockingLoader(Temp.CreateDirectory().Path); var filelist = new List(); // Do the following compilation twice. @@ -97,7 +97,7 @@ public void CSharpTrivialMetadataCaching() [ConditionalFact(typeof(DesktopOnly))] public void VisualBasicTrivialMetadataCaching() { - var loader = DefaultAnalyzerAssemblyLoader.CreateNonLockingLoader(Temp.CreateDirectory().Path); + var loader = AnalyzerAssemblyLoader.CreateNonLockingLoader(Temp.CreateDirectory().Path); var filelist = new List(); // Do the following compilation twice. diff --git a/src/Compilers/Server/VBCSCompilerTests/VBCSCompilerServerTests.cs b/src/Compilers/Server/VBCSCompilerTests/VBCSCompilerServerTests.cs index 9ab19b4b2724a..a71a309f6ea35 100644 --- a/src/Compilers/Server/VBCSCompilerTests/VBCSCompilerServerTests.cs +++ b/src/Compilers/Server/VBCSCompilerTests/VBCSCompilerServerTests.cs @@ -38,8 +38,8 @@ public class StartupTests : VBCSCompilerServerTests public async Task ShadowCopyAnalyzerAssemblyLoaderMissingDirectory() { var baseDirectory = Path.Combine(Path.GetTempPath(), TestBase.GetUniqueName()); - var loader = new ShadowCopyAnalyzerAssemblyLoader(baseDirectory: baseDirectory); - var task = loader.DeleteLeftoverDirectoriesTask; + var shadowResolver = new ShadowCopyAnalyzerPathResolver(baseDirectory); + var task = shadowResolver.DeleteLeftoverDirectoriesTask; await task; Assert.False(task.IsFaulted); } diff --git a/src/Compilers/Shared/BuildClient.cs b/src/Compilers/Shared/BuildClient.cs index 88fec0d5687c8..b54117b2b71ec 100644 --- a/src/Compilers/Shared/BuildClient.cs +++ b/src/Compilers/Shared/BuildClient.cs @@ -192,7 +192,7 @@ public Task RunCompilationAsync(IEnumerable origin private int RunLocalCompilation(string[] arguments, BuildPaths buildPaths, TextWriter textWriter) { - var loader = new DefaultAnalyzerAssemblyLoader(); + var loader = new AnalyzerAssemblyLoader(); return _compileFunc(arguments, buildPaths, textWriter, loader); } diff --git a/src/Compilers/Test/Core/Assert/ArtifactUploadUtil.cs b/src/Compilers/Test/Core/Assert/ArtifactUploadUtil.cs index cbe4b909edabd..3a1026eb28749 100644 --- a/src/Compilers/Test/Core/Assert/ArtifactUploadUtil.cs +++ b/src/Compilers/Test/Core/Assert/ArtifactUploadUtil.cs @@ -17,7 +17,7 @@ namespace Roslyn.Test.Utilities /// the test execution. This utility is helpful at getting those artifacts attached to AzDO / Helix /// when executed in our CI process. /// - /// The utilility works by collecting a set of file paths to artifacts. If the test succeeds it should + /// The utility works by collecting a set of file paths to artifacts. If the test succeeds it should /// call the method. Otherwise if the test fails an exception is generated, /// the call is skipped and in we prepare the artifacts for upload. /// diff --git a/src/Compilers/Test/Core/CompilationVerifier.cs b/src/Compilers/Test/Core/CompilationVerifier.cs index c709948406117..b8fb0762efd44 100644 --- a/src/Compilers/Test/Core/CompilationVerifier.cs +++ b/src/Compilers/Test/Core/CompilationVerifier.cs @@ -633,7 +633,8 @@ internal string VisualizeIL(CompilationTestData.MethodData methodData, bool real throw new Exception($"Failed to extract PDB information. PdbToXmlConverter returned:{Environment.NewLine}{actualPdbXml}"); } - var methodDef = (Cci.IMethodDefinition)methodData.Method.GetCciAdapter(); + var method = methodData.Method.PartialDefinitionPart ?? methodData.Method; + var methodDef = (Cci.IMethodDefinition)method.GetCciAdapter(); var methodToken = MetadataTokens.GetToken(_testData.MetadataWriter.GetMethodDefinitionOrReferenceHandle(methodDef)); var xmlDocument = XElement.Parse(actualPdbXml); var xmlMethod = ILValidation.GetMethodElement(xmlDocument, methodToken); diff --git a/src/Compilers/Test/Core/Diagnostics/CommonDiagnosticAnalyzers.cs b/src/Compilers/Test/Core/Diagnostics/CommonDiagnosticAnalyzers.cs index 0ce0f38fbe4ac..a66fda3648859 100644 --- a/src/Compilers/Test/Core/Diagnostics/CommonDiagnosticAnalyzers.cs +++ b/src/Compilers/Test/Core/Diagnostics/CommonDiagnosticAnalyzers.cs @@ -1556,7 +1556,7 @@ private void OnCompilationStart(CompilationStartAnalysisContext context) var sortedCallbackCodeBlockNames = new SortedSet(); if (_testIsGeneratedCodeInCallbacks) { - // Test all remaining analysis contexts that expose "IsGeneratdCode" flag + // Test all remaining analysis contexts that expose "IsGeneratedCode" flag context.RegisterSyntaxNodeAction(context => sortedCallbackSyntaxNodeNames.Add($"{context.ContainingSymbol.Name}(IsGeneratedCode:{context.IsGeneratedCode})"), ImmutableArray.Create(ClassDeclarationSyntaxKind)); diff --git a/src/Compilers/Test/Core/Metadata/ILBuilderVisualizer.cs b/src/Compilers/Test/Core/Metadata/ILBuilderVisualizer.cs index 845c29432a88f..39c539e512d61 100644 --- a/src/Compilers/Test/Core/Metadata/ILBuilderVisualizer.cs +++ b/src/Compilers/Test/Core/Metadata/ILBuilderVisualizer.cs @@ -74,7 +74,7 @@ public override string VisualizeLocalType(object type) /// private static List GetHandlerSpans(ImmutableArray regions) { - if (regions.Length == 0) + if (regions.IsDefaultOrEmpty) { return null; } diff --git a/src/Compilers/Test/Core/Metadata/MetadataReaderUtils.cs b/src/Compilers/Test/Core/Metadata/MetadataReaderUtils.cs index 8cd21b15c022b..f017a680afbeb 100644 --- a/src/Compilers/Test/Core/Metadata/MetadataReaderUtils.cs +++ b/src/Compilers/Test/Core/Metadata/MetadataReaderUtils.cs @@ -13,6 +13,7 @@ using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using System.Reflection.PortableExecutable; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Debugging; using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.PooledObjects; diff --git a/src/Compilers/Test/Core/Mocks/TestMessageProvider.cs b/src/Compilers/Test/Core/Mocks/TestMessageProvider.cs index 008e2eb21e579..b3fa3ea6172e3 100644 --- a/src/Compilers/Test/Core/Mocks/TestMessageProvider.cs +++ b/src/Compilers/Test/Core/Mocks/TestMessageProvider.cs @@ -470,6 +470,8 @@ public override int ERR_InvalidDebugInfo public override int ERR_FunctionPointerTypesInAttributeNotSupported => throw new NotImplementedException(); + public override int ERR_DataSectionStringLiteralHashCollision => throw new NotImplementedException(); + public override int? WRN_ByValArraySizeConstRequired => throw new NotImplementedException(); } } diff --git a/src/Compilers/Test/Core/SourceGeneration/TestGenerators.cs b/src/Compilers/Test/Core/SourceGeneration/TestGenerators.cs index efda098d14017..1b71535ce293f 100644 --- a/src/Compilers/Test/Core/SourceGeneration/TestGenerators.cs +++ b/src/Compilers/Test/Core/SourceGeneration/TestGenerators.cs @@ -46,7 +46,7 @@ public void Initialize(GeneratorInitializationContext context) } /// - /// A generator that produces diagnostics against existng source trees, rather than generating new content. + /// A generator that produces diagnostics against existing source trees, rather than generating new content. /// internal class DiagnosticProducingGenerator : ISourceGenerator { @@ -77,7 +77,7 @@ public SingleFileTestGenerator2(string content, string hintName = "generatedFile } } -#pragma warning disable RS0062 // Do not implicitly capture primary constructor paramters +#pragma warning disable RS0062 // Do not implicitly capture primary constructor parameters internal class CallbackGenerator( Action onInit, Action onExecute, @@ -125,7 +125,7 @@ public void Execute(GeneratorExecutionContext context) } } } -#pragma warning restore RS0062 // Do not implicitly capture primary constructor paramters +#pragma warning restore RS0062 // Do not implicitly capture primary constructor parameters internal class CallbackGenerator2 : CallbackGenerator { diff --git a/src/Compilers/Test/Core/TestHelpers.cs b/src/Compilers/Test/Core/TestHelpers.cs index 05f8777281074..204bae9fc1819 100644 --- a/src/Compilers/Test/Core/TestHelpers.cs +++ b/src/Compilers/Test/Core/TestHelpers.cs @@ -23,6 +23,11 @@ namespace Roslyn.Test.Utilities { public static class TestHelpers { + /// + /// A long timeout used to avoid hangs in tests, where a test failure manifests as an operation never occurring. + /// + public static readonly TimeSpan HangMitigatingTimeout = TimeSpan.FromMinutes(4); + public static ImmutableDictionary CreateImmutableDictionary( IEqualityComparer comparer, params (K, V)[] entries) diff --git a/src/Compilers/Test/Core/TestableCompiler.cs b/src/Compilers/Test/Core/TestableCompiler.cs index a8cc3c9873f31..6e647596259fb 100644 --- a/src/Compilers/Test/Core/TestableCompiler.cs +++ b/src/Compilers/Test/Core/TestableCompiler.cs @@ -137,7 +137,7 @@ internal static TestableCompiler CreateCSharpNetCoreApp(params string[] commandL private sealed class CSharpCompilerImpl : CSharpCompiler { internal CSharpCompilerImpl(string[] args, BuildPaths buildPaths, TestableFileSystem? fileSystem) - : base(CSharpCommandLineParser.Default, responseFile: null, args, buildPaths, additionalReferenceDirectories: null, new DefaultAnalyzerAssemblyLoader(), fileSystem: fileSystem) + : base(CSharpCommandLineParser.Default, responseFile: null, args, buildPaths, additionalReferenceDirectories: null, new AnalyzerAssemblyLoader(), fileSystem: fileSystem) { } } @@ -204,7 +204,7 @@ internal static TestableCompiler CreateBasicNetCoreApp(params string[] commandLi private sealed class BasicCompilerImpl : VisualBasicCompiler { internal BasicCompilerImpl(string[] args, BuildPaths buildPaths, TestableFileSystem? fileSystem) - : base(VisualBasicCommandLineParser.Default, responseFile: null, args, buildPaths, additionalReferenceDirectories: null, new DefaultAnalyzerAssemblyLoader(), fileSystem: fileSystem) + : base(VisualBasicCommandLineParser.Default, responseFile: null, args, buildPaths, additionalReferenceDirectories: null, new AnalyzerAssemblyLoader(), fileSystem: fileSystem) { } } diff --git a/src/Compilers/Test/Core/Traits/CompilerFeature.cs b/src/Compilers/Test/Core/Traits/CompilerFeature.cs index 6032c211ef423..d21ca01eded5e 100644 --- a/src/Compilers/Test/Core/Traits/CompilerFeature.cs +++ b/src/Compilers/Test/Core/Traits/CompilerFeature.cs @@ -43,5 +43,6 @@ public enum CompilerFeature RecordStructs, RequiredMembers, RefLifetime, + Extensions, } } diff --git a/src/Compilers/Test/Core/Traits/Traits.cs b/src/Compilers/Test/Core/Traits/Traits.cs index f15d2ed986d08..b5003cb91f2ed 100644 --- a/src/Compilers/Test/Core/Traits/Traits.cs +++ b/src/Compilers/Test/Core/Traits/Traits.cs @@ -37,7 +37,7 @@ public static class Features public const string ChangeSignature = nameof(ChangeSignature); public const string ClassView = nameof(ClassView); public const string Classification = nameof(Classification); - public const string CodeActionsAddAccessibilityModifiers = "CodeActions.AddAccessibilityModifiers"; + public const string CodeActionsAddOrRemoveAccessibilityModifiers = "CodeActions.AddOrRemoveAccessibilityModifiers"; public const string CodeActionsAddAnonymousTypeMemberName = "CodeActions.AddAnonymousTypeMemberName"; public const string CodeActionsAddAwait = "CodeActions.AddAwait"; public const string CodeActionsAddBraces = "CodeActions.AddBraces"; @@ -76,6 +76,7 @@ public static class Features public const string CodeActionsConvertQueryToForEach = "CodeActions.ConvertQueryToForEach"; public const string CodeActionsConvertToRawString = "CodeActions.CodeActionsConvertToRawString"; public const string CodeActionsConvertSwitchStatementToExpression = "CodeActions.ConvertSwitchStatementToExpression"; + public const string CodeActionsConvertToExtension = "CodeActions.ConvertToExtension"; public const string CodeActionsConvertToInterpolatedString = "CodeActions.ConvertToInterpolatedString"; public const string CodeActionsConvertToIterator = "CodeActions.ConvertToIterator"; public const string CodeActionsConvertToRecord = "CodeActions.ConvertToRecord"; @@ -238,6 +239,7 @@ public static class Features public const string ConvertAutoPropertyToFullProperty = nameof(ConvertAutoPropertyToFullProperty); public const string ConvertCast = nameof(ConvertCast); public const string ConvertTypeOfToNameOf = nameof(ConvertTypeOfToNameOf); + public const string CopilotImplementNotImplementedException = nameof(CopilotImplementNotImplementedException); public const string DebuggingBreakpoints = "Debugging.Breakpoints"; public const string DebuggingDataTips = "Debugging.DataTips"; public const string DebuggingEditAndContinue = "Debugging.EditAndContinue"; @@ -289,6 +291,7 @@ public static class Features public const string NetCore = nameof(NetCore); public const string NormalizeModifiersOrOperators = nameof(NormalizeModifiersOrOperators); public const string ObjectBrowser = nameof(ObjectBrowser); + public const string OnTheFlyDocs = nameof(OnTheFlyDocs); public const string Options = nameof(Options); public const string Organizing = nameof(Organizing); public const string Outlining = nameof(Outlining); diff --git a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs index 32197356378ef..cabe8fa772230 100644 --- a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs +++ b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs @@ -213,6 +213,22 @@ public NotNullIfNotNullAttribute(string parameterName) { } } "; + protected static readonly string CallerArgumentExpressionAttributeDefinition = """ + namespace System.Runtime.CompilerServices + { + [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true, Inherited = false)] + public sealed class CallerArgumentExpressionAttribute : Attribute + { + public CallerArgumentExpressionAttribute(string parameterName) + { + ParameterName = parameterName; + } + + public string ParameterName { get; } + } + } + """; + protected static readonly string IsExternalInitTypeDefinition = @" namespace System.Runtime.CompilerServices { diff --git a/src/Compilers/Test/Utilities/CSharp/MockCSharpCompiler.cs b/src/Compilers/Test/Utilities/CSharp/MockCSharpCompiler.cs index 8e73c67d40334..6705574b7c551 100644 --- a/src/Compilers/Test/Utilities/CSharp/MockCSharpCompiler.cs +++ b/src/Compilers/Test/Utilities/CSharp/MockCSharpCompiler.cs @@ -30,7 +30,7 @@ public MockCSharpCompiler(string responseFile, string workingDirectory, string[] } public MockCSharpCompiler(string responseFile, BuildPaths buildPaths, string[] args, ImmutableArray analyzers = default, ImmutableArray generators = default, AnalyzerAssemblyLoader loader = null, GeneratorDriverCache driverCache = null, ImmutableArray additionalReferences = default) - : base(CSharpCommandLineParser.Default, responseFile, args, buildPaths, Environment.GetEnvironmentVariable("LIB"), loader ?? new DefaultAnalyzerAssemblyLoader(), driverCache) + : base(CSharpCommandLineParser.Default, responseFile, args, buildPaths, Environment.GetEnvironmentVariable("LIB"), loader ?? new AnalyzerAssemblyLoader(), driverCache) { _analyzers = analyzers.NullToEmpty(); _generators = generators.NullToEmpty(); diff --git a/src/Compilers/Test/Utilities/VisualBasic/MockVbi.vb b/src/Compilers/Test/Utilities/VisualBasic/MockVbi.vb index 41b0c256906a3..64369063be1fe 100644 --- a/src/Compilers/Test/Utilities/VisualBasic/MockVbi.vb +++ b/src/Compilers/Test/Utilities/VisualBasic/MockVbi.vb @@ -12,7 +12,7 @@ Friend Class MockVbi Inherits VisualBasicCompiler Public Sub New(responseFile As String, workingDirectory As String, args As String()) - MyBase.New(VisualBasicCommandLineParser.Script, responseFile, args, CreateBuildPaths(workingDirectory), Nothing, New DefaultAnalyzerAssemblyLoader()) + MyBase.New(VisualBasicCommandLineParser.Script, responseFile, args, CreateBuildPaths(workingDirectory), Nothing, New AnalyzerAssemblyLoader()) End Sub Private Shared Function CreateBuildPaths(workingDirectory As String) As BuildPaths diff --git a/src/Compilers/Test/Utilities/VisualBasic/MockVisualBasicCompiler.vb b/src/Compilers/Test/Utilities/VisualBasic/MockVisualBasicCompiler.vb index 616e61833c417..8a66be7909764 100644 --- a/src/Compilers/Test/Utilities/VisualBasic/MockVisualBasicCompiler.vb +++ b/src/Compilers/Test/Utilities/VisualBasic/MockVisualBasicCompiler.vb @@ -37,7 +37,7 @@ Friend Class MockVisualBasicCompiler End Sub Public Sub New(responseFile As String, buildPaths As BuildPaths, args As String(), Optional analyzers As DiagnosticAnalyzer() = Nothing, Optional generators As ISourceGenerator() = Nothing, Optional additionalReferences As MetadataReference() = Nothing) - MyBase.New(VisualBasicCommandLineParser.Default, responseFile, args, buildPaths, Environment.GetEnvironmentVariable("LIB"), New DefaultAnalyzerAssemblyLoader()) + MyBase.New(VisualBasicCommandLineParser.Default, responseFile, args, buildPaths, Environment.GetEnvironmentVariable("LIB"), New AnalyzerAssemblyLoader()) _analyzers = analyzers.AsImmutableOrEmpty() _generators = generators.AsImmutableOrEmpty() diff --git a/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb b/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb index cb0257ff9b975..549049a430208 100644 --- a/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb +++ b/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb @@ -2487,6 +2487,16 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End If SynthesizedMetadataCompiler.ProcessSynthesizedMembers(Me, moduleBeingBuilt, cancellationToken) + + If moduleBeingBuilt.OutputKind.IsApplication() Then + Dim entryPoint = GetEntryPointAndDiagnostics(cancellationToken) + diagnostics.AddRange(entryPoint.Diagnostics) + If entryPoint.MethodSymbol IsNot Nothing AndAlso Not entryPoint.Diagnostics.HasAnyErrors() Then + moduleBeingBuilt.SetPEEntryPoint(entryPoint.MethodSymbol, diagnostics) + Else + Return False + End If + End If Else ' start generating PDB checksums if we need to emit PDBs If (emittingPdb OrElse moduleBuilder.EmitOptions.InstrumentationKinds.Contains(InstrumentationKind.TestCoverage)) AndAlso diff --git a/src/Compilers/VisualBasic/Portable/Emit/NamedTypeReference.vb b/src/Compilers/VisualBasic/Portable/Emit/NamedTypeReference.vb index 30f4422a89728..81e2608acb954 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/NamedTypeReference.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/NamedTypeReference.vb @@ -123,12 +123,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Public NotOverridable Overrides Function Equals(obj As Object) As Boolean ' It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - Throw Roslyn.Utilities.ExceptionUtilities.Unreachable + Throw ExceptionUtilities.Unreachable End Function Public NotOverridable Overrides Function GetHashCode() As Integer ' It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - Throw Roslyn.Utilities.ExceptionUtilities.Unreachable + Throw ExceptionUtilities.Unreachable End Function End Class End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb b/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb index c8a52432fcef3..ea1f4b7b63046 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb @@ -715,7 +715,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Private Shared Sub GetDocumentsForMethodsAndNestedTypes(documentList As PooledHashSet(Of Cci.DebugSourceDocument), typesToProcess As ArrayBuilder(Of Cci.ITypeDefinition), context As EmitContext) - ' Temporarily disable assert to unblock getting net8.0 teststing re-nabled on Unix. Will + ' Temporarily disable assert to unblock getting net8.0 testing re-enabled on Unix. Will ' remove this shortly. ' https://github.com/dotnet/roslyn/issues/71571 ' Debug.Assert(Not context.MetadataOnly) diff --git a/src/Compilers/VisualBasic/Portable/Emit/ParameterTypeInformation.vb b/src/Compilers/VisualBasic/Portable/Emit/ParameterTypeInformation.vb index 4f3ea0aed9844..dadb28702f577 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/ParameterTypeInformation.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/ParameterTypeInformation.vb @@ -50,12 +50,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Public Overrides Function Equals(obj As Object) As Boolean ' It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - Throw Roslyn.Utilities.ExceptionUtilities.Unreachable + Throw ExceptionUtilities.Unreachable End Function Public Overrides Function GetHashCode() As Integer ' It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - Throw Roslyn.Utilities.ExceptionUtilities.Unreachable + Throw ExceptionUtilities.Unreachable End Function End Class End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Emit/SymbolAdapter.vb b/src/Compilers/VisualBasic/Portable/Emit/SymbolAdapter.vb index c7c9551f017da..24f1d61b76320 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/SymbolAdapter.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/SymbolAdapter.vb @@ -154,12 +154,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Public NotOverridable Overrides Function Equals(obj As Object) As Boolean ' It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - Throw Roslyn.Utilities.ExceptionUtilities.Unreachable + Throw ExceptionUtilities.Unreachable End Function Public NotOverridable Overrides Function GetHashCode() As Integer ' It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - Throw Roslyn.Utilities.ExceptionUtilities.Unreachable + Throw ExceptionUtilities.Unreachable End Function diff --git a/src/Compilers/VisualBasic/Portable/Emit/TypeMemberReference.vb b/src/Compilers/VisualBasic/Portable/Emit/TypeMemberReference.vb index e53016af2ca34..0071a89ee6041 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/TypeMemberReference.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/TypeMemberReference.vb @@ -42,12 +42,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Public NotOverridable Overrides Function Equals(obj As Object) As Boolean ' It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - Throw Roslyn.Utilities.ExceptionUtilities.Unreachable + Throw ExceptionUtilities.Unreachable End Function Public NotOverridable Overrides Function GetHashCode() As Integer ' It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - Throw Roslyn.Utilities.ExceptionUtilities.Unreachable + Throw ExceptionUtilities.Unreachable End Function End Class End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Errors/ErrorFacts.vb b/src/Compilers/VisualBasic/Portable/Errors/ErrorFacts.vb index 0ceb29c88e20a..ca8fcd8f48918 100644 --- a/src/Compilers/VisualBasic/Portable/Errors/ErrorFacts.vb +++ b/src/Compilers/VisualBasic/Portable/Errors/ErrorFacts.vb @@ -21,6 +21,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ERRID.ERR_CannotGotoNonScopeBlocksWithClosure, ERRID.ERR_SymbolDefinedInAssembly ' Update src\Features\VisualBasic\Portable\Diagnostics\LanguageServer\VisualBasicLspBuildOnlyDiagnostics.vb + ' and TestIsBuildOnlyDiagnostic in src\Compilers\VisualBasic\Test\Semantic\Diagnostics\DiagnosticTests.vb ' whenever new values are added here. Return True Case ERRID.Void, diff --git a/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb b/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb index c600c952fafeb..0e573eaa217bd 100644 --- a/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb +++ b/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb @@ -594,6 +594,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Get End Property + Public Overrides ReadOnly Property ERR_DataSectionStringLiteralHashCollision As Integer + Get + Throw ExceptionUtilities.Unreachable + End Get + End Property + ' Generators Public Overrides ReadOnly Property WRN_GeneratorFailedDuringInitialization As Integer Get diff --git a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory.vb b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory.vb index 3d6408f888fcf..89ce274086a30 100644 --- a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory.vb +++ b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory.vb @@ -4,6 +4,7 @@ Imports System.Collections.Concurrent Imports System.Collections.Immutable +Imports System.Threading Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Symbols @@ -43,9 +44,9 @@ Namespace Microsoft.CodeAnalysis.Operations End If If _lazyPlaceholderToParentMap Is Nothing Then - Threading.Interlocked.CompareExchange(_lazyPlaceholderToParentMap, - New ConcurrentDictionary(Of BoundValuePlaceholderBase, BoundNode)(concurrencyLevel:=2, capacity:=10, comparer:=ReferenceEqualityComparer.Instance), - Nothing) + Interlocked.CompareExchange(_lazyPlaceholderToParentMap, + New ConcurrentDictionary(Of BoundValuePlaceholderBase, BoundNode)(concurrencyLevel:=2, capacity:=10, comparer:=ReferenceEqualityComparer.Instance), + Nothing) End If Dim knownParent = _lazyPlaceholderToParentMap.GetOrAdd(placeholderOpt, parent) @@ -445,7 +446,7 @@ Namespace Microsoft.CodeAnalysis.Operations If(boundCall.ReceiverOpt?.Kind <> BoundKind.MyClassReference, False) Dim boundReceiver As BoundExpression = If(boundCall.ReceiverOpt, boundCall.MethodGroupOpt?.ReceiverOpt) - Dim receiver as IOperation = CreateReceiverOperation(boundReceiver, targetMethod) + Dim receiver As IOperation = CreateReceiverOperation(boundReceiver, targetMethod) Dim arguments As ImmutableArray(Of IArgumentOperation) = DeriveArguments(boundCall) Dim syntax As SyntaxNode = boundCall.Syntax @@ -471,7 +472,7 @@ Namespace Microsoft.CodeAnalysis.Operations End Function Private Function CreateBoundArrayAccessOperation(boundArrayAccess As BoundArrayAccess) As IArrayElementReferenceOperation - Dim arrayReference as IOperation = Create(boundArrayAccess.Expression) + Dim arrayReference As IOperation = Create(boundArrayAccess.Expression) Dim indices = CreateFromArray(Of BoundExpression, IOperation)(boundArrayAccess.Indices) Dim syntax As SyntaxNode = boundArrayAccess.Syntax Dim type As ITypeSymbol = boundArrayAccess.Type @@ -819,7 +820,7 @@ Namespace Microsoft.CodeAnalysis.Operations Debug.Assert(boundObjectCreationExpression.ConstructorOpt IsNot Nothing OrElse boundObjectCreationExpression.Arguments.IsEmpty()) Dim constructor As IMethodSymbol = boundObjectCreationExpression.ConstructorOpt Dim initializer As IObjectOrCollectionInitializerOperation = DirectCast(Create(boundObjectCreationExpression.InitializerOpt), IObjectOrCollectionInitializerOperation) - Dim arguments as ImmutableArray(Of IArgumentOperation) = DeriveArguments(boundObjectCreationExpression) + Dim arguments As ImmutableArray(Of IArgumentOperation) = DeriveArguments(boundObjectCreationExpression) Dim syntax As SyntaxNode = boundObjectCreationExpression.Syntax Dim type As ITypeSymbol = boundObjectCreationExpression.Type @@ -881,7 +882,7 @@ Namespace Microsoft.CodeAnalysis.Operations Dim instance As IOperation = CreateReceiverOperation( If(boundPropertyAccess.ReceiverOpt, boundPropertyAccess.PropertyGroupOpt?.ReceiverOpt), [property]) - Dim arguments as ImmutableArray(Of IArgumentOperation) = DeriveArguments(boundPropertyAccess) + Dim arguments As ImmutableArray(Of IArgumentOperation) = DeriveArguments(boundPropertyAccess) Dim syntax As SyntaxNode = boundPropertyAccess.Syntax Dim type As ITypeSymbol = boundPropertyAccess.Type @@ -1058,9 +1059,9 @@ Namespace Microsoft.CodeAnalysis.Operations End Function Private Function CreateBoundIfStatementOperation(boundIfStatement As BoundIfStatement) As IConditionalOperation - Dim condition as IOperation = Create(boundIfStatement.Condition) - Dim whenTrue as IOperation = Create(boundIfStatement.Consequence) - Dim whenFalse as IOperation = Create(boundIfStatement.AlternativeOpt) + Dim condition As IOperation = Create(boundIfStatement.Condition) + Dim whenTrue As IOperation = Create(boundIfStatement.Consequence) + Dim whenFalse As IOperation = Create(boundIfStatement.AlternativeOpt) Dim syntax As SyntaxNode = boundIfStatement.Syntax Dim type As ITypeSymbol = Nothing Dim constantValue As ConstantValue = Nothing @@ -1281,7 +1282,7 @@ Namespace Microsoft.CodeAnalysis.Operations End Function Private Function CreateBoundCatchBlockOperation(boundCatchBlock As BoundCatchBlock) As ICatchClauseOperation - Dim exceptionDeclarationOrExpression as IOperation = CreateBoundCatchBlockExceptionDeclarationOrExpression(boundCatchBlock) + Dim exceptionDeclarationOrExpression As IOperation = CreateBoundCatchBlockExceptionDeclarationOrExpression(boundCatchBlock) Dim filter As IOperation = Create(boundCatchBlock.ExceptionFilterOpt) Dim handler As IBlockOperation = DirectCast(Create(boundCatchBlock.Body), IBlockOperation) Dim exceptionType As ITypeSymbol = If(boundCatchBlock.ExceptionSourceOpt?.Type, DirectCast(_semanticModel.Compilation, VisualBasicCompilation).GetWellKnownType(WellKnownType.System_Exception)) @@ -1417,8 +1418,8 @@ Namespace Microsoft.CodeAnalysis.Operations DirectCast(_semanticModel.Compilation.GetSpecialType(SpecialType.System_Boolean), TypeSymbol), SynthesizedLocalKind.LockTaken, syntaxOpt:=boundSyncLockStatement.LockExpression.Syntax)) - Dim lockedValue as IOperation = Create(boundSyncLockStatement.LockExpression) - Dim body as IOperation = Create(boundSyncLockStatement.Body) + Dim lockedValue As IOperation = Create(boundSyncLockStatement.LockExpression) + Dim body As IOperation = Create(boundSyncLockStatement.Body) Dim syntax As SyntaxNode = boundSyncLockStatement.Syntax Dim isImplicit As Boolean = boundSyncLockStatement.WasCompilerGenerated Return New LockOperation(lockedValue, body, lockTakenSymbol, _semanticModel, syntax, isImplicit) @@ -1664,7 +1665,7 @@ Namespace Microsoft.CodeAnalysis.Operations GetSpecialTypeMember(SpecialMember.System_Nullable_T_GetValueOrDefault), MethodSymbol) If method IsNot Nothing Then - Dim receiver as IOperation = CreateReceiverOperation(boundNullableIsTrueOperator.Operand, method) + Dim receiver As IOperation = CreateReceiverOperation(boundNullableIsTrueOperator.Operand, method) Return New InvocationOperation(method.AsMember(DirectCast(boundNullableIsTrueOperator.Operand.Type, NamedTypeSymbol)), constrainedToType:=Nothing, receiver, isVirtual:=False, diff --git a/src/Compilers/VisualBasic/Portable/PublicAPI.Shipped.txt b/src/Compilers/VisualBasic/Portable/PublicAPI.Shipped.txt index d84bb8398f872..52db4e3c26a29 100644 --- a/src/Compilers/VisualBasic/Portable/PublicAPI.Shipped.txt +++ b/src/Compilers/VisualBasic/Portable/PublicAPI.Shipped.txt @@ -68,6 +68,7 @@ Microsoft.CodeAnalysis.VisualBasic.LanguageVersion.VisualBasic15_3 = 1503 -> Mic Microsoft.CodeAnalysis.VisualBasic.LanguageVersion.VisualBasic15_5 = 1505 -> Microsoft.CodeAnalysis.VisualBasic.LanguageVersion Microsoft.CodeAnalysis.VisualBasic.LanguageVersion.VisualBasic16 = 1600 -> Microsoft.CodeAnalysis.VisualBasic.LanguageVersion Microsoft.CodeAnalysis.VisualBasic.LanguageVersion.VisualBasic16_9 = 1609 -> Microsoft.CodeAnalysis.VisualBasic.LanguageVersion +Microsoft.CodeAnalysis.VisualBasic.LanguageVersion.VisualBasic17_13 = 1713 -> Microsoft.CodeAnalysis.VisualBasic.LanguageVersion Microsoft.CodeAnalysis.VisualBasic.LanguageVersion.VisualBasic9 = 9 -> Microsoft.CodeAnalysis.VisualBasic.LanguageVersion Microsoft.CodeAnalysis.VisualBasic.LanguageVersionFacts Microsoft.CodeAnalysis.VisualBasic.LanguageVersionFacts.MapSpecifiedToEffectiveVersion(version As Microsoft.CodeAnalysis.VisualBasic.LanguageVersion) -> Microsoft.CodeAnalysis.VisualBasic.LanguageVersion diff --git a/src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt b/src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt index 360164d8fcc64..8b137891791fe 100644 --- a/src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt @@ -1 +1 @@ -Microsoft.CodeAnalysis.VisualBasic.LanguageVersion.VisualBasic17_13 = 1713 -> Microsoft.CodeAnalysis.VisualBasic.LanguageVersion + diff --git a/src/Compilers/VisualBasic/Portable/Symbols/EventSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/EventSymbol.vb index f0e41198bddf3..b4bf4b88f4d5e 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/EventSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/EventSymbol.vb @@ -323,6 +323,27 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Private ReadOnly Property IEventSymbol_PartialDefinitionPart As IEventSymbol Implements IEventSymbol.PartialDefinitionPart + Get + ' Feature not supported in VB + Return Nothing + End Get + End Property + + Private ReadOnly Property IEventSymbol_PartialImplementationPart As IEventSymbol Implements IEventSymbol.PartialImplementationPart + Get + ' Feature not supported in VB + Return Nothing + End Get + End Property + + Private ReadOnly Property IEventSymbol_IsPartialDefinition As Boolean Implements IEventSymbol.IsPartialDefinition + Get + ' Feature not supported in VB + Return False + End Get + End Property + Public Overrides Sub Accept(visitor As SymbolVisitor) visitor.VisitEvent(Me) End Sub diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEPropertySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEPropertySymbol.vb index 5c7571f2bc81b..0264bc6c8e9e2 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEPropertySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEPropertySymbol.vb @@ -4,14 +4,14 @@ Imports System.Collections.Immutable Imports System.Globalization -Imports System.Threading Imports System.Reflection Imports System.Reflection.Metadata +Imports System.Reflection.Metadata.Ecma335 +Imports System.Runtime.CompilerServices +Imports System.Threading Imports Microsoft.Cci Imports Microsoft.CodeAnalysis.PooledObjects -Imports System.Reflection.Metadata.Ecma335 Imports Microsoft.CodeAnalysis.VisualBasic.Emit -Imports System.Runtime.CompilerServices Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE @@ -270,7 +270,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE ''' Friend Sub SetIsWithEvents(value As Boolean) Dim newValue = If(value, ThreeState.True, ThreeState.False) - Dim origValue = Threading.Interlocked.CompareExchange(Me._isWithEvents, newValue, ThreeState.Unknown) + Dim origValue = Interlocked.CompareExchange(Me._isWithEvents, newValue, ThreeState.Unknown) Debug.Assert(origValue = ThreeState.Unknown OrElse origValue = newValue, "Tried changing already known IsWithEvent value.") End Sub diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingSymbolTranslator.vb b/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingSymbolTranslator.vb index 6c0c7d59ddfda..3ff5fc6e14437 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingSymbolTranslator.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingSymbolTranslator.vb @@ -3,15 +3,12 @@ ' See the LICENSE file in the project root for more information. Imports System.Collections.Concurrent -Imports System.Collections.Generic Imports System.Collections.Immutable -Imports System.Collections.ObjectModel +Imports System.Threading Imports Microsoft.Cci Imports Microsoft.CodeAnalysis.PooledObjects -Imports Microsoft.CodeAnalysis.Text -Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Imports Microsoft.CodeAnalysis.VisualBasic.Symbols -Imports Microsoft.CodeAnalysis.VisualBasic.Syntax +Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Retargeting @@ -649,7 +646,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Retargeting Dim newTypeModifiers = RetargetModifiers(oldTypeModifiers, modifiersHaveChanged) Dim newRefModifiers = RetargetModifiers(oldRefModifiers, modifiersHaveChanged) - Threading.Interlocked.CompareExchange(lazyCustomModifiers, CustomModifiersTuple.Create(newTypeModifiers, newRefModifiers), Nothing) + Interlocked.CompareExchange(lazyCustomModifiers, CustomModifiersTuple.Create(newTypeModifiers, newRefModifiers), Nothing) End If Return lazyCustomModifiers diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceNamedTypeSymbol_ComClass.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceNamedTypeSymbol_ComClass.vb index 16d84b989c8db..eef1641c6bcca 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceNamedTypeSymbol_ComClass.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceNamedTypeSymbol_ComClass.vb @@ -4,6 +4,7 @@ Imports System.Collections.Immutable Imports System.Runtime.InteropServices +Imports System.Threading Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols @@ -763,7 +764,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub GenerateDeclarationErrors(cancellationToken As Threading.CancellationToken) + Friend Overrides Sub GenerateDeclarationErrors(cancellationToken As CancellationToken) Throw ExceptionUtilities.Unreachable End Sub diff --git a/src/Compilers/VisualBasic/Portable/Symbols/TypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/TypeSymbol.vb index c6f532857bfda..4398a64648fb6 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/TypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/TypeSymbol.vb @@ -783,5 +783,16 @@ Done: Return Me End Function + Public ReadOnly Property IsExtension As Boolean Implements ITypeSymbol.IsExtension + Get + Return False + End Get + End Property + + Public ReadOnly Property ExtensionParameter As IParameterSymbol Implements ITypeSymbol.ExtensionParameter + Get + Return Nothing + End Get + End Property End Class End Namespace diff --git a/src/Compilers/VisualBasic/Portable/VBResources.resx b/src/Compilers/VisualBasic/Portable/VBResources.resx index 81ec12c060ab6..c153096c40ad6 100644 --- a/src/Compilers/VisualBasic/Portable/VBResources.resx +++ b/src/Compilers/VisualBasic/Portable/VBResources.resx @@ -5627,10 +5627,10 @@ The loaded assembly references .NET Framework, which is not supported. - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - The analyzer assembly references a newer version of the compiler than the currently running version. + Analyzer assembly cannot be used because it references a newer version of the compiler than the currently running version. assigning to or passing 'ByRef' properties with init-only setters diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.cs.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.cs.xlf index a38b5a90158cd..cd99d16dde1e7 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.cs.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.cs.xlf @@ -19,12 +19,12 @@ Cannot use 'OverloadResolutionPriorityAttribute' on this member. - Cannot use 'OverloadResolutionPriorityAttribute' on this member. + U tohoto členu nelze použít OverloadResolutionPriorityAttribute. Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. - Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + U přepisujících členů nelze použít OverloadResolutionPriorityAttribute. @@ -54,7 +54,7 @@ Cannot update '{0}'; attribute '{1}' is missing. - Cannot update '{0}'; attribute '{1}' is missing. + Nelze aktualizovat {0}; chybí atribut {1}. @@ -109,7 +109,7 @@ The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type - The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + Typ Microsoft.CodeAnalysis.EmbeddedAttribute musí být neobecný, Friend, NotInheritable, musí mít veřejný konstruktor bez parametrů, dědit z System.Attribute a být možné ho použít pro libovolný typ. @@ -134,7 +134,7 @@ The type name '{0}' is reserved to be used by the compiler. - The type name '{0}' is reserved to be used by the compiler. + Název typu {0} je vyhrazený pro použití kompilátorem. @@ -149,7 +149,7 @@ Type argument '{0}' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as type parameter '{1}'. - Type argument '{0}' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as type parameter '{1}'. + Argument typu {0} musí být typ, který nemůže mít hodnotu null, ani nesmí v žádné úrovni vnoření obsahovat pole, které by ji povolovalo, aby se dal použít jako parametr typu {1}. @@ -179,7 +179,7 @@ overload resolution priority - overload resolution priority + priorita řešení přetížení @@ -189,7 +189,7 @@ recognizing 'unmanaged' constraint - recognizing 'unmanaged' constraint + rozpoznává se omezení unmanaged. @@ -629,13 +629,13 @@ - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - Sestavení analyzátoru {0} odkazuje na verzi {1} kompilátoru, která je novější než aktuálně spuštěná verze {2}. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + Sestavení analyzátoru {0} odkazuje na verzi {1} kompilátoru, která je novější než aktuálně spuštěná verze {2}. - The analyzer assembly references a newer version of the compiler than the currently running version. - Sestavení analyzátoru odkazuje na novější verzi kompilátoru, než je aktuálně spuštěná verze. + Analyzer assembly cannot be used because it references a newer version of the compiler than the currently running version. + Sestavení analyzátoru odkazuje na novější verzi kompilátoru, než je aktuálně spuštěná verze. @@ -680,12 +680,12 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + {0} slouží jen pro účely vyhodnocení a v budoucích aktualizacích může dojít ke změně nebo odebrání: {1}. Type is for evaluation purposes only and is subject to change or removal in future updates. - Type is for evaluation purposes only and is subject to change or removal in future updates. + Typ slouží jen pro účely vyhodnocení a v budoucích aktualizacích může dojít ke změnám nebo odebrání. @@ -9353,7 +9353,7 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates. + {0} slouží jen pro účely vyhodnocení a v budoucích aktualizacích může dojít ke změně nebo odebrání. @@ -9363,7 +9363,7 @@ Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Informace o ladění metody {0} (token 0x{1:X8}) ze sestavení {2} nelze přečíst: {3} diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.de.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.de.xlf index 5f02f3563fc8d..f52b27726a1a1 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.de.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.de.xlf @@ -19,12 +19,12 @@ Cannot use 'OverloadResolutionPriorityAttribute' on this member. - Cannot use 'OverloadResolutionPriorityAttribute' on this member. + „OverloadResolutionPriorityAttribute“ kann für dieses Element nicht verwendet werden. Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. - Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + „OverloadResolutionPriorityAttribute“ kann nicht für ein überschriebenes Element verwendet werden. @@ -54,7 +54,7 @@ Cannot update '{0}'; attribute '{1}' is missing. - Cannot update '{0}'; attribute '{1}' is missing. + "{0}" kann nicht aktualisiert werden. Das Attribut "{1}" fehlt. @@ -109,7 +109,7 @@ The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type - The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + Der Typ "Microsoft.CodeAnalysis.EmbeddedAttribute" muss nicht generisch sein, Friend, NotInheritable, einen öffentlichen parameterlosen Konstruktor aufweisen, von System.Attribute erben und auf jeden Typ angewendet werden können. @@ -134,7 +134,7 @@ The type name '{0}' is reserved to be used by the compiler. - The type name '{0}' is reserved to be used by the compiler. + Der Typname "{0}" ist für die Verwendung durch den Compiler reserviert. @@ -149,7 +149,7 @@ Type argument '{0}' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as type parameter '{1}'. - Type argument '{0}' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as type parameter '{1}'. + Das Typargument „{0}“ muss, ebenso wie sämtliche Felder auf jeder Schachtelungsebene, ein Non-Nullable-Typ sein, damit er als Typparameter „{1}“ verwendet werden kann. @@ -179,7 +179,7 @@ overload resolution priority - overload resolution priority + Priorität der Überladungsauflösung @@ -189,7 +189,7 @@ recognizing 'unmanaged' constraint - recognizing 'unmanaged' constraint + "unmanaged"-Einschränkung wird erkannt @@ -629,13 +629,13 @@ - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - Die Analyzerassembly „{0}“ verweist auf Version „{1}“ des Compilers, die neuer ist als die aktuell ausgeführte Version „{2}“. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + Die Analyzerassembly „{0}“ verweist auf Version „{1}“ des Compilers, die neuer ist als die aktuell ausgeführte Version „{2}“. - The analyzer assembly references a newer version of the compiler than the currently running version. - Die Analyzerassembly verweist auf eine neuere Version des Compilers als die derzeit ausgeführte Version. + Analyzer assembly cannot be used because it references a newer version of the compiler than the currently running version. + Die Analyzerassembly verweist auf eine neuere Version des Compilers als die derzeit ausgeführte Version. @@ -680,12 +680,12 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + „{0}“ dient nur zu Evaluierungszwecken und kann in zukünftigen Updates geändert oder entfernt werden: „{1}“. Type is for evaluation purposes only and is subject to change or removal in future updates. - Type is for evaluation purposes only and is subject to change or removal in future updates. + Der Typ dient nur zu Testzwecken und kann in zukünftigen Aktualisierungen geändert oder entfernt werden. @@ -9353,7 +9353,7 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates. + "{0}" dient nur zu Testzwecken und kann in zukünftigen Aktualisierungen geändert oder entfernt werden. @@ -9363,7 +9363,7 @@ Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Die Debuginformationen der Methode „{0}“ (Token 0x{1:X8}) können nicht aus der Assembly „{2}“ gelesen werden: {3} diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.es.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.es.xlf index ea062b2aee2ed..be3274c2999a9 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.es.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.es.xlf @@ -19,12 +19,12 @@ Cannot use 'OverloadResolutionPriorityAttribute' on this member. - Cannot use 'OverloadResolutionPriorityAttribute' on this member. + No se puede usar "OverloadResolutionPriorityAttribute" en este miembro. Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. - Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + No se puede usar "OverloadResolutionPriorityAttribute" en un miembro de reemplazo. @@ -54,7 +54,7 @@ Cannot update '{0}'; attribute '{1}' is missing. - Cannot update '{0}'; attribute '{1}' is missing. + No se puede actualizar '{0}'; falta el atributo '{1}'. @@ -109,7 +109,7 @@ The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type - The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + El tipo 'Microsoft.CodeAnalysis.EmbeddedAttribute' debe ser no genérico, Friend, NotInheritable, tener un constructor sin parámetros Public, heredar de System.Attribute y poder aplicarse a cualquier tipo @@ -134,7 +134,7 @@ The type name '{0}' is reserved to be used by the compiler. - The type name '{0}' is reserved to be used by the compiler. + El nombre de tipo "{0}" está reservado para uso del compilador. @@ -149,7 +149,7 @@ Type argument '{0}' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as type parameter '{1}'. - Type argument '{0}' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as type parameter '{1}'. + El argumento de tipo '{0}' debe ser un tipo de valor que no acepta valores NULL, junto con todos los campos en cualquier nivel de anidamiento, para usarlo como parámetro de tipo '{1}'. @@ -179,7 +179,7 @@ overload resolution priority - overload resolution priority + prioridad de resolución de sobrecarga @@ -189,7 +189,7 @@ recognizing 'unmanaged' constraint - recognizing 'unmanaged' constraint + reconocimiento de la restricción 'unmanaged' @@ -629,13 +629,13 @@ - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - El ensamblado del analizador ”{0}” hace referencia a la versión ”{1}” del compilador, que es más reciente que la versión "{2}" que se está ejecutando actualmente. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + El ensamblado del analizador ”{0}” hace referencia a la versión ”{1}” del compilador, que es más reciente que la versión "{2}" que se está ejecutando actualmente. - The analyzer assembly references a newer version of the compiler than the currently running version. - El ensamblado del analizador hace referencia a una versión más reciente del compilador que la versión que se está ejecutando actualmente. + Analyzer assembly cannot be used because it references a newer version of the compiler than the currently running version. + El ensamblado del analizador hace referencia a una versión más reciente del compilador que la versión que se está ejecutando actualmente. @@ -680,12 +680,12 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + ''{0}'' es solo para fines de evaluación y está sujeto a cambios o eliminaciones en futuras actualizaciones: ''{1}''. Type is for evaluation purposes only and is subject to change or removal in future updates. - Type is for evaluation purposes only and is subject to change or removal in future updates. + Este tipo se incluye solo con fines de evaluación y está sujeto a cambios o a que se elimine en próximas actualizaciones. @@ -9353,7 +9353,7 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates. + "{0}" se incluye con fines de evaluación y está sujeto a cambios o a que se elimine en próximas actualizaciones. @@ -9363,7 +9363,7 @@ Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + No se puede leer la información de depuración del método '{0}' (token 0x{1:X8}) del ensamblado '{2}': {3} diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.fr.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.fr.xlf index ba3f55604cbcf..4b05beae4f487 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.fr.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.fr.xlf @@ -19,12 +19,12 @@ Cannot use 'OverloadResolutionPriorityAttribute' on this member. - Cannot use 'OverloadResolutionPriorityAttribute' on this member. + Impossible d'utiliser « OverloadResolutionPriorityAttribute » sur ce membre. Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. - Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + Impossible d'utiliser « OverloadResolutionPriorityAttribute » sur un membre de substitution. @@ -54,7 +54,7 @@ Cannot update '{0}'; attribute '{1}' is missing. - Cannot update '{0}'; attribute '{1}' is missing. + Impossible de mettre à jour '{0}' ; l'attribut '{1}' est manquant. @@ -109,7 +109,7 @@ The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type - The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + Le type 'Microsoft.CodeAnalysis.EmbeddedAttribute' doit être non générique, Friend, NotInheritable, avoir un constructeur sans paramètre public, hériter de System.Attribute et être appliqué à n’importe quel type @@ -134,7 +134,7 @@ The type name '{0}' is reserved to be used by the compiler. - The type name '{0}' is reserved to be used by the compiler. + L'utilisation du nom de type '{0}' est réservée au compilateur. @@ -149,7 +149,7 @@ Type argument '{0}' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as type parameter '{1}'. - Type argument '{0}' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as type parameter '{1}'. + Le type d’argument « {0} » doit être un type valeur non-nullable, ainsi que l’ensemble des champs à tous les niveaux d’imbrication, pour l’utiliser en tant que paramètre de type « {1} ». @@ -179,7 +179,7 @@ overload resolution priority - overload resolution priority + priorité de résolution de surcharge @@ -189,7 +189,7 @@ recognizing 'unmanaged' constraint - recognizing 'unmanaged' constraint + reconnaissance de la contrainte 'unmanaged' @@ -629,13 +629,13 @@ - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - L'assembly d'analyseur '{0}' fait référence à la version '{1}' du compilateur, qui est plus récente que la version en cours d'exécution '{2}'. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + L'assembly d'analyseur '{0}' fait référence à la version '{1}' du compilateur, qui est plus récente que la version en cours d'exécution '{2}'. - The analyzer assembly references a newer version of the compiler than the currently running version. - L'assembly de l'analyseur fait référence à une version plus récente du compilateur que la version en cours d'exécution. + Analyzer assembly cannot be used because it references a newer version of the compiler than the currently running version. + L'assembly de l'analyseur fait référence à une version plus récente du compilateur que la version en cours d'exécution. @@ -680,12 +680,12 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + « {0} » est utilisé à des fins d’évaluation uniquement et est susceptible d’être modifié ou supprimé dans les futures mises à jour : « {1} ». Type is for evaluation purposes only and is subject to change or removal in future updates. - Type is for evaluation purposes only and is subject to change or removal in future updates. + Le type est utilisé à des fins d'évaluation uniquement. Il sera peut-être changé ou supprimé au cours des prochaines mises à jour. @@ -9353,7 +9353,7 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates. + '{0}' est utilisé à des fins d'évaluation uniquement. Il sera peut-être changé ou supprimé au cours des prochaines mises à jour. @@ -9363,7 +9363,7 @@ Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Nous ne pouvons pas lire les informations de débogage de la méthode « {0} » (jeton 0x{1:X8}) dans l'assembly « {2} » : {3} diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.it.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.it.xlf index 2a3716b030aa9..d7659c5a7ee3b 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.it.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.it.xlf @@ -19,12 +19,12 @@ Cannot use 'OverloadResolutionPriorityAttribute' on this member. - Cannot use 'OverloadResolutionPriorityAttribute' on this member. + Non è possibile usare 'OverloadResolutionPriorityAttribute' per questo membro. Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. - Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + Non è possibile usare 'OverloadResolutionPriorityAttribute' in un membro di override. @@ -54,7 +54,7 @@ Cannot update '{0}'; attribute '{1}' is missing. - Cannot update '{0}'; attribute '{1}' is missing. + Non è possibile aggiornare '{0}'. Manca l'attributo '{1}'. @@ -109,7 +109,7 @@ The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type - The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + Il tipo 'Microsoft.CodeAnalysis.EmbeddedAttribute' deve essere non generico, Friend, NotInheritable, avere un costruttore senza parametri Public, ereditare da System.Attribute e poter essere applicato a qualsiasi tipo @@ -134,7 +134,7 @@ The type name '{0}' is reserved to be used by the compiler. - The type name '{0}' is reserved to be used by the compiler. + Il nome di tipo '{0}' è riservato al compilatore. @@ -149,7 +149,7 @@ Type argument '{0}' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as type parameter '{1}'. - Type argument '{0}' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as type parameter '{1}'. + L'argomento di tipo '{0}' deve essere un tipo valore che non ammette i valori Null, unitamente a tutti i campi a ogni livello di annidamento, per poter essere usato come parametro di tipo '{1}'. @@ -179,7 +179,7 @@ overload resolution priority - overload resolution priority + priorità di risoluzione dell'overload @@ -189,7 +189,7 @@ recognizing 'unmanaged' constraint - recognizing 'unmanaged' constraint + riconoscimento del vincolo 'unmanaged' @@ -630,13 +630,13 @@ - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - L'assembly dell'analizzatore '{0}' fa riferimento alla versione '{1}' del compilatore, che è più recente della versione attualmente in esecuzione '{2}'. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + L'assembly dell'analizzatore '{0}' fa riferimento alla versione '{1}' del compilatore, che è più recente della versione attualmente in esecuzione '{2}'. - The analyzer assembly references a newer version of the compiler than the currently running version. - L'assembly dell'analizzatore fa riferimento alla versione del compilatore, che è più recente della versione attualmente in esecuzione. + Analyzer assembly cannot be used because it references a newer version of the compiler than the currently running version. + L'assembly dell'analizzatore fa riferimento alla versione del compilatore, che è più recente della versione attualmente in esecuzione. @@ -681,12 +681,12 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + "{0}" viene usato solo a scopo di valutazione e potrebbe essere modificato o rimosso in aggiornamenti futuri: "{1}". Type is for evaluation purposes only and is subject to change or removal in future updates. - Type is for evaluation purposes only and is subject to change or removal in future updates. + Type viene usato solo a scopo di valutazione e potrebbe essere modificato o rimosso in aggiornamenti futuri. @@ -9354,7 +9354,7 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates. + '{0}' viene usato solo a scopo di valutazione e potrebbe essere modificato o rimosso in aggiornamenti futuri. @@ -9364,7 +9364,7 @@ Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Non è possibile leggere le informazione di debug del metodo '{0}' (token 0x{1:X8}) dall'assembly '{2}': {3} diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ja.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ja.xlf index 28741ebdc70bd..440445efa7967 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ja.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ja.xlf @@ -19,12 +19,12 @@ Cannot use 'OverloadResolutionPriorityAttribute' on this member. - Cannot use 'OverloadResolutionPriorityAttribute' on this member. + このメンバーでは 'OverloadResolutionPriorityAttribute' を使用できません。 Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. - Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + オーバーライドするメンバーに 'OverloadResolutionPriorityAttribute' を使用することはできません。 @@ -54,7 +54,7 @@ Cannot update '{0}'; attribute '{1}' is missing. - Cannot update '{0}'; attribute '{1}' is missing. + '{0}' を更新できません。属性 '{1}' がありません。 @@ -109,7 +109,7 @@ The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type - The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + 型 'Microsoft.CodeAnalysis.EmbeddedAttribute' は非ジェネリック、Friend、NotInheritable、Public パラメーターなしのコンストラクターを持ち、System.Attribute から継承し、任意の型に適用できる必要があります @@ -134,7 +134,7 @@ The type name '{0}' is reserved to be used by the compiler. - The type name '{0}' is reserved to be used by the compiler. + 型名 '{0}' は、コンパイラによる使用のために予約されています。 @@ -149,7 +149,7 @@ Type argument '{0}' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as type parameter '{1}'. - Type argument '{0}' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as type parameter '{1}'. + 型引数 '{0}' を型パラメーター '{1}' として使用するには、入れ子になっているすべてのレベルにおけるすべてのフィールドとともに、null 非許容値の型である必要があります。 @@ -179,7 +179,7 @@ overload resolution priority - overload resolution priority + オーバーロード解決の優先順位 @@ -189,7 +189,7 @@ recognizing 'unmanaged' constraint - recognizing 'unmanaged' constraint + 'unmanaged' 制約を認識しています @@ -631,13 +631,13 @@ - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - アナライザー アセンブリ '{0}' は、コンパイラのバージョン '{1}' を参照しています。これは、現在実行中のバージョン '{2}' よりも新しいバージョンです。 + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + アナライザー アセンブリ '{0}' は、コンパイラのバージョン '{1}' を参照しています。これは、現在実行中のバージョン '{2}' よりも新しいバージョンです。 - The analyzer assembly references a newer version of the compiler than the currently running version. - アナライザー アセンブリが参照しるコンパイラのバージョンは、現在実行中のバージョンよりも新しいです。 + Analyzer assembly cannot be used because it references a newer version of the compiler than the currently running version. + アナライザー アセンブリが参照しるコンパイラのバージョンは、現在実行中のバージョンよりも新しいです。 @@ -682,12 +682,12 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + '{0}' は、評価の目的でのみ提供されています。将来の更新で変更または削除されることがあります: '{1}'。 Type is for evaluation purposes only and is subject to change or removal in future updates. - Type is for evaluation purposes only and is subject to change or removal in future updates. + 型は評価の目的でのみ提供されています。将来の更新で変更または削除されることがあります。 @@ -9355,7 +9355,7 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates. + '{0}' は、評価の目的でのみ提供されています。将来の更新で変更または削除されることがあります。 @@ -9365,7 +9365,7 @@ Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + メソッド '{0}' (トークン 0x{1:X8}) のデバッグ情報をアセンブリ '{2}': {3} から読み取ることができません diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ko.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ko.xlf index 5ff7924c96318..3ccca121c0470 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ko.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ko.xlf @@ -19,12 +19,12 @@ Cannot use 'OverloadResolutionPriorityAttribute' on this member. - Cannot use 'OverloadResolutionPriorityAttribute' on this member. + 이 멤버에는 'OverloadResolutionPriorityAttribute'를 사용할 수 없습니다. Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. - Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + 재정의 멤버에는 'OverloadResolutionPriorityAttribute'를 사용할 수 없습니다. @@ -54,7 +54,7 @@ Cannot update '{0}'; attribute '{1}' is missing. - Cannot update '{0}'; attribute '{1}' is missing. + '{0}'을(를) 업데이트할 수 없습니다. 특성 '{1}'이(가) 없습니다. @@ -109,7 +109,7 @@ The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type - The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + 'Microsoft.CodeAnalysis.EmbeddedAttribute' 형식은 제네릭이 아니어야 하고, Friend, NotInheritable이어야 하며, Public 매개 변수가 없는 생성자를 포함하고, System.Attribute에서 상속하며, 모든 형식에 적용할 수 있어야 합니다. @@ -134,7 +134,7 @@ The type name '{0}' is reserved to be used by the compiler. - The type name '{0}' is reserved to be used by the compiler. + 형식 이름 '{0}'은(는) 컴파일러에서 사용하도록 예약되어 있습니다. @@ -149,7 +149,7 @@ Type argument '{0}' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as type parameter '{1}'. - Type argument '{0}' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as type parameter '{1}'. + 형식 인수 '{0}'은(는) 형식 매개 변수 '{1}'로 사용하려면 모든 중첩 수준의 모든 필드와 함께 null을 허용하지 않는 값 형식이어야 합니다. @@ -179,7 +179,7 @@ overload resolution priority - overload resolution priority + 오버로드 해결 우선 순위 @@ -189,7 +189,7 @@ recognizing 'unmanaged' constraint - recognizing 'unmanaged' constraint + 'unmanaged' 제약 조건을 인식하는 중 @@ -629,13 +629,13 @@ - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - 분석기 어셈블리 '{0}'은(는) 컴파일러의 '{1}' 버전을 참조하며, 이 버전은 현재 실행 중인 버전 '{2}'보다 최신 버전입니다. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + 분석기 어셈블리 '{0}'은(는) 컴파일러의 '{1}' 버전을 참조하며, 이 버전은 현재 실행 중인 버전 '{2}'보다 최신 버전입니다. - The analyzer assembly references a newer version of the compiler than the currently running version. - 분석기 어셈블리는 현재 실행 중인 버전보다 최신 버전의 컴파일러를 참조합니다. + Analyzer assembly cannot be used because it references a newer version of the compiler than the currently running version. + 분석기 어셈블리는 현재 실행 중인 버전보다 최신 버전의 컴파일러를 참조합니다. @@ -680,12 +680,12 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + '{0}'은(는) 평가 목적으로 제공되며, 이후 업데이트에서 변경되거나 제거될 수 있습니다. '{1}'. Type is for evaluation purposes only and is subject to change or removal in future updates. - Type is for evaluation purposes only and is subject to change or removal in future updates. + 형식은 평가 목적으로 제공되며, 이후 업데이트에서 변경되거나 제거될 수 있습니다. @@ -9353,7 +9353,7 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates. + '{0}'은(는) 평가 목적으로 제공되며, 이후 업데이트에서 변경되거나 제거될 수 있습니다. @@ -9363,7 +9363,7 @@ Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + 어셈블리 '{2}'에서 '{0}' 메서드(토큰 0x{1:X8})의 디버그 정보를 읽을 수 없습니다. {3} diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.pl.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.pl.xlf index 3af7eb53af3c1..ea736d6e939fe 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.pl.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.pl.xlf @@ -19,12 +19,12 @@ Cannot use 'OverloadResolutionPriorityAttribute' on this member. - Cannot use 'OverloadResolutionPriorityAttribute' on this member. + Nie można użyć atrybutu "OverloadResolutionPriorityAttribute" w tej składowej. Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. - Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + Nie można użyć atrybutu „OverloadResolutionPriorityAttribute” w zastępującej składowej. @@ -54,7 +54,7 @@ Cannot update '{0}'; attribute '{1}' is missing. - Cannot update '{0}'; attribute '{1}' is missing. + Nie można zaktualizować elementu „{0}”. Brak atrybutu „{1}”. @@ -109,7 +109,7 @@ The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type - The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + Typ "Microsoft.CodeAnalysis.EmbeddedAttribute" nie może być rodzajowy, element Friend, NotInheritable ma konstruktora bez parametrów publicznych, dziedziczy z elementu System.Attribute i może być stosowany do dowolnego typu @@ -134,7 +134,7 @@ The type name '{0}' is reserved to be used by the compiler. - The type name '{0}' is reserved to be used by the compiler. + Nazwa typu „{0}” jest zarezerwowana do użycia przez kompilator. @@ -149,7 +149,7 @@ Type argument '{0}' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as type parameter '{1}'. - Type argument '{0}' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as type parameter '{1}'. + Argument typu „{0}” musi być typem wartości niedopuszczającym wartości null wraz ze wszystkimi polami na dowolnym poziomie zagnieżdżenia, aby można było użyć go jako parametru typu „{1}”. @@ -179,7 +179,7 @@ overload resolution priority - overload resolution priority + priorytet rozwiązywania przeciążenia @@ -189,7 +189,7 @@ recognizing 'unmanaged' constraint - recognizing 'unmanaged' constraint + rozpoznawanie ograniczenia "niezarządzanego" @@ -629,13 +629,13 @@ - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - Zestaw analizatora „{0}” odwołuje się do wersji „{1}” kompilatora, która jest nowsza niż obecnie uruchomiona wersja „{2}”. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + Zestaw analizatora „{0}” odwołuje się do wersji „{1}” kompilatora, która jest nowsza niż obecnie uruchomiona wersja „{2}”. - The analyzer assembly references a newer version of the compiler than the currently running version. - Zestaw analizatora odwołuje się do nowszej wersji kompilatora niż obecnie uruchomiona wersja. + Analyzer assembly cannot be used because it references a newer version of the compiler than the currently running version. + Zestaw analizatora odwołuje się do nowszej wersji kompilatora niż obecnie uruchomiona wersja. @@ -680,12 +680,12 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + Element „{0}” jest przeznaczony wyłącznie do celów ewaluacyjnych i może zostać zmieniony albo usunięty w przyszłych aktualizacjach: „”{1}. Type is for evaluation purposes only and is subject to change or removal in future updates. - Type is for evaluation purposes only and is subject to change or removal in future updates. + Typ jest przeznaczony wyłącznie do celów ewaluacyjnych i może zostać zmieniony albo usunięty w przyszłych aktualizacjach. @@ -9353,7 +9353,7 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates. + 'Element „{0}” jest przeznaczony wyłącznie do celów ewaluacyjnych i może zostać zmieniony albo usunięty w przyszłych aktualizacjach. @@ -9363,7 +9363,7 @@ Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Nie można odczytać informacji debugowania metody „{0}” (token 0x{1:X8}) z zestawu „{2}”: {3} diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.pt-BR.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.pt-BR.xlf index b6f66d5e39910..dd23654acf80a 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.pt-BR.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.pt-BR.xlf @@ -19,12 +19,12 @@ Cannot use 'OverloadResolutionPriorityAttribute' on this member. - Cannot use 'OverloadResolutionPriorityAttribute' on this member. + Não é possível usar 'OverloadResolutionPriorityAttribute' neste membro. Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. - Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + Não é possível usar 'OverloadResolutionPriorityAttribute' em um membro que substitui outro. @@ -54,7 +54,7 @@ Cannot update '{0}'; attribute '{1}' is missing. - Cannot update '{0}'; attribute '{1}' is missing. + Não é possível atualizar '{0}'; o atributo '{1}' está ausente. @@ -109,7 +109,7 @@ The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type - The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + O tipo 'Microsoft.CodeAnalysis.EmbeddedAttribute' deve ser não genérico, Friend, NotInheritable, ter um construtor Public sem parâmetros, herdar de System.Attribute e ser aplicado a qualquer tipo @@ -134,7 +134,7 @@ The type name '{0}' is reserved to be used by the compiler. - The type name '{0}' is reserved to be used by the compiler. + O nome do tipo '{0}' está reservado para ser usado pelo compilador. @@ -149,7 +149,7 @@ Type argument '{0}' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as type parameter '{1}'. - Type argument '{0}' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as type parameter '{1}'. + O argumento de tipo '{0}' deve ser um tipo de valor não anulável, juntamente com todos os campos em qualquer nível de aninhamento, para usá-lo como parâmetro de tipo '{1}'. @@ -179,7 +179,7 @@ overload resolution priority - overload resolution priority + prioridade de resolução de sobrecarga @@ -189,7 +189,7 @@ recognizing 'unmanaged' constraint - recognizing 'unmanaged' constraint + reconhecendo restrição 'unmanaged' @@ -629,13 +629,13 @@ - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - O assembly do analisador '{0}' referencia a versão '{1}' do compilador, que é mais recente que a versão em execução no momento '{2}'. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + O assembly do analisador '{0}' referencia a versão '{1}' do compilador, que é mais recente que a versão em execução no momento '{2}'. - The analyzer assembly references a newer version of the compiler than the currently running version. - O assembly do analisador faz referência a uma versão mais recente do compilador do que a versão em execução no momento. + Analyzer assembly cannot be used because it references a newer version of the compiler than the currently running version. + O assembly do analisador faz referência a uma versão mais recente do compilador do que a versão em execução no momento. @@ -680,12 +680,12 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + '{0}'é apenas para fins de avaliação e está sujeito a alterações ou remoção em atualizações futuras.'{1}'. Type is for evaluation purposes only and is subject to change or removal in future updates. - Type is for evaluation purposes only and is subject to change or removal in future updates. + O tipo destina-se somente para fins de avaliação e está sujeito a alterações ou remoções em atualizações futuras. @@ -9353,7 +9353,7 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates. + '{0}' é para fins de avaliação somente e está sujeito a alterações ou remoções em atualizações futuras. @@ -9363,7 +9363,7 @@ Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Não é possível ler as informações de depuração do método '{0}' (token 0x{1:X8}) do assembly '{2}': {3} diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ru.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ru.xlf index 6fd91383a942e..075a143a0723a 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ru.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ru.xlf @@ -19,12 +19,12 @@ Cannot use 'OverloadResolutionPriorityAttribute' on this member. - Cannot use 'OverloadResolutionPriorityAttribute' on this member. + Невозможно использовать "OverloadResolutionPriorityAttribute" с этим членом. Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. - Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + Невозможно использовать "OverloadResolutionPriorityAttribute" с переопределяемым членом. @@ -54,7 +54,7 @@ Cannot update '{0}'; attribute '{1}' is missing. - Cannot update '{0}'; attribute '{1}' is missing. + Невозможно обновить "{0}"; нет атрибута "{1}". @@ -109,7 +109,7 @@ The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type - The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + Тип "Microsoft.CodeAnalysis.EmbeddedAttribute" должен быть неуниверсанным, friend, NotInheritable, иметь конструктор Public без параметров, наследовать от System.Attribute и иметь возможность применяться к любому типу @@ -134,7 +134,7 @@ The type name '{0}' is reserved to be used by the compiler. - The type name '{0}' is reserved to be used by the compiler. + Имя типа "{0}" зарезервировано для использования компилятором. @@ -149,7 +149,7 @@ Type argument '{0}' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as type parameter '{1}'. - Type argument '{0}' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as type parameter '{1}'. + Чтобы аргумент типа "{0}" можно было использовать как параметр типа "{1}", он должен быть типом значения, который, как и все поля на любом уровне вложения, не допускает значения NULL. @@ -179,7 +179,7 @@ overload resolution priority - overload resolution priority + приоритет разрешения перегрузки @@ -189,7 +189,7 @@ recognizing 'unmanaged' constraint - recognizing 'unmanaged' constraint + распознавание ограничения "unmanaged" @@ -629,13 +629,13 @@ optionstrict[+|-] Принудительное применени - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - Сборка анализатора "{0}" ссылается на версию "{1}" компилятора, являющуюся более новой, чем версия "{2}". + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + Сборка анализатора "{0}" ссылается на версию "{1}" компилятора, являющуюся более новой, чем версия "{2}". - The analyzer assembly references a newer version of the compiler than the currently running version. - Сборка анализатора ссылается на более новую версию компилятора, чем установленная сейчас. + Analyzer assembly cannot be used because it references a newer version of the compiler than the currently running version. + Сборка анализатора ссылается на более новую версию компилятора, чем установленная сейчас. @@ -680,12 +680,12 @@ optionstrict[+|-] Принудительное применени '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + "{0}" предназначен только для оценки и может быть изменен или удален в будущих обновлениях: "{1}". Type is for evaluation purposes only and is subject to change or removal in future updates. - Type is for evaluation purposes only and is subject to change or removal in future updates. + Тип предназначен только для оценки и может быть изменен или удален в будущих обновлениях. @@ -9353,7 +9353,7 @@ optionstrict[+|-] Принудительное применени '{0}' is for evaluation purposes only and is subject to change or removal in future updates. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates. + "{0}" предназначен только для оценки и может быть изменен или удален в будущих обновлениях. @@ -9363,7 +9363,7 @@ optionstrict[+|-] Принудительное применени Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Не удается прочитать отладочную информацию метода "{0}"' (токен 0x{1:X8}) из сборки "{2}": {3} diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.tr.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.tr.xlf index 51b981a52f571..6af7446cd9a65 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.tr.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.tr.xlf @@ -19,12 +19,12 @@ Cannot use 'OverloadResolutionPriorityAttribute' on this member. - Cannot use 'OverloadResolutionPriorityAttribute' on this member. + Bu üyede 'OverloadResolutionPriorityAttribute' kullanılamaz. Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. - Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + Geçersiz kılan bir üyede 'OverloadResolutionPriorityAttribute' kullanılamaz. @@ -54,7 +54,7 @@ Cannot update '{0}'; attribute '{1}' is missing. - Cannot update '{0}'; attribute '{1}' is missing. + '{0}' güncelleştirilemiyor; '{1}' özniteliği eksik. @@ -109,7 +109,7 @@ The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type - The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + 'Microsoft.CodeAnalysis.EmbeddedAttribute' türü genel olmayan, Friend, NotInheritable, Public parametresiz oluşturucusu, System.Attribute'tan devralınmalıdır ve herhangi bir türe uygulanmalıdır @@ -134,7 +134,7 @@ The type name '{0}' is reserved to be used by the compiler. - The type name '{0}' is reserved to be used by the compiler. + '{0}' tür adı, derleyici tarafından kullanılmak üzere ayrılmıştır. @@ -149,7 +149,7 @@ Type argument '{0}' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as type parameter '{1}'. - Type argument '{0}' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as type parameter '{1}'. + '{1}' tür parametresi olarak kullanabilmek için '{0}' tür bağımsız değişkeninin, herhangi bir iç içe yerleştirme düzeyindeki tüm alanlarla birlikte null atanamaz bir değer türü olması gerekir. @@ -179,7 +179,7 @@ overload resolution priority - overload resolution priority + aşırı yükleme çözümlemesi önceliği @@ -189,7 +189,7 @@ recognizing 'unmanaged' constraint - recognizing 'unmanaged' constraint + 'unmanaged' kısıtlaması tanınıyor @@ -630,13 +630,13 @@ - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - '{0}' çözümleyici bütünleştirilmiş kodu, derleyicinin şu anda çalışan '{2}' sürümünden daha yeni olan '{1}' sürümüne başvurur. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + '{0}' çözümleyici bütünleştirilmiş kodu, derleyicinin şu anda çalışan '{2}' sürümünden daha yeni olan '{1}' sürümüne başvurur. - The analyzer assembly references a newer version of the compiler than the currently running version. - Çözümleyici bütünleştirilmiş kodu, derleyicinin şu anda çalışandan daha yeni bir sürümüne başvurur. + Analyzer assembly cannot be used because it references a newer version of the compiler than the currently running version. + Çözümleyici bütünleştirilmiş kodu, derleyicinin şu anda çalışandan daha yeni bir sürümüne başvurur. @@ -681,12 +681,12 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + '{0}' yalnızca değerlendirme amaçlıdır ve gelecekteki güncelleştirmelerde değiştirilebilir veya kaldırılabilir: '{1}'. Type is for evaluation purposes only and is subject to change or removal in future updates. - Type is for evaluation purposes only and is subject to change or removal in future updates. + Tür, yalnızca değerlendirme amaçlıdır ve gelecekteki güncelleştirmelerde değiştirilebilir veya kaldırılabilir. @@ -9354,7 +9354,7 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates. + '{0}' yalnızca değerlendirme amaçlıdır ve gelecekteki güncelleştirmelerde değiştirilebilir veya kaldırılabilir. @@ -9364,7 +9364,7 @@ Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + '{2}' bütünleştirilmiş kodundan '{0}' metodunun (belirteç 0x{1:X8}) hata ayıklama bilgileri okunamıyor: {3} diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hans.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hans.xlf index adbb1683ec375..7a5a5f73a5c49 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hans.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hans.xlf @@ -19,12 +19,12 @@ Cannot use 'OverloadResolutionPriorityAttribute' on this member. - Cannot use 'OverloadResolutionPriorityAttribute' on this member. + 无法对此成员使用 'OverloadResolutionPriorityAttribute'。 Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. - Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + 无法对替代成员使用 'OverloadResolutionPriorityAttribute'。 @@ -54,7 +54,7 @@ Cannot update '{0}'; attribute '{1}' is missing. - Cannot update '{0}'; attribute '{1}' is missing. + 无法更新“{0}”;特性“{1}”缺失。 @@ -109,7 +109,7 @@ The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type - The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + 类型 “Microsoft.CodeAnalysis.EmbeddedAttribute” 必须是非泛型,Friend、NotInheritable、具有 Public 无参数构造函数、从 System.Attribute 继承,并且能够应用于任何类型 @@ -134,7 +134,7 @@ The type name '{0}' is reserved to be used by the compiler. - The type name '{0}' is reserved to be used by the compiler. + 类型名称“{0}”是保留给编译器使用的。 @@ -149,7 +149,7 @@ Type argument '{0}' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as type parameter '{1}'. - Type argument '{0}' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as type parameter '{1}'. + 类型参数“{0}”以及任何嵌套级别的所有字段必须是不可为 null 的值类型,才能将其用作类型参数“{1}”。 @@ -179,7 +179,7 @@ overload resolution priority - overload resolution priority + 重载解析优先级 @@ -189,7 +189,7 @@ recognizing 'unmanaged' constraint - recognizing 'unmanaged' constraint + 正在识别 “unmanaged” 约束 @@ -629,13 +629,13 @@ - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - 分析器程序集“{0}”引用了编译器的版本“{1}”,该版本高于当前正在运行的版本“{2}”。 + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + 分析器程序集“{0}”引用了编译器的版本“{1}”,该版本高于当前正在运行的版本“{2}”。 - The analyzer assembly references a newer version of the compiler than the currently running version. - 分析器程序集引用的编译器版本高于当前正在运行的版本。 + Analyzer assembly cannot be used because it references a newer version of the compiler than the currently running version. + 分析器程序集引用的编译器版本高于当前正在运行的版本。 @@ -680,12 +680,12 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + “{0}”仅用于评估,在将来的更新中可能会被更改或删除:“{1}”。 Type is for evaluation purposes only and is subject to change or removal in future updates. - Type is for evaluation purposes only and is subject to change or removal in future updates. + 类型仅用于评估,在将来的更新中可能会被更改或删除。 @@ -9353,7 +9353,7 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates. + “{0}”仅用于评估,在将来的更新中可能会被更改或删除。 @@ -9363,7 +9363,7 @@ Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + 无法从程序集“{2}”读取方法“{0}”(令牌 0x{1:X8})的调试信息: {3} diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hant.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hant.xlf index 80ded5eb2fe5f..440e9c48e4924 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hant.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hant.xlf @@ -19,12 +19,12 @@ Cannot use 'OverloadResolutionPriorityAttribute' on this member. - Cannot use 'OverloadResolutionPriorityAttribute' on this member. + 無法在此成員上使用 'OverloadResolutionPriorityAttribute'。 Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. - Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + 無法在覆寫成員上使用 'OverloadResolutionPriorityAttribute'。 @@ -54,7 +54,7 @@ Cannot update '{0}'; attribute '{1}' is missing. - Cannot update '{0}'; attribute '{1}' is missing. + 無法更新 '{0}'; 缺少屬性 '{1}'。 @@ -109,7 +109,7 @@ The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type - The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + 類型 'Microsoft.CodeAnalysis.EmbeddedAttribute' 必須是非泛型、好友、NotInheritable、具有公用無參數建構函式、繼承自 System.Attribute,而且可以套用到任何類型 @@ -134,7 +134,7 @@ The type name '{0}' is reserved to be used by the compiler. - The type name '{0}' is reserved to be used by the compiler. + 類型名稱 '{0}' 保留供編譯器使用。 @@ -149,7 +149,7 @@ Type argument '{0}' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as type parameter '{1}'. - Type argument '{0}' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as type parameter '{1}'. + 型別引數 '{0}' 及任何巢狀層級的所有欄位必須是不可為 null 的值類型,如此才能將其作爲型別參數 '{1}' 使用。 @@ -179,7 +179,7 @@ overload resolution priority - overload resolution priority + 多載解析優先順序 @@ -189,7 +189,7 @@ recognizing 'unmanaged' constraint - recognizing 'unmanaged' constraint + 辨識 'unmanaged' 條件約束 @@ -630,13 +630,13 @@ - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - 分析程式組件 '{0}' 參考編譯器的版本 '{1}' ,比目前執行的版本 '{2}' 還要新。 + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + 分析程式組件 '{0}' 參考編譯器的版本 '{1}' ,比目前執行的版本 '{2}' 還要新。 - The analyzer assembly references a newer version of the compiler than the currently running version. - 分析程式組件參考的編譯器版本比目前執行的版本新。 + Analyzer assembly cannot be used because it references a newer version of the compiler than the currently running version. + 分析程式組件參考的編譯器版本比目前執行的版本新。 @@ -681,12 +681,12 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + '{0}' 僅供評估用。後續更新: '{1}' 時可能會有所變更或移除。 Type is for evaluation purposes only and is subject to change or removal in future updates. - Type is for evaluation purposes only and is subject to change or removal in future updates. + 類型僅供評估之用。後續更新時可能會有所變更或移除。 @@ -9354,7 +9354,7 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. - '{0}' is for evaluation purposes only and is subject to change or removal in future updates. + '{0}' 僅供評估之用。後續更新時可能會有所變更或移除。 @@ -9364,7 +9364,7 @@ Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + 無法從組件 '{2}' 讀取方法 '{0}' (權杖 0x{1:X8}) 的偵錯資訊: {3} diff --git a/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests.vb b/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests.vb index 489f5ef45ae5c..0b6f776f7b276 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests.vb @@ -1875,6 +1875,7 @@ End Class Public Sub AttributeArgumentAsEnumFromMetadata() Dim metadata1 = VisualBasicCompilation.Create("bar.dll", + options:=TestOptions.DebugDll, references:={MscorlibRef}, syntaxTrees:={Parse("Public Enum Bar : Baz : End Enum")}).EmitToArray(New EmitOptions(metadataOnly:=True)) @@ -1882,6 +1883,7 @@ End Class Dim metadata2 = VisualBasicCompilation.Create( "goo.dll", + options:=TestOptions.DebugDll, references:={MscorlibRef, ref1}, syntaxTrees:={ VisualBasicSyntaxTree.ParseText( + Public Sub EmitMetadataOnly_Exe() + CompileAndVerify( + + +Module Program + Sub Main() + System.Console.WriteLine("a") + End Sub +End Module + + , + options:=TestOptions.ReleaseExe.WithMetadataImportOptions(MetadataImportOptions.All), + emitOptions:=EmitOptions.Default.WithEmitMetadataOnly(True), + symbolValidator:=Sub(m) + Assert.NotEqual(0, m.GetMetadata().Module.PEReaderOpt.PEHeaders.CorHeader.EntryPointTokenOrRelativeVirtualAddress) + Dim main = m.GlobalNamespace.GetMember(Of MethodSymbol)("Program.Main") + Assert.Equal(Accessibility.Public, main.DeclaredAccessibility) + End Sub + ).VerifyDiagnostics() + End Sub + + + Public Sub EmitMetadataOnly_Exe_AsyncMain() + Dim emitResult = CreateCompilation( + + +Imports System.Threading.Tasks +Module Program + Public Async Function Main() As Task + Await Task.Yield() + System.Console.WriteLine("a") + End Function +End Module + + , + options:=TestOptions.ReleaseExe, + assemblyName:="MyLib" + ).Emit(New MemoryStream(), options:=EmitOptions.Default.WithEmitMetadataOnly(True)) + Assert.False(emitResult.Success) + emitResult.Diagnostics.AssertTheseDiagnostics( +BC30737: No accessible 'Main' method with an appropriate signature was found in 'MyLib'. + ) + End Sub + + + Public Sub EmitMetadataOnly_Exe_AsyncMain_Void() + Dim emitResult = CreateCompilation( + + +Imports System.Threading.Tasks +Module Program + Public Async Sub Main() + Await Task.Yield() + System.Console.WriteLine("a") + End Sub +End Module + + , + options:=TestOptions.ReleaseExe, + assemblyName:="MyLib" + ).Emit(New MemoryStream(), options:=EmitOptions.Default.WithEmitMetadataOnly(True)) + Assert.False(emitResult.Success) + emitResult.Diagnostics.AssertTheseDiagnostics( +BC36934: The 'Main' method cannot be marked 'Async'. + Public Async Sub Main() + ~~~~ + ) + End Sub + + + Public Sub EmitMetadataOnly_Exe_NoMain() + Dim emitResult = CreateCompilation( + + +Module Program +End Module + + , + options:=TestOptions.ReleaseExe, + assemblyName:="MyLib" + ).Emit(New MemoryStream(), options:=EmitOptions.Default.WithEmitMetadataOnly(True)) + Assert.False(emitResult.Success) + emitResult.Diagnostics.AssertTheseDiagnostics( +BC30420: 'Sub Main' was not found in 'MyLib'. + ) + End Sub + + + Public Sub EmitMetadataOnly_Exe_FriendMain_ExcludePrivateMembers() + CompileAndVerify( + + +Module Program + Friend Sub Main() + End Sub +End Module + + , + options:=TestOptions.ReleaseExe.WithMetadataImportOptions(MetadataImportOptions.All), + emitOptions:=EmitOptions.Default.WithEmitMetadataOnly(True).WithIncludePrivateMembers(False), + symbolValidator:=Sub(m) + Assert.NotEqual(0, m.GetMetadata().Module.PEReaderOpt.PEHeaders.CorHeader.EntryPointTokenOrRelativeVirtualAddress) + Dim main = m.GlobalNamespace.GetMember(Of MethodSymbol)("Program.Main") + Assert.Equal(Accessibility.Internal, main.DeclaredAccessibility) + End Sub + ).VerifyDiagnostics() + End Sub + + + Public Sub ExcludePrivateMembers_FriendMain() + Using peStream As New MemoryStream() + Using metadataStream As New MemoryStream() + Dim comp = CreateCompilation( + + +Module Program + Friend Sub Main() + End Sub +End Module + + , + options:=TestOptions.ReleaseExe + ) + Dim emitResult = comp.Emit( + peStream:=peStream, + metadataPEStream:=metadataStream, + options:=EmitOptions.Default.WithIncludePrivateMembers(False)) + Assert.True(emitResult.Success) + emitResult.Diagnostics.Verify() + + Verify(peStream) + Verify(metadataStream) + + CompileAndVerify(comp).VerifyDiagnostics() + End Using + End Using + End Sub + + Private Shared Sub Verify(stream As Stream) + stream.Position = 0 + Assert.NotEqual(0, New PEHeaders(stream).CorHeader.EntryPointTokenOrRelativeVirtualAddress) + + stream.Position = 0 + Dim reference = AssemblyMetadata.CreateFromStream(stream).GetReference() + Dim comp = CreateCompilation("", references:={reference}, options:=TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)) + Dim main = comp.GetMember(Of MethodSymbol)("Program.Main") + Assert.Equal(Accessibility.Internal, main.DeclaredAccessibility) + End Sub + + + Public Sub ExcludePrivateMembers_DebugEntryPoint() + Using peStream As New MemoryStream() + Using metadataStream As New MemoryStream() + Dim comp = CreateCompilation( + + +Module Program + Private Sub M1() + End Sub + Private Sub M2() + End Sub +End Module + + ).VerifyDiagnostics() + Dim emitResult = comp.Emit( + peStream:=peStream, + metadataPEStream:=metadataStream, + debugEntryPoint:=comp.GetMember(Of MethodSymbol)("Program.M1"), + options:=EmitOptions.Default.WithIncludePrivateMembers(False)) + Assert.True(emitResult.Success) + emitResult.Diagnostics.Verify() + + ' M1 should be emitted (it's the debug entry-point), M2 shouldn't (private members are excluded). + metadataStream.Position = 0 + Dim reference = AssemblyMetadata.CreateFromStream(metadataStream).GetReference() + Dim comp2 = CreateCompilation("", references:={reference}, + options:=TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)) + Dim m1 = comp2.GetMember(Of MethodSymbol)("Program.M1") + Assert.Equal(Accessibility.Private, m1.DeclaredAccessibility) + Assert.Null(comp2.GetMember(Of MethodSymbol)("Program.M2")) + End Using + End Using + End Sub End Class End Namespace diff --git a/src/Compilers/VisualBasic/Test/Emit/Semantics/StaticLocalsSemanticTests.vb b/src/Compilers/VisualBasic/Test/Emit/Semantics/StaticLocalsSemanticTests.vb index b0e00bafb735d..2263160ba4391 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Semantics/StaticLocalsSemanticTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Semantics/StaticLocalsSemanticTests.vb @@ -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. +Imports System.Threading Imports Microsoft.CodeAnalysis -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 Xunit Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests @@ -346,8 +344,8 @@ End Class Public Sub Semantic_StaticLocalDeclaration_LateBound() ' test late bind ' call ToString() on object defeat the purpose - Dim currCulture = Threading.Thread.CurrentThread.CurrentCulture - Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture + Dim currCulture = Thread.CurrentThread.CurrentCulture + Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture Try 'Declare static local which is late bound Dim compilationDef = CreateCompilationWithMscorlib40AndVBRuntime( @@ -391,7 +389,7 @@ After:5.5]]>) Catch ex As Exception Assert.Null(ex) Finally - Threading.Thread.CurrentThread.CurrentCulture = currCulture + Thread.CurrentThread.CurrentCulture = currCulture End Try End Sub @@ -1444,7 +1442,7 @@ End Class Public Sub Semantic_MaximumLength_StaticLocalIdentifier() - 'The Use of Static Locals with an identifier at maxmimum length to ensure functionality + 'The Use of Static Locals with an identifier at maximum length to ensure functionality 'works and generated backing field is correctly supported. Dim compilationDef = CreateCompilationWithMscorlib40AndVBRuntime( diff --git a/src/Compilers/VisualBasic/Test/Semantic/Compilation/GetImportScopesTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Compilation/GetImportScopesTests.vb index 524689f53a18f..3b8c725991d22 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Compilation/GetImportScopesTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Compilation/GetImportScopesTests.vb @@ -338,7 +338,7 @@ end namespace #Region "xml namespace" - Public Sub TestBeforeXmlNamespae() + Public Sub TestBeforeXmlNamespace() Dim Text = "'pos Imports " Dim scopes = GetImportScopes(Text) diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/InterpolatedStringTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/InterpolatedStringTests.vb index da29a53e273c8..5eeaf3b59a046 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/InterpolatedStringTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/InterpolatedStringTests.vb @@ -1,6 +1,8 @@ ' Licensed to the .NET Foundation under one or more agreements. ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. + +Imports System.Threading Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.VisualBasic.SyntaxFacts @@ -555,7 +557,7 @@ BC42322: Runtime errors might occur when converting 'String' to 'IFormattable'. Public Sub InvariantCulture() - Dim previousCulture = Threading.Thread.CurrentThread.CurrentCulture + Dim previousCulture = Thread.CurrentThread.CurrentCulture Dim verifier = CompileAndVerify( @@ -584,7 +586,7 @@ End Module , expectedOutput:="1,51,51,51.5") - Assert.Equal(previousCulture, Threading.Thread.CurrentThread.CurrentCulture) + Assert.Equal(previousCulture, Thread.CurrentThread.CurrentCulture) End Sub diff --git a/src/Compilers/VisualBasic/Test/Semantic/SourceGeneration/GeneratorDriverTests_Attributes_SimpleName.vb b/src/Compilers/VisualBasic/Test/Semantic/SourceGeneration/GeneratorDriverTests_Attributes_SimpleName.vb index 6bd8efbe6c381..1188390890653 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/SourceGeneration/GeneratorDriverTests_Attributes_SimpleName.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/SourceGeneration/GeneratorDriverTests_Attributes_SimpleName.vb @@ -468,7 +468,7 @@ end class Dim source = " imports AAttribute : X - + class C end class " diff --git a/src/Compilers/VisualBasic/Test/Symbol/DocumentationComments/DocCommentTests.vb b/src/Compilers/VisualBasic/Test/Symbol/DocumentationComments/DocCommentTests.vb index 1757a5bb79bf9..8d2f0944c2544 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/DocumentationComments/DocCommentTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/DocumentationComments/DocCommentTests.vb @@ -3,15 +3,15 @@ ' See the LICENSE file in the project root for more information. Imports System.Collections.Immutable +Imports System.IO +Imports System.Text +Imports System.Threading +Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Imports Microsoft.CodeAnalysis.Test.Utilities -Imports System.Xml.Linq -Imports System.Text -Imports System.IO -Imports Roslyn.Test.Utilities Imports Microsoft.CodeAnalysis.VisualBasic.VisualBasicCompilation +Imports Roslyn.Test.Utilities Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests Public Class DocCommentTests @@ -12129,8 +12129,8 @@ xmlDoc) If preferred Is Nothing Then ensureEnglishUICulture = False Else - saveUICulture = Threading.Thread.CurrentThread.CurrentUICulture - Threading.Thread.CurrentThread.CurrentUICulture = preferred + saveUICulture = Thread.CurrentThread.CurrentUICulture + Thread.CurrentThread.CurrentUICulture = preferred End If End If @@ -12138,7 +12138,7 @@ xmlDoc) diagnostics = compilation.GetDiagnostics(CompilationStage.Compile).ToArray() Finally If ensureEnglishUICulture Then - Threading.Thread.CurrentThread.CurrentUICulture = saveUICulture + Thread.CurrentThread.CurrentUICulture = saveUICulture End If End Try @@ -12170,8 +12170,8 @@ xmlDoc) If preferred Is Nothing Then ensureEnglishUICulture = False Else - saveUICulture = Threading.Thread.CurrentThread.CurrentUICulture - Threading.Thread.CurrentThread.CurrentUICulture = preferred + saveUICulture = Thread.CurrentThread.CurrentUICulture + Thread.CurrentThread.CurrentUICulture = preferred End If End If @@ -12179,7 +12179,7 @@ xmlDoc) emitResult = compilation.Emit(output, xmlDocumentationStream:=xml) Finally If ensureEnglishUICulture Then - Threading.Thread.CurrentThread.CurrentUICulture = saveUICulture + Thread.CurrentThread.CurrentUICulture = saveUICulture End If End Try diff --git a/src/Dependencies/Collections/Microsoft.CodeAnalysis.Collections.Package.csproj b/src/Dependencies/Collections/Microsoft.CodeAnalysis.Collections.Package.csproj index cbcddc860d25f..e77a382a6ca5a 100644 --- a/src/Dependencies/Collections/Microsoft.CodeAnalysis.Collections.Package.csproj +++ b/src/Dependencies/Collections/Microsoft.CodeAnalysis.Collections.Package.csproj @@ -20,10 +20,6 @@ $(NoWarn);NU5128 - - - - @@ -46,11 +42,13 @@ - <_File Remove="@(_File)"/> + <_File Remove="@(_File)" /> <_File Include="$(MSBuildProjectDirectory)\**\*.resx" TargetDir="contentFiles/$(_LanguageDirName)/$(TargetFramework)" BuildAction="EmbeddedResource" /> <_File Include="$(MSBuildProjectDirectory)\**\*.xlf" TargetDir="contentFiles/$(_LanguageDirName)/$(TargetFramework)" BuildAction="None" /> - + + + \ No newline at end of file diff --git a/src/Compilers/Core/Portable/Syntax/CollectionBuilderAttribute.cs b/src/Dependencies/Contracts/CollectionBuilderAttribute.cs similarity index 100% rename from src/Compilers/Core/Portable/Syntax/CollectionBuilderAttribute.cs rename to src/Dependencies/Contracts/CollectionBuilderAttribute.cs diff --git a/src/Compilers/Core/Portable/InternalUtilities/CompilerFeatureRequiredAttribute.cs b/src/Dependencies/Contracts/CompilerFeatureRequiredAttribute.cs similarity index 100% rename from src/Compilers/Core/Portable/InternalUtilities/CompilerFeatureRequiredAttribute.cs rename to src/Dependencies/Contracts/CompilerFeatureRequiredAttribute.cs diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/Contract.InterpolatedStringHandlers.cs b/src/Dependencies/Contracts/Contract.InterpolatedStringHandlers.cs similarity index 96% rename from src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/Contract.InterpolatedStringHandlers.cs rename to src/Dependencies/Contracts/Contract.InterpolatedStringHandlers.cs index 84469add46cbf..628aa3457f573 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/Contract.InterpolatedStringHandlers.cs +++ b/src/Dependencies/Contracts/Contract.InterpolatedStringHandlers.cs @@ -2,12 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#if !MICROSOFT_CODEANALYSIS_CONTRACTS_NO_CONTRACT + using System.Runtime.CompilerServices; using System.Text; #pragma warning disable IDE0060 // Remove unused parameter - https://github.com/dotnet/roslyn/issues/58168 -namespace Roslyn.Utilities; +namespace Microsoft.CodeAnalysis; internal static partial class Contract { @@ -65,3 +67,5 @@ public ThrowIfNullInterpolatedStringHandler(int literalLength, int formattedCoun public string GetFormattedText() => _stringBuilder.ToString(); } } + +#endif diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/Contract.cs b/src/Dependencies/Contracts/Contract.cs similarity index 98% rename from src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/Contract.cs rename to src/Dependencies/Contracts/Contract.cs index db14883bd1652..489ffe5bea9de 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/Contract.cs +++ b/src/Dependencies/Contracts/Contract.cs @@ -2,13 +2,15 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#if !MICROSOFT_CODEANALYSIS_CONTRACTS_NO_CONTRACT + using System; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Runtime.CompilerServices; -namespace Roslyn.Utilities; +namespace Microsoft.CodeAnalysis; internal static partial class Contract { @@ -157,3 +159,5 @@ public static void Fail(string message = "Unexpected", [CallerLineNumber] int li throw new InvalidOperationException($"{message} - file {fileName} line {lineNumber}"); } } + +#endif diff --git a/src/Compilers/Core/Portable/InternalUtilities/ExceptionUtilities.cs b/src/Dependencies/Contracts/ExceptionUtilities.cs similarity index 98% rename from src/Compilers/Core/Portable/InternalUtilities/ExceptionUtilities.cs rename to src/Dependencies/Contracts/ExceptionUtilities.cs index e2c787f7f2eb4..983341521a3c3 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/ExceptionUtilities.cs +++ b/src/Dependencies/Contracts/ExceptionUtilities.cs @@ -7,7 +7,7 @@ using System.Runtime.CompilerServices; using System.Threading; -namespace Roslyn.Utilities +namespace Microsoft.CodeAnalysis { internal static class ExceptionUtilities { diff --git a/src/Compilers/Core/Portable/InternalUtilities/ExperimentalAttribute.cs b/src/Dependencies/Contracts/ExperimentalAttribute.cs similarity index 100% rename from src/Compilers/Core/Portable/InternalUtilities/ExperimentalAttribute.cs rename to src/Dependencies/Contracts/ExperimentalAttribute.cs diff --git a/src/Compilers/Core/Portable/InternalUtilities/IReadOnlySet.cs b/src/Dependencies/Contracts/IReadOnlySet.cs similarity index 100% rename from src/Compilers/Core/Portable/InternalUtilities/IReadOnlySet.cs rename to src/Dependencies/Contracts/IReadOnlySet.cs diff --git a/src/Compilers/Core/Portable/InternalUtilities/InterpolatedStringHandlerArgumentAttribute.cs b/src/Dependencies/Contracts/InterpolatedStringHandlerArgumentAttribute.cs similarity index 100% rename from src/Compilers/Core/Portable/InternalUtilities/InterpolatedStringHandlerArgumentAttribute.cs rename to src/Dependencies/Contracts/InterpolatedStringHandlerArgumentAttribute.cs diff --git a/src/Compilers/Core/Portable/InternalUtilities/InterpolatedStringHandlerAttribute.cs b/src/Dependencies/Contracts/InterpolatedStringHandlerAttribute.cs similarity index 100% rename from src/Compilers/Core/Portable/InternalUtilities/InterpolatedStringHandlerAttribute.cs rename to src/Dependencies/Contracts/InterpolatedStringHandlerAttribute.cs diff --git a/src/Compilers/Core/Portable/InternalUtilities/IsExternalInit.cs b/src/Dependencies/Contracts/IsExternalInit.cs similarity index 100% rename from src/Compilers/Core/Portable/InternalUtilities/IsExternalInit.cs rename to src/Dependencies/Contracts/IsExternalInit.cs diff --git a/src/Dependencies/Contracts/Microsoft.CodeAnalysis.Contracts.Package.csproj b/src/Dependencies/Contracts/Microsoft.CodeAnalysis.Contracts.Package.csproj new file mode 100644 index 0000000000000..d00764e8b32d7 --- /dev/null +++ b/src/Dependencies/Contracts/Microsoft.CodeAnalysis.Contracts.Package.csproj @@ -0,0 +1,26 @@ + + + + + $(NetRoslynSourceBuild);netstandard2.0 + false + false + none + false + true + + + true + true + Microsoft.CodeAnalysis.Contracts + false + + Package containing sources of Microsoft .NET Compiler Platform ("Roslyn") contract and polyfill types. + + + $(NoWarn);NU5128 + + + + + \ No newline at end of file diff --git a/src/Dependencies/Contracts/Microsoft.CodeAnalysis.Contracts.projitems b/src/Dependencies/Contracts/Microsoft.CodeAnalysis.Contracts.projitems new file mode 100644 index 0000000000000..b98b83ea55567 --- /dev/null +++ b/src/Dependencies/Contracts/Microsoft.CodeAnalysis.Contracts.projitems @@ -0,0 +1,32 @@ + + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + BD974609-C68B-4BE6-9682-EB132462B50D + + + Microsoft.CodeAnalysis.Contracts + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Dependencies/Contracts/Microsoft.CodeAnalysis.Contracts.shproj b/src/Dependencies/Contracts/Microsoft.CodeAnalysis.Contracts.shproj new file mode 100644 index 0000000000000..e6fb451a37453 --- /dev/null +++ b/src/Dependencies/Contracts/Microsoft.CodeAnalysis.Contracts.shproj @@ -0,0 +1,14 @@ + + + + + BD974609-C68B-4BE6-9682-EB132462B50D + 14.0 + + + + + + + + \ No newline at end of file diff --git a/src/Compilers/Core/Portable/InternalUtilities/NonCopyableAttribute.cs b/src/Dependencies/Contracts/NonCopyableAttribute.cs similarity index 53% rename from src/Compilers/Core/Portable/InternalUtilities/NonCopyableAttribute.cs rename to src/Dependencies/Contracts/NonCopyableAttribute.cs index edaee07bae0cb..a5efff996a18a 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/NonCopyableAttribute.cs +++ b/src/Dependencies/Contracts/NonCopyableAttribute.cs @@ -2,14 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; -namespace Roslyn.Utilities +namespace Microsoft.CodeAnalysis; + +[AttributeUsage(AttributeTargets.Struct | AttributeTargets.GenericParameter)] +internal sealed class NonCopyableAttribute : Attribute { - [AttributeUsage(AttributeTargets.Struct | AttributeTargets.GenericParameter)] - internal sealed class NonCopyableAttribute : Attribute - { - } } diff --git a/src/Compilers/Core/Portable/InternalUtilities/NonDefaultableAttribute.cs b/src/Dependencies/Contracts/NonDefaultableAttribute.cs similarity index 53% rename from src/Compilers/Core/Portable/InternalUtilities/NonDefaultableAttribute.cs rename to src/Dependencies/Contracts/NonDefaultableAttribute.cs index a0d14a00b4b5b..c89b6aed40f05 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/NonDefaultableAttribute.cs +++ b/src/Dependencies/Contracts/NonDefaultableAttribute.cs @@ -2,14 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; -namespace Roslyn.Utilities +namespace Microsoft.CodeAnalysis; + +[AttributeUsage(AttributeTargets.Struct | AttributeTargets.GenericParameter)] +internal sealed class NonDefaultableAttribute : Attribute { - [AttributeUsage(AttributeTargets.Struct | AttributeTargets.GenericParameter)] - internal sealed class NonDefaultableAttribute : Attribute - { - } } diff --git a/src/Compilers/Core/Portable/InternalUtilities/NullableAttributes.cs b/src/Dependencies/Contracts/NullableAttributes.cs similarity index 100% rename from src/Compilers/Core/Portable/InternalUtilities/NullableAttributes.cs rename to src/Dependencies/Contracts/NullableAttributes.cs diff --git a/src/Compilers/Core/Portable/InternalUtilities/RequiredMemberAttribute.cs b/src/Dependencies/Contracts/RequiredMemberAttribute.cs similarity index 100% rename from src/Compilers/Core/Portable/InternalUtilities/RequiredMemberAttribute.cs rename to src/Dependencies/Contracts/RequiredMemberAttribute.cs diff --git a/src/Compilers/Core/Portable/InternalUtilities/SetsRequiredMembersAttribute.cs b/src/Dependencies/Contracts/SetsRequiredMembersAttribute.cs similarity index 100% rename from src/Compilers/Core/Portable/InternalUtilities/SetsRequiredMembersAttribute.cs rename to src/Dependencies/Contracts/SetsRequiredMembersAttribute.cs diff --git a/src/Dependencies/PooledObjects/ArrayBuilder.cs b/src/Dependencies/PooledObjects/ArrayBuilder.cs index c76055bead00d..35ab00e03a50b 100644 --- a/src/Dependencies/PooledObjects/ArrayBuilder.cs +++ b/src/Dependencies/PooledObjects/ArrayBuilder.cs @@ -16,6 +16,9 @@ namespace Microsoft.CodeAnalysis.PooledObjects [DebuggerDisplay("Count = {Count,nq}")] [DebuggerTypeProxy(typeof(ArrayBuilder<>.DebuggerProxy))] internal sealed partial class ArrayBuilder : IReadOnlyCollection, IReadOnlyList, ICollection +#if !MICROSOFT_CODEANALYSIS_POOLEDOBJECTS_NO_POOLED_DISPOSER + , IPooled +#endif { /// /// See for an explanation of this constant value. @@ -720,5 +723,49 @@ public ImmutableArray SelectDistinct(Func selector) set.Free(); return result.ToImmutableAndFree(); } + +#if !MICROSOFT_CODEANALYSIS_POOLEDOBJECTS_NO_POOLED_DISPOSER + + private static readonly ObjectPool> s_keepLargeInstancesPool = CreatePool(); + + public static PooledDisposer> GetInstance(out ArrayBuilder instance) + => GetInstance(discardLargeInstances: true, out instance); + + public static PooledDisposer> GetInstance(int capacity, out ArrayBuilder instance) + { + instance = GetInstance(capacity); + return new PooledDisposer>(instance); + } + + public static PooledDisposer> GetInstance(int capacity, T fillWithValue, out ArrayBuilder instance) + { + instance = GetInstance(capacity, fillWithValue); + return new PooledDisposer>(instance); + } + + public static PooledDisposer> GetInstance(bool discardLargeInstances, out ArrayBuilder instance) + { + // If we're discarding large instances (the default behavior), then just use the normal pool. If we're not, use + // a specific pool so that *other* normal callers don't accidentally get it and discard it. + instance = discardLargeInstances ? GetInstance() : s_keepLargeInstancesPool.Allocate(); + return new PooledDisposer>(instance, discardLargeInstances); + } + + void IPooled.Free(bool discardLargeInstances) + { + // If we're discarding large instances, use the default behavior (which already does that). Otherwise, always + // clear and free the instance back to its originating pool. + if (discardLargeInstances) + { + Free(); + } + else + { + this.Clear(); + _pool?.Free(this); + } + } + +#endif } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/IPooled.cs b/src/Dependencies/PooledObjects/IPooled.cs similarity index 86% rename from src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/IPooled.cs rename to src/Dependencies/PooledObjects/IPooled.cs index 6a0d0d14d4128..0b687f3f3e697 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/IPooled.cs +++ b/src/Dependencies/PooledObjects/IPooled.cs @@ -6,5 +6,5 @@ namespace Microsoft.CodeAnalysis.PooledObjects; internal interface IPooled { - void Free(); + void Free(bool discardLargeInstances); } diff --git a/src/Dependencies/PooledObjects/Microsoft.CodeAnalysis.PooledObjects.projitems b/src/Dependencies/PooledObjects/Microsoft.CodeAnalysis.PooledObjects.projitems index 97a2e3f5ca08f..3b563ade211f9 100644 --- a/src/Dependencies/PooledObjects/Microsoft.CodeAnalysis.PooledObjects.projitems +++ b/src/Dependencies/PooledObjects/Microsoft.CodeAnalysis.PooledObjects.projitems @@ -12,9 +12,11 @@ + + diff --git a/src/Dependencies/PooledObjects/PooledDisposer.cs b/src/Dependencies/PooledObjects/PooledDisposer.cs new file mode 100644 index 0000000000000..e497c4dbd16e9 --- /dev/null +++ b/src/Dependencies/PooledObjects/PooledDisposer.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. + +#if !MICROSOFT_CODEANALYSIS_POOLEDOBJECTS_NO_POOLED_DISPOSER +using System; + +namespace Microsoft.CodeAnalysis.PooledObjects; + +internal readonly partial struct PooledDisposer( + TPoolable instance, + bool discardLargeInstances = true) : IDisposable + where TPoolable : class, IPooled +{ + void IDisposable.Dispose() + => instance?.Free(discardLargeInstances); +} +#endif diff --git a/src/Workspaces/Core/Portable/Shared/Utilities/AsyncBatchingWorkQueue`0.cs b/src/Dependencies/Threading/AsyncBatchingWorkQueue`0.cs similarity index 91% rename from src/Workspaces/Core/Portable/Shared/Utilities/AsyncBatchingWorkQueue`0.cs rename to src/Dependencies/Threading/AsyncBatchingWorkQueue`0.cs index fd21607855f71..db94f6efbc8e7 100644 --- a/src/Workspaces/Core/Portable/Shared/Utilities/AsyncBatchingWorkQueue`0.cs +++ b/src/Dependencies/Threading/AsyncBatchingWorkQueue`0.cs @@ -9,7 +9,7 @@ using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Shared.TestHooks; -namespace Roslyn.Utilities; +namespace Microsoft.CodeAnalysis.Threading; /// internal sealed class AsyncBatchingWorkQueue( @@ -22,5 +22,5 @@ private static Func, CancellationToken, Value => (items, ct) => processBatchAsync(ct); public void AddWork(bool cancelExistingWork = false) - => base.AddWork(default(VoidResult), cancelExistingWork); + => AddWork(default(VoidResult), cancelExistingWork); } diff --git a/src/Workspaces/Core/Portable/Shared/Utilities/AsyncBatchingWorkQueue`1.cs b/src/Dependencies/Threading/AsyncBatchingWorkQueue`1.cs similarity index 97% rename from src/Workspaces/Core/Portable/Shared/Utilities/AsyncBatchingWorkQueue`1.cs rename to src/Dependencies/Threading/AsyncBatchingWorkQueue`1.cs index 98aa376ccf429..a14aebc098cb9 100644 --- a/src/Workspaces/Core/Portable/Shared/Utilities/AsyncBatchingWorkQueue`1.cs +++ b/src/Dependencies/Threading/AsyncBatchingWorkQueue`1.cs @@ -9,7 +9,7 @@ using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Shared.TestHooks; -namespace Roslyn.Utilities; +namespace Microsoft.CodeAnalysis.Threading; /// internal class AsyncBatchingWorkQueue( diff --git a/src/Workspaces/Core/Portable/Shared/Utilities/AsyncBatchingWorkQueue`2.cs b/src/Dependencies/Threading/AsyncBatchingWorkQueue`2.cs similarity index 97% rename from src/Workspaces/Core/Portable/Shared/Utilities/AsyncBatchingWorkQueue`2.cs rename to src/Dependencies/Threading/AsyncBatchingWorkQueue`2.cs index db07db90e48bd..4844a6f60c807 100644 --- a/src/Workspaces/Core/Portable/Shared/Utilities/AsyncBatchingWorkQueue`2.cs +++ b/src/Dependencies/Threading/AsyncBatchingWorkQueue`2.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.TestHooks; -namespace Roslyn.Utilities; +namespace Microsoft.CodeAnalysis.Threading; /// /// A queue where items can be added to to be processed in batches after some delay has passed. When processing @@ -140,10 +140,16 @@ public void CancelExistingWork() public void AddWork(TItem item, bool cancelExistingWork = false) { - using var _ = ArrayBuilder.GetInstance(out var items); - items.Add(item); - - AddWork(items, cancelExistingWork); + var items = ArrayBuilder.GetInstance(); + try + { + items.Add(item); + AddWork(items, cancelExistingWork); + } + finally + { + items.Free(); + } } public void AddWork(IEnumerable items, bool cancelExistingWork = false) @@ -254,9 +260,7 @@ void AddItemsToBatch(IEnumerable items) var batchResultTask = _processBatchAsync(nextBatch, batchCancellationToken).Preserve(); await batchResultTask.NoThrowAwaitableInternal(false); if (batchResultTask.IsCompletedSuccessfully) - { return batchResultTask.Result; - } else if (batchResultTask.IsCanceled && !_entireQueueCancellationToken.IsCancellationRequested) { // Don't bubble up cancellation to the queue for the nested batch cancellation. Just because we decided @@ -265,8 +269,11 @@ void AddItemsToBatch(IEnumerable items) } else { + Contract.ThrowIfFalse(batchResultTask.IsCompleted); + // Realize the completed result to force the exception to be thrown. - batchResultTask.VerifyCompleted(); + batchResultTask.GetAwaiter().GetResult(); + throw ExceptionUtilities.Unreachable(); } } diff --git a/src/Workspaces/Core/Portable/Utilities/CancellationSeries.cs b/src/Dependencies/Threading/CancellationSeries.cs similarity index 99% rename from src/Workspaces/Core/Portable/Utilities/CancellationSeries.cs rename to src/Dependencies/Threading/CancellationSeries.cs index bddcaf175195f..1a477841243e2 100644 --- a/src/Workspaces/Core/Portable/Utilities/CancellationSeries.cs +++ b/src/Dependencies/Threading/CancellationSeries.cs @@ -11,7 +11,7 @@ using System; using System.Threading; -namespace Roslyn.Utilities; +namespace Microsoft.CodeAnalysis.Threading; /// /// Produces a series of objects such that requesting a new token diff --git a/src/Compilers/Core/Portable/InternalUtilities/ConfiguredYieldAwaitable.cs b/src/Dependencies/Threading/ConfiguredYieldAwaitable.cs similarity index 98% rename from src/Compilers/Core/Portable/InternalUtilities/ConfiguredYieldAwaitable.cs rename to src/Dependencies/Threading/ConfiguredYieldAwaitable.cs index 5bfa632d7488f..80502b3fbc1fc 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/ConfiguredYieldAwaitable.cs +++ b/src/Dependencies/Threading/ConfiguredYieldAwaitable.cs @@ -7,7 +7,7 @@ using System.Threading; using System.Threading.Tasks; -namespace Roslyn.Utilities +namespace Microsoft.CodeAnalysis.Threading { /// /// A custom awaiter that supports for diff --git a/src/Dependencies/Threading/Microsoft.CodeAnalysis.Threading.Package.csproj b/src/Dependencies/Threading/Microsoft.CodeAnalysis.Threading.Package.csproj new file mode 100644 index 0000000000000..ab9f373d8fec6 --- /dev/null +++ b/src/Dependencies/Threading/Microsoft.CodeAnalysis.Threading.Package.csproj @@ -0,0 +1,33 @@ + + + + + netstandard2.0 + false + none + false + true + + + true + true + Microsoft.CodeAnalysis.Threading + false + + Package containing sources of Microsoft .NET Compiler Platform ("Roslyn") threading utilities. + + + $(NoWarn);NU5128 + + + + + + + + + + + + + diff --git a/src/Dependencies/Threading/Microsoft.CodeAnalysis.Threading.projitems b/src/Dependencies/Threading/Microsoft.CodeAnalysis.Threading.projitems new file mode 100644 index 0000000000000..1e6df17045318 --- /dev/null +++ b/src/Dependencies/Threading/Microsoft.CodeAnalysis.Threading.projitems @@ -0,0 +1,30 @@ + + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + 967723E8-4FDD-447B-99F6-4F8C47CB5433 + + + Microsoft.CodeAnalysis.Threading + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Dependencies/Threading/Microsoft.CodeAnalysis.Threading.shproj b/src/Dependencies/Threading/Microsoft.CodeAnalysis.Threading.shproj new file mode 100644 index 0000000000000..d47a9e3d50b06 --- /dev/null +++ b/src/Dependencies/Threading/Microsoft.CodeAnalysis.Threading.shproj @@ -0,0 +1,14 @@ + + + + + 967723E8-4FDD-447B-99F6-4F8C47CB5433 + 14.0 + + + + + + + + \ No newline at end of file diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/TestHooks/TaskExtensions.cs b/src/Dependencies/Threading/TaskExtensions.cs similarity index 95% rename from src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/TestHooks/TaskExtensions.cs rename to src/Dependencies/Threading/TaskExtensions.cs index 9f4d7dc88b518..f35eb18a71e10 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/TestHooks/TaskExtensions.cs +++ b/src/Dependencies/Threading/TaskExtensions.cs @@ -3,13 +3,10 @@ // See the LICENSE file in the project root for more information. using System; -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; -using System.Threading; using System.Threading.Tasks; -using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Shared.TestHooks; +namespace Microsoft.CodeAnalysis.Threading; internal static partial class TaskExtensions { @@ -50,7 +47,6 @@ public readonly struct NoThrowTaskAwaitable /// Whether the continuation should be scheduled on the current sync context. public NoThrowTaskAwaitable(Task task, bool captureContext) { - Contract.ThrowIfNull(task, nameof(task)); _task = task; _captureContext = captureContext; } @@ -87,7 +83,6 @@ public NoThrowTaskAwaiter GetAwaiter() /// if set to true [capture context]. public NoThrowTaskAwaiter(Task task, bool captureContext) { - Contract.ThrowIfNull(task, nameof(task)); _task = task; _captureContext = captureContext; } diff --git a/src/Workspaces/Core/Portable/Shared/TestHooks/IAsyncToken.cs b/src/Dependencies/Threading/TestHooks/IAsyncToken.cs similarity index 100% rename from src/Workspaces/Core/Portable/Shared/TestHooks/IAsyncToken.cs rename to src/Dependencies/Threading/TestHooks/IAsyncToken.cs diff --git a/src/Workspaces/Core/Portable/Shared/TestHooks/IAsynchronousOperationListener.cs b/src/Dependencies/Threading/TestHooks/IAsynchronousOperationListener.cs similarity index 100% rename from src/Workspaces/Core/Portable/Shared/TestHooks/IAsynchronousOperationListener.cs rename to src/Dependencies/Threading/TestHooks/IAsynchronousOperationListener.cs diff --git a/src/Workspaces/Core/Portable/Shared/TestHooks/IAsynchronousOperationListenerProvider.cs b/src/Dependencies/Threading/TestHooks/IAsynchronousOperationListenerProvider.cs similarity index 100% rename from src/Workspaces/Core/Portable/Shared/TestHooks/IAsynchronousOperationListenerProvider.cs rename to src/Dependencies/Threading/TestHooks/IAsynchronousOperationListenerProvider.cs diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/TestHooks/IExpeditableDelaySource.cs b/src/Dependencies/Threading/TestHooks/IExpeditableDelaySource.cs similarity index 100% rename from src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/TestHooks/IExpeditableDelaySource.cs rename to src/Dependencies/Threading/TestHooks/IExpeditableDelaySource.cs diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/TestHooks/ValueTaskExtensions.cs b/src/Dependencies/Threading/ValueTaskExtensions.cs similarity index 98% rename from src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/TestHooks/ValueTaskExtensions.cs rename to src/Dependencies/Threading/ValueTaskExtensions.cs index 183f634b0bb43..366c3014edcda 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/TestHooks/ValueTaskExtensions.cs +++ b/src/Dependencies/Threading/ValueTaskExtensions.cs @@ -4,11 +4,9 @@ using System; using System.Runtime.CompilerServices; -using System.Runtime.ExceptionServices; using System.Threading.Tasks; -using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Shared.TestHooks; +namespace Microsoft.CodeAnalysis.Threading; internal static class ValueTaskExtensions { diff --git a/src/Dependencies/Threading/VoidResult.cs b/src/Dependencies/Threading/VoidResult.cs new file mode 100644 index 0000000000000..2e626ce7209d5 --- /dev/null +++ b/src/Dependencies/Threading/VoidResult.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; + +namespace Microsoft.CodeAnalysis.Threading; + +/// +/// Explicitly indicates result is void +/// +internal readonly struct VoidResult : IEquatable +{ + public override bool Equals(object? obj) + => obj is VoidResult; + + public override int GetHashCode() + => 0; + + public bool Equals(VoidResult other) + => true; +} diff --git a/src/Dependencies/Threading/YieldAwaitableExtensions.cs b/src/Dependencies/Threading/YieldAwaitableExtensions.cs new file mode 100644 index 0000000000000..6cd6f6db5794b --- /dev/null +++ b/src/Dependencies/Threading/YieldAwaitableExtensions.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.CompilerServices; +using System.Threading.Tasks; + +namespace Microsoft.CodeAnalysis.Threading; + +internal static class YieldAwaitableExtensions +{ + /// + /// Implements ConfigureAwait(bool) for . The resulting behavior in asynchronous code + /// is the same as one would expect for . + /// + /// The awaitable provided by . + /// + /// An object used to await this yield. + public static ConfiguredYieldAwaitable ConfigureAwait(this YieldAwaitable awaitable, bool continueOnCapturedContext) + { + return new ConfiguredYieldAwaitable(awaitable, continueOnCapturedContext); + } +} diff --git a/src/EditorFeatures/CSharp/ChangeSignature/CSharpChangeSignatureCommandHandler.cs b/src/EditorFeatures/CSharp/ChangeSignature/CSharpChangeSignatureCommandHandler.cs index 0d05a0d03f487..414e316e9ef5c 100644 --- a/src/EditorFeatures/CSharp/ChangeSignature/CSharpChangeSignatureCommandHandler.cs +++ b/src/EditorFeatures/CSharp/ChangeSignature/CSharpChangeSignatureCommandHandler.cs @@ -7,7 +7,6 @@ using Microsoft.CodeAnalysis.ChangeSignature; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Utilities; diff --git a/src/EditorFeatures/CSharp/CodeCleanup/CSharpCodeCleanupService.cs b/src/EditorFeatures/CSharp/CodeCleanup/CSharpCodeCleanupService.cs index 083c1ca0978b4..f00c77eb4d622 100644 --- a/src/EditorFeatures/CSharp/CodeCleanup/CSharpCodeCleanupService.cs +++ b/src/EditorFeatures/CSharp/CodeCleanup/CSharpCodeCleanupService.cs @@ -36,7 +36,7 @@ internal class CSharpCodeCleanupService(ICodeFixService codeFixService, IDiagnos IDEDiagnosticIds.RemoveUnnecessaryParenthesesDiagnosticId, IDEDiagnosticIds.AddRequiredParenthesesDiagnosticId), new DiagnosticSet(AnalyzersResources.Add_accessibility_modifiers, - IDEDiagnosticIds.AddAccessibilityModifiersDiagnosticId), + IDEDiagnosticIds.AddOrRemoveAccessibilityModifiersDiagnosticId), new DiagnosticSet(FeaturesResources.Apply_coalesce_expression_preferences, IDEDiagnosticIds.UseCoalesceExpressionForTernaryConditionalCheckDiagnosticId), new DiagnosticSet(FeaturesResources.Apply_object_collection_initialization_preferences, diff --git a/src/EditorFeatures/CSharp/CompleteStatement/CompleteStatementCommandHandler.cs b/src/EditorFeatures/CSharp/CompleteStatement/CompleteStatementCommandHandler.cs index 2bc5648d8b235..6f45619a5fc92 100644 --- a/src/EditorFeatures/CSharp/CompleteStatement/CompleteStatementCommandHandler.cs +++ b/src/EditorFeatures/CSharp/CompleteStatement/CompleteStatementCommandHandler.cs @@ -172,7 +172,7 @@ private static bool TryGetStartingNode( startingNode = tokenOnLeft.GetRequiredParent(); - // If the caret is before an opening delimiter or after a closing delimeter, + // If the caret is before an opening delimiter or after a closing delimiter, // start analysis with node outside of delimiters. // // Examples, diff --git a/src/EditorFeatures/CSharp/DocumentationComments/DocumentationCommentCommandHandler.cs b/src/EditorFeatures/CSharp/DocumentationComments/DocumentationCommentCommandHandler.cs index a0b5d4a0b5726..0fe739c2930be 100644 --- a/src/EditorFeatures/CSharp/DocumentationComments/DocumentationCommentCommandHandler.cs +++ b/src/EditorFeatures/CSharp/DocumentationComments/DocumentationCommentCommandHandler.cs @@ -25,8 +25,10 @@ internal sealed class DocumentationCommentCommandHandler( IUIThreadOperationExecutor uiThreadOperationExecutor, ITextUndoHistoryRegistry undoHistoryRegistry, IEditorOperationsFactoryService editorOperationsFactoryService, - EditorOptionsService editorOptionsService) - : AbstractDocumentationCommentCommandHandler(uiThreadOperationExecutor, undoHistoryRegistry, editorOperationsFactoryService, editorOptionsService) + EditorOptionsService editorOptionsService, + CopilotGenerateDocumentationCommentManager generateDocumentationCommentManager) + : AbstractDocumentationCommentCommandHandler(uiThreadOperationExecutor, undoHistoryRegistry, + editorOperationsFactoryService, editorOptionsService, generateDocumentationCommentManager) { protected override string ExteriorTriviaText => "///"; } diff --git a/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs b/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs index 809ef38fa78aa..202bca0eb7023 100644 --- a/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs +++ b/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs @@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Editor.BackgroundWorkIndicator; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; -using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.EventHookup; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.LanguageService; diff --git a/src/EditorFeatures/CSharp/Formatting/CSharpFormattingInteractionService.cs b/src/EditorFeatures/CSharp/Formatting/CSharpFormattingInteractionService.cs index 538b8250aaaae..fd247d02858f6 100644 --- a/src/EditorFeatures/CSharp/Formatting/CSharpFormattingInteractionService.cs +++ b/src/EditorFeatures/CSharp/Formatting/CSharpFormattingInteractionService.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; diff --git a/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler.cs b/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler.cs index 1fa853da29253..9b6ee3f333efe 100644 --- a/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler.cs +++ b/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler.cs @@ -8,7 +8,6 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.Commanding; -using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Operations; using Microsoft.VisualStudio.Utilities; @@ -20,18 +19,14 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.RawStringLiteral; [Order(After = nameof(SplitStringLiteralCommandHandler))] [method: ImportingConstructor] [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] -internal partial class RawStringLiteralCommandHandler( +internal sealed partial class RawStringLiteralCommandHandler( ITextUndoHistoryRegistry undoHistoryRegistry, - IGlobalOptionService globalOptions, IEditorOperationsFactoryService editorOperationsFactoryService, - EditorOptionsService editorOptionsService, - IIndentationManagerService indentationManager) + EditorOptionsService editorOptionsService) { private readonly ITextUndoHistoryRegistry _undoHistoryRegistry = undoHistoryRegistry; - private readonly IGlobalOptionService _globalOptions = globalOptions; private readonly IEditorOperationsFactoryService _editorOperationsFactoryService = editorOperationsFactoryService; private readonly EditorOptionsService _editorOptionsService = editorOptionsService; - private readonly IIndentationManagerService _indentationManager = indentationManager; public string DisplayName => CSharpEditorResources.Split_raw_string; } diff --git a/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler_Return.cs b/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler_Return.cs index 22c871fa7b1b8..6170f34428627 100644 --- a/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler_Return.cs +++ b/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler_Return.cs @@ -2,8 +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.Diagnostics; using System.Linq; -using System.Threading; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; @@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; using Roslyn.Utilities; @@ -31,6 +30,8 @@ public CommandState GetCommandState(ReturnKeyCommandArgs args) /// public bool ExecuteCommand(ReturnKeyCommandArgs args, CommandExecutionContext context) { + var cancellationToken = context.OperationContext.UserCancellationToken; + var textView = args.TextView; var subjectBuffer = args.SubjectBuffer; var spans = textView.Selection.GetSnapshotSpansOnBuffer(subjectBuffer); @@ -51,8 +52,6 @@ public bool ExecuteCommand(ReturnKeyCommandArgs args, CommandExecutionContext co if (position >= currentSnapshot.Length) return false; - var cancellationToken = context.OperationContext.UserCancellationToken; - var document = currentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document == null) return false; @@ -77,6 +76,10 @@ bool ExecuteReturnCommandBeforeQuoteCharacter() quotesAfter++; } + // We must have at least one following quote, as we only got into ExecuteReturnCommandBeforeQuoteCharacter + // if there was a quote character in front of it. + Debug.Assert(quotesAfter > 0); + for (var i = position - 1; i >= 0; i--) { if (currentSnapshot[i] != '"') @@ -110,6 +113,14 @@ SyntaxKind.InterpolatedSingleLineRawStringStartToken or return false; } + if (!isEmpty) + { + // in the non empty case (e.g. `"""goo$$"""`) we have to make sure sure that the caret is before the + // final quotes, not the initial ones. + if (token.Span.End - quotesAfter != position) + return false; + } + return MakeEdit(parsedDocument, expression, isEmpty); } diff --git a/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler_TypeChar.cs b/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler_TypeChar.cs index f652c81fd8d2b..39b6b3ee56903 100644 --- a/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler_TypeChar.cs +++ b/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler_TypeChar.cs @@ -53,7 +53,7 @@ private bool ExecuteCommandWorker(TypeCharCommandArgs args, Action nextCommandHa var textChangeOpt = TryGenerateInitialEmptyRawString(caret.Value, cancellationToken) ?? TryGrowInitialEmptyRawString(caret.Value, cancellationToken) ?? - TryGrowRawStringDelimeters(caret.Value, cancellationToken); + TryGrowRawStringDelimiters(caret.Value, cancellationToken); if (textChangeOpt is not TextChange textChange) return false; @@ -115,8 +115,13 @@ private bool ExecuteCommandWorker(TypeCharCommandArgs args, Action nextCommandHa if (token.SpanStart != start) return null; - if (token.Kind() is not (SyntaxKind.StringLiteralToken or SyntaxKind.InterpolatedStringStartToken or SyntaxKind.InterpolatedSingleLineRawStringStartToken)) + if (token.Kind() is not (SyntaxKind.StringLiteralToken or + SyntaxKind.InterpolatedStringStartToken or + SyntaxKind.InterpolatedSingleLineRawStringStartToken or + SyntaxKind.InterpolatedMultiLineRawStringStartToken)) + { return null; + } return new TextChange(new TextSpan(position + 1, 0), "\"\"\""); } @@ -124,8 +129,8 @@ private bool ExecuteCommandWorker(TypeCharCommandArgs args, Action nextCommandHa /// /// When typing " given a raw string like """$$""" (or a similar multiline form), then update the /// text to be: """"$$"""". i.e. grow both the start and end delimiters to keep the string properly - /// balanced. This differs from TryGrowRawStringDelimeters in that the language will consider that initial - /// """""" text to be a single delimeter, while we want to treat it as two. + /// balanced. This differs from TryGrowRawStringDelimiters in that the language will consider that initial + /// """""" text to be a single delimiter, while we want to treat it as two. /// private static TextChange? TryGrowInitialEmptyRawString( SnapshotPoint caret, @@ -183,7 +188,7 @@ SyntaxKind.InterpolatedSingleLineRawStringStartToken or /// update the text to be: """" goo bar """". i.e. grow both the start and end delimiters to keep the /// string properly balanced. /// - private static TextChange? TryGrowRawStringDelimeters( + private static TextChange? TryGrowRawStringDelimiters( SnapshotPoint caret, CancellationToken cancellationToken) { @@ -191,7 +196,7 @@ SyntaxKind.InterpolatedSingleLineRawStringStartToken or var position = caret.Position; // if we have """$$" then typing `"` here should not grow the start/end quotes. we only want to grow them - // if the user is at the end of the start delimeter. + // if the user is at the end of the start delimiter. if (position < snapshot.Length && snapshot[position] == '"') return null; diff --git a/src/EditorFeatures/CSharp/StringCopyPaste/AbstractPasteProcessor.cs b/src/EditorFeatures/CSharp/StringCopyPaste/AbstractPasteProcessor.cs index 162aada98d09b..bf2d7c8abbb5f 100644 --- a/src/EditorFeatures/CSharp/StringCopyPaste/AbstractPasteProcessor.cs +++ b/src/EditorFeatures/CSharp/StringCopyPaste/AbstractPasteProcessor.cs @@ -8,7 +8,6 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.CSharp.StringCopyPaste; diff --git a/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteCommandHandler.cs b/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteCommandHandler.cs index d1f7077462368..a2ea589d312ba 100644 --- a/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteCommandHandler.cs +++ b/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteCommandHandler.cs @@ -26,7 +26,6 @@ using Microsoft.VisualStudio.Text.Editor.OptionsExtensionMethods; using Microsoft.VisualStudio.Text.Operations; using Microsoft.VisualStudio.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.CSharp.StringCopyPaste; diff --git a/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteCommandHandler_CutCopy.cs b/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteCommandHandler_CutCopy.cs index b4b10da7c9c5c..85dfeaabe7766 100644 --- a/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteCommandHandler_CutCopy.cs +++ b/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteCommandHandler_CutCopy.cs @@ -13,7 +13,6 @@ using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.CSharp.StringCopyPaste; diff --git a/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteData.cs b/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteData.cs index d183eb9652434..0178a3eb22b6c 100644 --- a/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteData.cs +++ b/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteData.cs @@ -11,7 +11,6 @@ using System.Text.Json.Serialization; using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.Editor.CSharp.StringCopyPaste; diff --git a/src/EditorFeatures/CSharp/StringCopyPaste/StringInfo.cs b/src/EditorFeatures/CSharp/StringCopyPaste/StringInfo.cs index fa453c402f813..b8b9e298e8091 100644 --- a/src/EditorFeatures/CSharp/StringCopyPaste/StringInfo.cs +++ b/src/EditorFeatures/CSharp/StringCopyPaste/StringInfo.cs @@ -7,7 +7,6 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.CSharp.StringCopyPaste; diff --git a/src/EditorFeatures/CSharp/TextStructureNavigation/CSharpTextStructureNavigatorProvider.cs b/src/EditorFeatures/CSharp/TextStructureNavigation/CSharpTextStructureNavigatorProvider.cs index 26f0775e849f4..d7f65690b4a56 100644 --- a/src/EditorFeatures/CSharp/TextStructureNavigation/CSharpTextStructureNavigatorProvider.cs +++ b/src/EditorFeatures/CSharp/TextStructureNavigation/CSharpTextStructureNavigatorProvider.cs @@ -97,7 +97,7 @@ protected override TextExtent GetExtentOfWordFromToken(ITextStructureNavigator n contentStart++; } - var end = token.Span.End; + var end = Math.Max(contentStart, token.Span.End); var contentEnd = end; if (CharAt(contentEnd - 1) == '8') @@ -115,6 +115,8 @@ protected override TextExtent GetExtentOfWordFromToken(ITextStructureNavigator n contentEnd--; } + // Ensure that in error conditions like a naked `"` that we don't end up with invalid bounds. + contentEnd = Math.Max(contentStart, contentEnd); return (TextSpan.FromBounds(start, contentStart), TextSpan.FromBounds(contentStart, contentEnd), TextSpan.FromBounds(contentEnd, end)); } diff --git a/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticBraceCompletionTests.cs b/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticBraceCompletionTests.cs index 21dc30a5381f9..5460ab773426a 100644 --- a/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticBraceCompletionTests.cs +++ b/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticBraceCompletionTests.cs @@ -4,7 +4,9 @@ using System; using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Formatting; +using Microsoft.CodeAnalysis.CSharp.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.UnitTests.AutomaticCompletion; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Formatting; @@ -1852,12 +1854,56 @@ namespace NS1 CheckReturn(session.Session, 0, expectedAfterReturn); } + [WpfFact] + public void ModernExtension() + { + var code = """ + namespace N + { + static class C + { + extension(string s) $$ + } + } + """; + + var expectedBeforeReturn = """ + namespace N + { + static class C + { + extension(string s) { } + } + } + """; + + var expectedAfterReturn = """ + namespace N + { + static class C + { + extension(string s) + { + + } + } + } + """; + using var session = CreateSession(code, parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersionExtensions.CSharpNext)); + Assert.NotNull(session); + + CheckStart(session.Session); + CheckText(session.Session, expectedBeforeReturn); + CheckReturn(session.Session, 12, expectedAfterReturn); + } + internal static Holder CreateSession( [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string code, - OptionsCollection? globalOptions = null) + OptionsCollection? globalOptions = null, + ParseOptions? parseOptions = null) { return CreateSession( - EditorTestWorkspace.CreateCSharp(code), + EditorTestWorkspace.CreateCSharp(code, parseOptions), CurlyBrace.OpenCharacter, CurlyBrace.CloseCharacter, globalOptions); } } diff --git a/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticParenthesisCompletionTests.cs b/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticParenthesisCompletionTests.cs index 993f53e89eebe..e8b9f97eb9750 100644 --- a/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticParenthesisCompletionTests.cs +++ b/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticParenthesisCompletionTests.cs @@ -2,8 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.UnitTests.AutomaticCompletion; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; @@ -193,10 +193,26 @@ public static A Create() CheckStart(session.Session, expectValidSession: false); } - internal static Holder CreateSession(string code) + [WpfFact] + public void ExtensionParameterList_OpenParenthesis_Delete() + { + var code = """ + static class C + { + extension$$ + } + """; + + using var session = CreateSession(code, CSharpParseOptions.Default.WithLanguageVersion(LanguageVersionExtensions.CSharpNext)); + Assert.NotNull(session); + CheckStart(session.Session); + CheckBackspace(session.Session); + } + + internal static Holder CreateSession(string code, ParseOptions? parseOptions = null) { return CreateSession( - EditorTestWorkspace.CreateCSharp(code), + EditorTestWorkspace.CreateCSharp(code, parseOptions), Parenthesis.OpenCharacter, Parenthesis.CloseCharacter); } } diff --git a/src/EditorFeatures/CSharpTest/Classification/SemanticClassifierTests_Regex.cs b/src/EditorFeatures/CSharpTest/Classification/SemanticClassifierTests_Regex.cs index c1a4348299cd1..f011511041a70 100644 --- a/src/EditorFeatures/CSharpTest/Classification/SemanticClassifierTests_Regex.cs +++ b/src/EditorFeatures/CSharpTest/Classification/SemanticClassifierTests_Regex.cs @@ -1312,4 +1312,70 @@ void Goo() Namespace("RegularExpressions"), Keyword("var")); } + + [Theory, CombinatorialData] + [WorkItem("https://github.com/dotnet/roslyn/issues/77189")] + public async Task TestStringFieldUsedLater_ProperModifiers( + TestHost testHost, + [CombinatorialValues("const", "static readonly")] string modifiers) + { + await TestAsync( + $$""" + using System.Diagnostics.CodeAnalysis; + using System.Text.RegularExpressions; + + class Program + { + private {{modifiers}} string regexValue = [|@"$(\a\t\u0020)"|]; + + void Goo() + { + Bar(regexValue); + } + + void Bar([StringSyntax(StringSyntaxAttribute.Regex)] string p) + { + } + } + """ + EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp, + testHost, + Regex.Anchor("$"), + Regex.Grouping("("), + Regex.OtherEscape("\\"), + Regex.OtherEscape("a"), + Regex.OtherEscape("\\"), + Regex.OtherEscape("t"), + Regex.OtherEscape("\\"), + Regex.OtherEscape("u"), + Regex.OtherEscape("0020"), + Regex.Grouping(")")); + } + + [Theory, CombinatorialData] + [WorkItem("https://github.com/dotnet/roslyn/issues/77189")] + public async Task TestStringFieldUsedLater_ImproperModifiers( + TestHost testHost, + [CombinatorialValues("", "static", "readonly")] string modifiers) + { + await TestAsync( + $$""" + using System.Diagnostics.CodeAnalysis; + using System.Text.RegularExpressions; + + class Program + { + private {{modifiers}} string regexValue = [|@"$(\a\t\u0020)"|]; + + void Goo() + { + Bar(regexValue); + } + + void Bar([StringSyntax(StringSyntaxAttribute.Regex)] string p) + { + } + } + """ + EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp, + testHost); + } } diff --git a/src/EditorFeatures/CSharpTest/CodeActions/AddUsing/AddUsingTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/AddUsing/AddUsingTests.cs index 553f3dc7c3415..7a55d39720be5 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/AddUsing/AddUsingTests.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/AddUsing/AddUsingTests.cs @@ -3,13 +3,11 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Collections.Immutable; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Remote.Testing; using Microsoft.CodeAnalysis.Tags; using Microsoft.CodeAnalysis.Test.Utilities; diff --git a/src/EditorFeatures/CSharpTest/CodeActions/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersTests.cs index ed9be9de37571..aa38c36ea5655 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersTests.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersTests.cs @@ -4400,4 +4400,19 @@ public override int GetHashCode() LanguageVersion = LanguageVersion.Default, }.RunAsync(); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76916")] + public async Task TestMissingWithPrimaryConstructorAndNoFields() + { + await new VerifyCS.Test + { + TestCode = """ + class C(int a) + { + [||] + } + """, + LanguageVersion = LanguageVersion.CSharp12, + }.RunAsync(); + } } diff --git a/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.cs b/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.cs index cacb71edb2822..df6fe69dee917 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.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.Immutable; using System.Threading.Tasks; using Microsoft.CodeAnalysis.GenerateType; using Microsoft.CodeAnalysis.Test.Utilities; diff --git a/src/EditorFeatures/CSharpTest/CodeActions/InitializeParameter/AddParameterCheckTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/InitializeParameter/AddParameterCheckTests.cs index 51e66334cc26d..ba0ebdce47118 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/InitializeParameter/AddParameterCheckTests.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/InitializeParameter/AddParameterCheckTests.cs @@ -30,7 +30,7 @@ public async Task TestEmptyFile() } [Fact] - public async Task TestSimpleReferenceType_AlreadyNullChecked() + public async Task TestSimpleReferenceType_AlreadyNullChecked1() { var testCode = """ using System; @@ -53,6 +53,27 @@ public C([||]string s) }.RunAsync(); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/61181")] + public async Task TestSimpleReferenceType_AlreadyNullChecked2() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + + class C + { + public C([||]string s) + { + ArgumentNullException.ThrowIfNull(s); + } + } + """, + LanguageVersion = LanguageVersion.CSharp11, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, + }.RunAsync(); + } + [Fact] public async Task TestSimpleReferenceType() { @@ -83,6 +104,36 @@ public C(string s) """); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/61181")] + public async Task TestSimpleReferenceType_ThrowIfNull() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + + class C + { + public C([||]string s) + { + } + } + """, + FixedCode = """ + using System; + + class C + { + public C(string s) + { + ArgumentNullException.ThrowIfNull(s); + } + } + """, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, + }.RunAsync(); + } + [Fact] public async Task TestSimpleReferenceType_CSharp6() { @@ -521,45 +572,81 @@ public C([||]string a, string b, string c) } } """, - FixedCode = @$"using System; + FixedCode = $$""" + using System; -class C -{{ - public C(string a, string b, string c) - {{ - if (string.IsNullOrEmpty(a)) - {{ - throw new ArgumentException($""{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(a)}").Replace(""" + class C + { + public C(string a, string b, string c) + { + if (string.IsNullOrEmpty(a)) + { + throw new ArgumentException($"{{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(a)}").Replace(""" " """, """ \" - """)}"", nameof(a)); - }} + """)}}", nameof(a)); + } - if (string.IsNullOrEmpty(b)) - {{ - throw new ArgumentException($""{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(b)}").Replace(""" + if (string.IsNullOrEmpty(b)) + { + throw new ArgumentException($"{{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(b)}").Replace(""" " """, """ \" - """)}"", nameof(b)); - }} + """)}}", nameof(b)); + } - if (string.IsNullOrEmpty(c)) - {{ - throw new ArgumentException($""{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(c)}").Replace(""" + if (string.IsNullOrEmpty(c)) + { + throw new ArgumentException($"{{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(c)}").Replace(""" " """, """ \" - """)}"", nameof(c)); - }} - }} -}}", + """)}}", nameof(c)); + } + } + } + """, CodeActionIndex = 3, CodeActionEquivalenceKey = nameof(FeaturesResources.Add_null_checks_for_all_parameters) }.RunAsync(); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/61181")] + public async Task TestMultiNullableParameters_Net7() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + + class C + { + public C([||]string a, string b, string c) + { + } + } + """, + FixedCode = $$""" + using System; + + class C + { + public C(string a, string b, string c) + { + ArgumentException.ThrowIfNullOrEmpty(a); + ArgumentException.ThrowIfNullOrEmpty(b); + ArgumentException.ThrowIfNullOrEmpty(c); + } + } + """, + CodeActionIndex = 3, + CodeActionEquivalenceKey = nameof(FeaturesResources.Add_null_checks_for_all_parameters), + ReferenceAssemblies = ReferenceAssemblies.Net.Net70, + }.RunAsync(); + } + [Fact] public async Task TestMultiNullableParametersSomeNullableReferenceTypes() { @@ -577,33 +664,35 @@ public C([||]string a, string b, string? c) } } """, - FixedCode = @$"#nullable enable + FixedCode = $$""" + #nullable enable -using System; + using System; -class C -{{ - public C(string a, string b, string? c) - {{ - if (string.IsNullOrEmpty(a)) - {{ - throw new ArgumentException($""{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(a)}").Replace(""" + class C + { + public C(string a, string b, string? c) + { + if (string.IsNullOrEmpty(a)) + { + throw new ArgumentException($"{{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(a)}").Replace(""" " """, """ \" - """)}"", nameof(a)); - }} + """)}}", nameof(a)); + } - if (string.IsNullOrEmpty(b)) - {{ - throw new ArgumentException($""{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(b)}").Replace(""" + if (string.IsNullOrEmpty(b)) + { + throw new ArgumentException($"{{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(b)}").Replace(""" " """, """ \" - """)}"", nameof(b)); - }} - }} -}}", + """)}}", nameof(b)); + } + } + } + """, CodeActionIndex = 3, CodeActionEquivalenceKey = nameof(FeaturesResources.Add_null_checks_for_all_parameters) }.RunAsync(); @@ -640,31 +729,33 @@ public C(string a, [||]bool b, string c) } } """, - FixedCode = @$"using System; + FixedCode = $$""" + using System; -class C -{{ - public C(string a, bool b, string c) - {{ - if (string.IsNullOrEmpty(a)) - {{ - throw new ArgumentException($""{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(a)}").Replace(""" + class C + { + public C(string a, bool b, string c) + { + if (string.IsNullOrEmpty(a)) + { + throw new ArgumentException($"{{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(a)}").Replace(""" " """, """ \" - """)}"", nameof(a)); - }} + """)}}", nameof(a)); + } - if (string.IsNullOrEmpty(c)) - {{ - throw new ArgumentException($""{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(c)}").Replace(""" + if (string.IsNullOrEmpty(c)) + { + throw new ArgumentException($"{{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(c)}").Replace(""" " """, """ \" - """)}"", nameof(c)); - }} - }} -}}", + """)}}", nameof(c)); + } + } + } + """, CodeActionIndex = 0, CodeActionEquivalenceKey = nameof(FeaturesResources.Add_null_checks_for_all_parameters) }.RunAsync(); @@ -685,31 +776,33 @@ public C([||]string a, bool b, string c) } } """, - FixedCode = @$"using System; + FixedCode = $$""" + using System; -class C -{{ - public C(string a, bool b, string c) - {{ - if (string.IsNullOrEmpty(a)) - {{ - throw new ArgumentException($""{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(a)}").Replace(""" + class C + { + public C(string a, bool b, string c) + { + if (string.IsNullOrEmpty(a)) + { + throw new ArgumentException($"{{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(a)}").Replace(""" " """, """ \" - """)}"", nameof(a)); - }} + """)}}", nameof(a)); + } - if (string.IsNullOrEmpty(c)) - {{ - throw new ArgumentException($""{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(c)}").Replace(""" + if (string.IsNullOrEmpty(c)) + { + throw new ArgumentException($"{{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(c)}").Replace(""" " """, """ \" - """)}"", nameof(c)); - }} - }} -}}", + """)}}", nameof(c)); + } + } + } + """, CodeActionIndex = 3, CodeActionEquivalenceKey = nameof(FeaturesResources.Add_null_checks_for_all_parameters) }.RunAsync(); @@ -730,36 +823,38 @@ public C([||]string a, object b, string c) } } """, - FixedCode = @$"using System; + FixedCode = $$""" + using System; -class C -{{ - public C(string a, object b, string c) - {{ - if (string.IsNullOrEmpty(a)) - {{ - throw new ArgumentException($""{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(a)}").Replace(""" + class C + { + public C(string a, object b, string c) + { + if (string.IsNullOrEmpty(a)) + { + throw new ArgumentException($"{{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(a)}").Replace(""" " """, """ \" - """)}"", nameof(a)); - }} + """)}}", nameof(a)); + } - if (b is null) - {{ - throw new ArgumentNullException(nameof(b)); - }} + if (b is null) + { + throw new ArgumentNullException(nameof(b)); + } - if (string.IsNullOrEmpty(c)) - {{ - throw new ArgumentException($""{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(c)}").Replace(""" + if (string.IsNullOrEmpty(c)) + { + throw new ArgumentException($"{{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(c)}").Replace(""" " """, """ \" - """)}"", nameof(c)); - }} - }} -}}", + """)}}", nameof(c)); + } + } + } + """, CodeActionIndex = 3, CodeActionEquivalenceKey = nameof(FeaturesResources.Add_null_checks_for_all_parameters) }.RunAsync(); @@ -1864,22 +1959,24 @@ public C([||]string s) } } """, - FixedCode = $@"using System; + FixedCode = $$""" + using System; -class C -{{ - public C(string s) - {{ - if (string.IsNullOrEmpty(s)) - {{ - throw new ArgumentException($""{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(s)}").Replace(""" + class C + { + public C(string s) + { + if (string.IsNullOrEmpty(s)) + { + throw new ArgumentException($"{{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(s)}").Replace(""" " """, """ \" - """)}"", nameof(s)); - }} - }} -}}", + """)}}", nameof(s)); + } + } + } + """, CodeActionIndex = 1, CodeActionEquivalenceKey = nameof(FeaturesResources.Add_string_IsNullOrEmpty_check) }.RunAsync(); @@ -1900,27 +1997,61 @@ public C([||]string s) } } """, - FixedCode = $@"using System; + FixedCode = $$""" + using System; -class C -{{ - public C(string s) - {{ - if (string.IsNullOrWhiteSpace(s)) - {{ - throw new ArgumentException($""{string.Format(FeaturesResources._0_cannot_be_null_or_whitespace, "{nameof(s)}").Replace(""" + class C + { + public C(string s) + { + if (string.IsNullOrWhiteSpace(s)) + { + throw new ArgumentException($"{{string.Format(FeaturesResources._0_cannot_be_null_or_whitespace, "{nameof(s)}").Replace(""" " """, """ \" - """)}"", nameof(s)); - }} - }} -}}", + """)}}", nameof(s)); + } + } + } + """, CodeActionIndex = 2, CodeActionEquivalenceKey = nameof(FeaturesResources.Add_string_IsNullOrWhiteSpace_check) }.RunAsync(); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/61181")] + public async Task TestSpecialStringCheck2_Net8() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + + class C + { + public C([||]string s) + { + } + } + """, + FixedCode = $$""" + using System; + + class C + { + public C(string s) + { + ArgumentException.ThrowIfNullOrWhiteSpace(s); + } + } + """, + CodeActionIndex = 2, + CodeActionEquivalenceKey = nameof(FeaturesResources.Add_string_IsNullOrWhiteSpace_check), + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + }.RunAsync(); + } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/51338")] [UseCulture("de-DE", "de-DE")] public async Task TestSpecialStringCheck3() @@ -1937,22 +2068,24 @@ public C([||]string s) } } """, - FixedCode = $@"using System; + FixedCode = $$""" + using System; -class C -{{ - public C(string s) - {{ - if (string.IsNullOrEmpty(s)) - {{ - throw new ArgumentException($""{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(s)}").Replace(""" + class C + { + public C(string s) + { + if (string.IsNullOrEmpty(s)) + { + throw new ArgumentException($"{{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(s)}").Replace(""" " """, """ \" - """)}"", nameof(s)); - }} - }} -}}", + """)}}", nameof(s)); + } + } + } + """, CodeActionIndex = 1, CodeActionEquivalenceKey = nameof(FeaturesResources.Add_string_IsNullOrEmpty_check) }.RunAsync(); @@ -1991,22 +2124,24 @@ static void Main([||]String bar) } } """, - FixedCode = @$"using System; + FixedCode = $$""" + using System; -class Program -{{ - static void Main(String bar) - {{ - if (String.IsNullOrEmpty(bar)) - {{ - throw new ArgumentException($""{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(bar)}").Replace(""" + class Program + { + static void Main(String bar) + { + if (String.IsNullOrEmpty(bar)) + { + throw new ArgumentException($"{{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(bar)}").Replace(""" " """, """ \" - """)}"", nameof(bar)); - }} - }} -}}", + """)}}", nameof(bar)); + } + } + } + """, CodeActionIndex = 1, CodeActionEquivalenceKey = nameof(FeaturesResources.Add_string_IsNullOrEmpty_check), Options = @@ -2583,20 +2718,22 @@ public C($$string s) } } """, - FixedCode = $@"using System; + FixedCode = $$""" + using System; -class C -{{ - public C(string s) - {{ - if (string.IsNullOrEmpty(s)) - throw new ArgumentException($""{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(s)}").Replace(""" + class C + { + public C(string s) + { + if (string.IsNullOrEmpty(s)) + throw new ArgumentException($"{{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(s)}").Replace(""" " """, """ \" - """)}"", nameof(s)); - }} -}}", + """)}}", nameof(s)); + } + } + """, Options = { { CSharpCodeStyleOptions.PreferThrowExpression, false }, @@ -2623,20 +2760,22 @@ public C($$string s) } } """, - FixedCode = @$"using System; + FixedCode = $$""" + using System; -class C -{{ - public C(string s) - {{ - if (string.IsNullOrEmpty(s)) - throw new ArgumentException($""{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(s)}").Replace(""" + class C + { + public C(string s) + { + if (string.IsNullOrEmpty(s)) + throw new ArgumentException($"{{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(s)}").Replace(""" " """, """ \" - """)}"", nameof(s)); - }} -}}", + """)}}", nameof(s)); + } + } + """, Options = { { CSharpCodeStyleOptions.PreferThrowExpression, false }, @@ -2663,22 +2802,24 @@ public C($$string s) } } """, - FixedCode = @$"using System; + FixedCode = $$""" + using System; -class C -{{ - public C(string s) - {{ - if (string.IsNullOrEmpty(s)) - {{ - throw new ArgumentException($""{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(s)}").Replace(""" + class C + { + public C(string s) + { + if (string.IsNullOrEmpty(s)) + { + throw new ArgumentException($"{{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(s)}").Replace(""" " """, """ \" - """)}"", nameof(s)); - }} - }} -}}", + """)}}", nameof(s)); + } + } + } + """, Options = { { CSharpCodeStyleOptions.PreferThrowExpression, false }, @@ -2705,19 +2846,21 @@ public C($$string s) } } """, - FixedCode = @$"using System; + FixedCode = $$""" + using System; -class C -{{ - public C(string s) - {{ - if (string.IsNullOrEmpty(s)) throw new ArgumentException($""{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(s)}").Replace(""" + class C + { + public C(string s) + { + if (string.IsNullOrEmpty(s)) throw new ArgumentException($"{{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(s)}").Replace(""" " """, """ \" - """)}"", nameof(s)); - }} -}}", + """)}}", nameof(s)); + } + } + """, Options = { { CSharpCodeStyleOptions.PreferThrowExpression, false }, @@ -2744,19 +2887,21 @@ public C($$string s) } } """, - FixedCode = @$"using System; + FixedCode = $$""" + using System; -class C -{{ - public C(string s) - {{ - if (string.IsNullOrEmpty(s)) throw new ArgumentException($""{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(s)}").Replace(""" + class C + { + public C(string s) + { + if (string.IsNullOrEmpty(s)) throw new ArgumentException($"{{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(s)}").Replace(""" " """, """ \" - """)}"", nameof(s)); - }} -}}", + """)}}", nameof(s)); + } + } + """, Options = { { CSharpCodeStyleOptions.PreferThrowExpression, false }, @@ -2783,22 +2928,24 @@ public C($$string s) } } """, - FixedCode = @$"using System; + FixedCode = $$""" + using System; -class C -{{ - public C(string s) - {{ - if (string.IsNullOrEmpty(s)) - {{ - throw new ArgumentException($""{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(s)}").Replace(""" + class C + { + public C(string s) + { + if (string.IsNullOrEmpty(s)) + { + throw new ArgumentException($"{{string.Format(FeaturesResources._0_cannot_be_null_or_empty, "{nameof(s)}").Replace(""" " """, """ \" - """)}"", nameof(s)); - }} - }} -}}", + """)}}", nameof(s)); + } + } + } + """, Options = { { CSharpCodeStyleOptions.PreferThrowExpression, false }, diff --git a/src/EditorFeatures/CSharpTest/CodeActions/MoveType/MoveTypeTests.MoveScope.cs b/src/EditorFeatures/CSharpTest/CodeActions/MoveType/MoveTypeTests.MoveScope.cs index fa203ef7f5a51..6f6d30a1ece97 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/MoveType/MoveTypeTests.MoveScope.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/MoveType/MoveTypeTests.MoveScope.cs @@ -6,7 +6,6 @@ using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings.MoveType; using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.Formatting; diff --git a/src/EditorFeatures/CSharpTest/CodeActions/MoveType/MoveTypeTests.MoveToNewFile.cs b/src/EditorFeatures/CSharpTest/CodeActions/MoveType/MoveTypeTests.MoveToNewFile.cs index a698667972f75..1fd02d76caab3 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/MoveType/MoveTypeTests.MoveToNewFile.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/MoveType/MoveTypeTests.MoveToNewFile.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.Immutable; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Test.Utilities; diff --git a/src/EditorFeatures/CSharpTest/CodeActions/SyncNamespace/CSharpSyncNamespaceTestsBase.cs b/src/EditorFeatures/CSharpTest/CodeActions/SyncNamespace/CSharpSyncNamespaceTestsBase.cs index b6377fe8b2dbd..52708bf17e7d4 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/SyncNamespace/CSharpSyncNamespaceTestsBase.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/SyncNamespace/CSharpSyncNamespaceTestsBase.cs @@ -15,7 +15,6 @@ using Microsoft.CodeAnalysis.CSharp.CodeRefactorings.SyncNamespace; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Test.Utilities; -using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.UnitTests; using Roslyn.Test.Utilities; using Roslyn.Utilities; diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/CrefCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/CrefCompletionProviderTests.cs index 73ee6614a0c5b..d815e3673d99e 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/CrefCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/CrefCompletionProviderTests.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion; @@ -15,7 +14,6 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data; using Roslyn.Test.Utilities; -using Roslyn.Utilities; using Xunit; using RoslynTrigger = Microsoft.CodeAnalysis.Completion.CompletionTrigger; diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProviderTests.cs index da1717ad8e0d8..f8a06a905dd66 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProviderTests.cs @@ -169,7 +169,7 @@ class Bar : IGoo { void IGoo.Goo() { - throw new System.NotImplementedException();$$ + [|throw new System.NotImplementedException();|] } } """; @@ -549,7 +549,7 @@ class Bar : IGoo { int IGoo.Generic(K key, V value) { - throw new System.NotImplementedException();$$ + [|throw new System.NotImplementedException();|] } } """; @@ -1214,7 +1214,7 @@ class C : IFoo { static bool IFoo.TryDecode(out DecodeError? decodeError, out string? errorMessage) { - throw new System.NotImplementedException();$$ + [|throw new System.NotImplementedException();|] } } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExtensionMethodImportCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExtensionMethodImportCompletionProviderTests.cs index d04b2b1cb67c4..8f607e10d4a66 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExtensionMethodImportCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExtensionMethodImportCompletionProviderTests.cs @@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data; using Roslyn.Test.Utilities; -using Roslyn.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders; diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs index f5cad13cf7700..4c5e053f27347 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs @@ -41,91 +41,99 @@ internal override OptionsCollection NonCompletionOptions [WpfFact] public async Task InheritedVirtualPublicMethod() { - await VerifyItemExistsAsync(@" -public class a -{ - public virtual void goo() { } -} + await VerifyItemExistsAsync(""" + public class a + { + public virtual void goo() { } + } -public class b : a -{ - override $$ -}", "goo()"); + public class b : a + { + override $$ + } + """, "goo()"); } [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543799")] public async Task InheritedParameterDefaultValue1() { - await VerifyItemExistsAsync(@"public class a -{ - public virtual void goo(int x = 42) { } -} + await VerifyItemExistsAsync(""" + public class a + { + public virtual void goo(int x = 42) { } + } -public class b : a -{ - override $$ -}", "goo(int x = 42)", "void a.goo([int x = 42])"); + public class b : a + { + override $$ + } + """, "goo(int x = 42)", "void a.goo([int x = 42])"); } [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543799")] public async Task InheritedParameterDefaultValue2() { - await VerifyItemExistsAsync(@"public class a -{ - public virtual void goo(int x, int y = 42) { } -} + await VerifyItemExistsAsync(""" + public class a + { + public virtual void goo(int x, int y = 42) { } + } -public class b : a -{ - override $$ -}", "goo(int x, int y = 42)", "void a.goo(int x, [int y = 42])"); + public class b : a + { + override $$ + } + """, "goo(int x, int y = 42)", "void a.goo(int x, [int y = 42])"); } [WpfFact] public async Task InheritedAbstractPublicMethod() { - await VerifyItemExistsAsync(@" -public class a -{ - public abstract void goo(); -} + await VerifyItemExistsAsync(""" + public class a + { + public abstract void goo(); + } -public class b : a -{ - override $$ -}", "goo()"); + public class b : a + { + override $$ + } + """, "goo()"); } [WpfFact] public async Task NotPrivateInheritedMethod() { - await VerifyItemIsAbsentAsync(@" -public class a -{ - private virtual void goo() { } -} + await VerifyItemIsAbsentAsync(""" + public class a + { + private virtual void goo() { } + } -public class b : a -{ - override $$ -}", "goo()"); + public class b : a + { + override $$ + } + """, "goo()"); } [WpfFact] public async Task MatchReturnType() { - var markup = @" -public class a -{ - public virtual void goo() { } + var markup = """ + public class a + { + public virtual void goo() { } - public virtual string bar() {return null;} -} + public virtual string bar() {return null;} + } -public class b : a -{ - override void $$ -}"; + public class b : a + { + override void $$ + } + """; await VerifyItemIsAbsentAsync(markup, "bar()"); await VerifyItemExistsAsync(markup, "goo()"); } @@ -133,18 +141,19 @@ override void $$ [WpfFact] public async Task InvalidReturnType() { - var markup = @" -public class a -{ - public virtual void goo() { } + var markup = """ + public class a + { + public virtual void goo() { } - public virtual string bar() {return null;} -} + public virtual string bar() {return null;} + } -public class b : a -{ - override badtype $$ -}"; + public class b : a + { + override badtype $$ + } + """; await VerifyItemExistsAsync(markup, "goo()"); await VerifyItemExistsAsync(markup, "bar()"); @@ -153,247 +162,263 @@ override badtype $$ [WpfFact] public async Task NotAlreadyImplementedMethods() { - await VerifyItemIsAbsentAsync(@" -public class a -{ - protected virtual void goo() { } + await VerifyItemIsAbsentAsync(""" + public class a + { + protected virtual void goo() { } - protected virtual string bar() {return null;} -} + protected virtual string bar() {return null;} + } -public class b : a -{ - protected override void goo() { } + public class b : a + { + protected override void goo() { } - override $$ -}", "goo()"); + override $$ + } + """, "goo()"); } [WpfFact] public async Task NotSealed() { - await VerifyItemIsAbsentAsync(@" -public class a -{ - protected sealed void goo() { } -} + await VerifyItemIsAbsentAsync(""" + public class a + { + protected sealed void goo() { } + } -public class b : a -{ - public override $$ -}", "goo()"); + public class b : a + { + public override $$ + } + """, "goo()"); } [WpfFact] public async Task ShowEvent() { - await VerifyItemExistsAsync(@" -using System; -public class a -{ - public virtual event EventHandler goo; -} + await VerifyItemExistsAsync(""" + using System; + public class a + { + public virtual event EventHandler goo; + } -public class b : a -{ - public override $$ -}", "goo"); + public class b : a + { + public override $$ + } + """, "goo"); } [WpfFact] public async Task NotIfTokensAfterPosition() { - await VerifyNoItemsExistAsync(@" -public class a -{ - public virtual void goo() { } -} + await VerifyNoItemsExistAsync(""" + public class a + { + public virtual void goo() { } + } -public class b : a -{ - public override $$ void -}"); + public class b : a + { + public override $$ void + } + """); } [WpfFact] public async Task NotIfNameAfterPosition() { - await VerifyNoItemsExistAsync(@" -public class a -{ - public virtual void goo() { } -} + await VerifyNoItemsExistAsync(""" + public class a + { + public virtual void goo() { } + } -public class b : a -{ - public override void $$ bar -}"); + public class b : a + { + public override void $$ bar + } + """); } [WpfFact] public async Task NotIfStatic() { - await VerifyNoItemsExistAsync(@" -public class a -{ - public virtual void goo() { } -} + await VerifyNoItemsExistAsync(""" + public class a + { + public virtual void goo() { } + } -public class b : a -{ - public static override $$ -}"); + public class b : a + { + public static override $$ + } + """); } [WpfFact] public async Task AfterSingleLineMethodDeclaration() { - await VerifyNoItemsExistAsync(@" -public class a -{ - public virtual void goo() { } -} + await VerifyNoItemsExistAsync(""" + public class a + { + public virtual void goo() { } + } -public class b : a -{ - void bar() { } override $$ -}"); + public class b : a + { + void bar() { } override $$ + } + """); } [WpfFact] public async Task SuggestProperty() { - await VerifyItemExistsAsync(@" -public class a -{ - public virtual int goo { } -} + await VerifyItemExistsAsync(""" + public class a + { + public virtual int goo { } + } -public class b : a -{ - override $$ -}", "goo"); + public class b : a + { + override $$ + } + """, "goo"); } [WpfFact] public async Task NotSuggestSealed() { - await VerifyItemIsAbsentAsync(@" -public class a -{ - public sealed int goo { } -} + await VerifyItemIsAbsentAsync(""" + public class a + { + public sealed int goo { } + } -public class b : a -{ - override $$ -}", "goo"); + public class b : a + { + override $$ + } + """, "goo"); } [WpfFact] public async Task GatherModifiers() { - await VerifyItemExistsAsync(@" -public class a -{ - public abstract extern unsafe int goo { } -} + await VerifyItemExistsAsync(""" + public class a + { + public abstract extern unsafe int goo { } + } -public class b : a -{ - override $$ -}", "goo"); + public class b : a + { + override $$ + } + """, "goo"); } [WpfFact] public async Task IgnorePartial() { - await VerifyNoItemsExistAsync(@" -public class a -{ - public virtual partial goo() { } -} + await VerifyNoItemsExistAsync(""" + public class a + { + public virtual partial goo() { } + } -public class b : a -{ - override partial $$ -}"); + public class b : a + { + override partial $$ + } + """); } [WpfFact] public async Task IgnoreSealed() { - await VerifyItemIsAbsentAsync(@" -public class a -{ - public virtual sealed int goo() { } -} + await VerifyItemIsAbsentAsync(""" + public class a + { + public virtual sealed int goo() { } + } -public class b : a -{ - override $$ -}", "goo()"); + public class b : a + { + override $$ + } + """, "goo()"); } [WpfFact] public async Task IgnoreIfTokenAfter() { - await VerifyNoItemsExistAsync(@" -public class a -{ - public virtual int goo() { } -} + await VerifyNoItemsExistAsync(""" + public class a + { + public virtual int goo() { } + } -public class b : a -{ - override $$ int -}"); + public class b : a + { + override $$ int + } + """); } [WpfFact] public async Task SuggestAfterUnsafeAbstractExtern() { - await VerifyItemExistsAsync(@" -public class a -{ - public virtual int goo() { } -} + await VerifyItemExistsAsync(""" + public class a + { + public virtual int goo() { } + } -public class b : a -{ - unsafe abstract extern override $$ -}", "goo()"); + public class b : a + { + unsafe abstract extern override $$ + } + """, "goo()"); } [WpfFact] public async Task SuggestAfterSealed() { - await VerifyItemExistsAsync(@" -public class a -{ - public virtual int goo() { } -} + await VerifyItemExistsAsync(""" + public class a + { + public virtual int goo() { } + } -public class b : a -{ - sealed override $$ -}", "goo()"); + public class b : a + { + sealed override $$ + } + """, "goo()"); } [WpfFact] public async Task NoAccessibility() { - var markup = @" -public class a -{ - public virtual int goo() { } - protected virtual int bar() { } -} + var markup = """ + public class a + { + public virtual int goo() { } + protected virtual int bar() { } + } -public class b : a -{ - override $$ -}"; + public class b : a + { + override $$ + } + """; await VerifyItemExistsAsync(markup, "goo()"); await VerifyItemExistsAsync(markup, "bar()"); @@ -402,19 +427,20 @@ public class b : a [WpfFact] public async Task FilterAccessibility() { - var markup = @" -public class a -{ - public virtual int goo() { } - protected virtual int bar() { } - internal virtual int far() { } - private virtual int bor() { } -} + var markup = """ + public class a + { + public virtual int goo() { } + protected virtual int bar() { } + internal virtual int far() { } + private virtual int bor() { } + } -public class b : a -{ - override internal $$ -}"; + public class b : a + { + override internal $$ + } + """; await VerifyItemIsAbsentAsync(markup, "goo()"); await VerifyItemIsAbsentAsync(markup, "bar()"); @@ -422,50 +448,53 @@ override internal $$ await VerifyItemExistsAsync(markup, "far()"); - await VerifyItemExistsAsync(@" -public class a -{ - public virtual int goo() { } - protected virtual int bar() { } - internal virtual int far() { } - private virtual int bor() { } -} + await VerifyItemExistsAsync(""" + public class a + { + public virtual int goo() { } + protected virtual int bar() { } + internal virtual int far() { } + private virtual int bor() { } + } -public class b : a -{ - override protected $$ -}", "bar()"); + public class b : a + { + override protected $$ + } + """, "bar()"); } [WpfFact] public async Task FilterPublicInternal() { - var protectedinternal = @" -public class a -{ - protected internal virtual void goo() { } - public virtual void bar() { } -} + var protectedinternal = """ + public class a + { + protected internal virtual void goo() { } + public virtual void bar() { } + } -public class b : a -{ - protected internal override $$ -}"; + public class b : a + { + protected internal override $$ + } + """; await VerifyItemIsAbsentAsync(protectedinternal, "bar()"); await VerifyItemExistsAsync(protectedinternal, "goo()"); - var internalprotected = @" -public class a -{ - protected internal virtual void goo() { } - public virtual void bar() { } -} + var internalprotected = """ + public class a + { + protected internal virtual void goo() { } + public virtual void bar() { } + } -public class b : a -{ - internal protected override $$ -}"; + public class b : a + { + internal protected override $$ + } + """; await VerifyItemIsAbsentAsync(internalprotected, "bar()"); await VerifyItemExistsAsync(internalprotected, "goo()"); @@ -474,55 +503,59 @@ internal protected override $$ [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/64821")] public async Task FilterAccessibility1() { - var test1 = @" -public class a -{ - private protected virtual void goo() { } -} + var test1 = """ + public class a + { + private protected virtual void goo() { } + } -public class b : a -{ - private override $$ -}"; + public class b : a + { + private override $$ + } + """; await VerifyItemExistsAsync(test1, "goo()"); - test1 = @" -public class a -{ - private protected virtual void goo() { } -} + test1 = """ + public class a + { + private protected virtual void goo() { } + } -public class b : a -{ - protected override $$ -}"; + public class b : a + { + protected override $$ + } + """; await VerifyItemExistsAsync(test1, "goo()"); - test1 = @" -public class a -{ - private protected virtual void goo() { } -} + test1 = """ + public class a + { + private protected virtual void goo() { } + } -public class b : a -{ - private protected override $$ -}"; + public class b : a + { + private protected override $$ + } + """; await VerifyItemExistsAsync(test1, "goo()"); - test1 = @" -public class a -{ - private protected virtual void goo() { } -} - -public class b : a -{ - protected private override $$ -}"; + test1 = """ + public class a + { + private protected virtual void goo() { } + } + + public class b : a + { + protected private override $$ + } + """; await VerifyItemExistsAsync(test1, "goo()"); } @@ -530,55 +563,59 @@ protected private override $$ [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/64821")] public async Task FilterAccessibility2() { - var test1 = @" -public class a -{ - protected internal virtual void goo() { } -} + var test1 = """ + public class a + { + protected internal virtual void goo() { } + } -public class b : a -{ - protected override $$ -}"; + public class b : a + { + protected override $$ + } + """; await VerifyItemExistsAsync(test1, "goo()"); - test1 = @" -public class a -{ - protected internal virtual void goo() { } -} + test1 = """ + public class a + { + protected internal virtual void goo() { } + } -public class b : a -{ - internal override $$ -}"; + public class b : a + { + internal override $$ + } + """; await VerifyItemExistsAsync(test1, "goo()"); - test1 = @" -public class a -{ - protected internal virtual void goo() { } -} + test1 = """ + public class a + { + protected internal virtual void goo() { } + } -public class b : a -{ - protected internal override $$ -}"; + public class b : a + { + protected internal override $$ + } + """; await VerifyItemExistsAsync(test1, "goo()"); - test1 = @" -public class a -{ - protected internal virtual void goo() { } -} + test1 = """ + public class a + { + protected internal virtual void goo() { } + } -public class b : a -{ - internal protected override $$ -}"; + public class b : a + { + internal protected override $$ + } + """; await VerifyItemExistsAsync(test1, "goo()"); } @@ -586,11 +623,12 @@ internal protected override $$ [WpfFact] public async Task VerifySignatureFormat() { - var markup = @" -public class a -{ - override $$ -}"; + var markup = """ + public class a + { + override $$ + } + """; await VerifyItemExistsAsync(markup, "Equals(object obj)"); } @@ -598,16 +636,17 @@ public class a [WpfFact] public async Task PrivateNoFilter() { - var markup = @" -public class c -{ - public virtual void goo() { } -} + var markup = """ + public class c + { + public virtual void goo() { } + } -public class a : c -{ - private override $$ -}"; + public class a : c + { + private override $$ + } + """; await VerifyNoItemsExistAsync(markup); } @@ -631,20 +670,22 @@ public async Task NotOfferedOverrideAlone() [WpfFact] public async Task IntermediateClassOverriddenMember() { - var markup = @"abstract class Base -{ - public abstract void Goo(); -} + var markup = """ + abstract class Base + { + public abstract void Goo(); + } -class Derived : Base -{ - public override void Goo() { } -} + class Derived : Base + { + public override void Goo() { } + } -class SomeClass : Derived -{ - override $$ -}"; + class SomeClass : Derived + { + override $$ + } + """; await VerifyItemExistsAsync(markup, "Goo()", "void Derived.Goo()"); } @@ -652,20 +693,22 @@ class SomeClass : Derived [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543748")] public async Task NotOfferedBaseClassMember() { - var markup = @"abstract class Base -{ - public abstract void Goo(); -} + var markup = """ + abstract class Base + { + public abstract void Goo(); + } -class Derived : Base -{ - public override void Goo() { } -} + class Derived : Base + { + public override void Goo() { } + } -class SomeClass : Derived -{ - override $$ -}"; + class SomeClass : Derived + { + override $$ + } + """; await VerifyItemIsAbsentAsync(markup, "Goo()", "void Base.Goo()"); } @@ -673,15 +716,17 @@ class SomeClass : Derived [WpfFact] public async Task NotOfferedOnNonVirtual() { - var markup = @"class Base -{ - public void Goo(); -} + var markup = """ + class Base + { + public void Goo(); + } -class SomeClass : Base -{ - override $$ -}"; + class SomeClass : Base + { + override $$ + } + """; await VerifyItemIsAbsentAsync(markup, "Goo()", "void Base.Goo()"); } @@ -689,15 +734,17 @@ class SomeClass : Base [WpfFact] public async Task GenericTypeNameSubstitutedForGenericInDerivedClass1() { - var markup = @"public abstract class Base -{ - public abstract void Goo(T t); -} + var markup = """ + public abstract class Base + { + public abstract void Goo(T t); + } -public class SomeClass : Base -{ - override $$ -}"; + public class SomeClass : Base + { + override $$ + } + """; await VerifyItemExistsAsync(markup, "Goo(X t)"); await VerifyItemIsAbsentAsync(markup, "Goo(T t)"); } @@ -705,15 +752,17 @@ public class SomeClass : Base [WpfFact] public async Task GenericTypeNameSubstitutedForGenericInDerivedClass2() { - var markup = @"public abstract class Base -{ - public abstract void Goo(T t); -} + var markup = """ + public abstract class Base + { + public abstract void Goo(T t); + } -public class SomeClass : Base -{ - override $$ -}"; + public class SomeClass : Base + { + override $$ + } + """; await VerifyItemExistsAsync(markup, "Goo(Y t)"); await VerifyItemIsAbsentAsync(markup, "Goo(T t)"); } @@ -721,15 +770,17 @@ public class SomeClass : Base [WpfFact] public async Task GenericTypeNameSubstitutedForGenericInDerivedClass3() { - var markup = @"public abstract class Base -{ - public abstract void Goo(T t, S s); -} + var markup = """ + public abstract class Base + { + public abstract void Goo(T t, S s); + } -public class SomeClass : Base -{ - override $$ -}"; + public class SomeClass : Base + { + override $$ + } + """; await VerifyItemExistsAsync(markup, "Goo(Y t, Z s)"); await VerifyItemIsAbsentAsync(markup, "Goo(T t, S s)"); } @@ -737,15 +788,17 @@ public class SomeClass : Base [WpfFact] public async Task GenericTypeNameSubstitutedForNonGenericInDerivedClass1() { - var markup = @"public abstract class Base -{ - public abstract void Goo(T t); -} + var markup = """ + public abstract class Base + { + public abstract void Goo(T t); + } -public class SomeClass : Base -{ - override $$ -}"; + public class SomeClass : Base + { + override $$ + } + """; await VerifyItemExistsAsync(markup, "Goo(int t)"); await VerifyItemIsAbsentAsync(markup, "Goo(T t)"); } @@ -753,15 +806,17 @@ public class SomeClass : Base [WpfFact] public async Task GenericTypeNameSubstitutedForNonGenericInDerivedClass2() { - var markup = @"public abstract class Base -{ - public abstract void Goo(T t); -} + var markup = """ + public abstract class Base + { + public abstract void Goo(T t); + } -public class SomeClass : Base -{ - override $$ -}"; + public class SomeClass : Base + { + override $$ + } + """; await VerifyItemExistsAsync(markup, "Goo(int t)"); await VerifyItemIsAbsentAsync(markup, "Goo(T t)"); } @@ -769,17 +824,19 @@ public class SomeClass : Base [WpfFact] public async Task GenericTypeNameSubstitutedForNonGenericInDerivedClass3() { - var markup = @"using System; + var markup = """ + using System; -public abstract class Base -{ - public abstract void Goo(T t, S s); -} + public abstract class Base + { + public abstract void Goo(T t, S s); + } -public class SomeClass : Base -{ - override $$ -}"; + public class SomeClass : Base + { + override $$ + } + """; await VerifyItemExistsAsync(markup, "Goo(int t, Exception s)"); await VerifyItemIsAbsentAsync(markup, "Goo(T t, S s)"); } @@ -787,17 +844,19 @@ public class SomeClass : Base [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543756")] public async Task ParameterTypeSimplified() { - var markup = @"using System; + var markup = """ + using System; -public abstract class Base -{ - public abstract void Goo(System.Exception e); -} + public abstract class Base + { + public abstract void Goo(System.Exception e); + } -public class SomeClass : Base -{ - override $$ -}"; + public class SomeClass : Base + { + override $$ + } + """; await VerifyItemExistsAsync(markup, "Goo(Exception e)"); } @@ -805,32 +864,36 @@ public class SomeClass : Base [WpfFact] public async Task NullableAnnotationsIncluded() { - var markup = @"#nullable enable + var markup = """ + #nullable enable -public abstract class Base -{ - public abstract void Goo(string? s); -} + public abstract class Base + { + public abstract void Goo(string? s); + } -public class SomeClass : Base -{ - override $$ -}"; + public class SomeClass : Base + { + override $$ + } + """; await VerifyItemExistsAsync(markup, "Goo(string? s)"); } [WpfFact] public async Task EscapedMethodNameInIntelliSenseList() { - var markup = @"public abstract class Base -{ - public abstract void @class(); -} + var markup = """ + public abstract class Base + { + public abstract void @class(); + } -public class SomeClass : Base -{ - override $$ -}"; + public class SomeClass : Base + { + override $$ + } + """; MarkupTestFile.GetPosition(markup, out var code, out int position); await BaseVerifyWorkerAsync(code, position, "@class()", "void Base.@class()", SourceCodeKind.Regular, false, deletedCharTrigger: null, false, null, null, null, null, null, null); @@ -840,15 +903,17 @@ public class SomeClass : Base [WpfFact] public async Task EscapedPropertyNameInIntelliSenseList() { - var markup = @"public abstract class Base -{ - public virtual int @class { get; set; } -} + var markup = """ + public abstract class Base + { + public virtual int @class { get; set; } + } -public class SomeClass : Base -{ - override $$ -}"; + public class SomeClass : Base + { + override $$ + } + """; MarkupTestFile.GetPosition(markup, out var code, out int position); await BaseVerifyWorkerAsync(code, position, "@class", "int Base.@class { get; set; }", SourceCodeKind.Regular, false, deletedCharTrigger: null, false, null, null, null, null, null, null); @@ -858,15 +923,17 @@ public class SomeClass : Base [WpfFact] public async Task EscapedParameterNameInIntelliSenseList() { - var markup = @"public abstract class Base -{ - public abstract void goo(int @class); -} + var markup = """ + public abstract class Base + { + public abstract void goo(int @class); + } -public class SomeClass : Base -{ - override $$ -}"; + public class SomeClass : Base + { + override $$ + } + """; await VerifyItemExistsAsync(markup, "goo(int @class)", "void Base.goo(int @class)"); } @@ -874,15 +941,17 @@ public class SomeClass : Base [WpfFact] public async Task RefParameter() { - var markup = @"public abstract class Base -{ - public abstract void goo(int x, ref string y); -} + var markup = """ + public abstract class Base + { + public abstract void goo(int x, ref string y); + } -public class SomeClass : Base -{ - override $$ -}"; + public class SomeClass : Base + { + override $$ + } + """; await VerifyItemExistsAsync(markup, "goo(int x, ref string y)", "void Base.goo(int x, ref string y)"); } @@ -890,15 +959,17 @@ public class SomeClass : Base [WpfFact] public async Task OutParameter() { - var markup = @"public abstract class Base -{ - public abstract void goo(int x, out string y); -} + var markup = """ + public abstract class Base + { + public abstract void goo(int x, out string y); + } -public class SomeClass : Base -{ - override $$ -}"; + public class SomeClass : Base + { + override $$ + } + """; await VerifyItemExistsAsync(markup, "goo(int x, out string y)", "void Base.goo(int x, out string y)"); } @@ -906,757 +977,1142 @@ public class SomeClass : Base [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/529714")] public async Task GenericMethodTypeParametersNotRenamed() { - var markup = @"abstract class CGoo -{ - public virtual X Something(X arg) - { - return default(X); - } -} -class Derived : CGoo -{ - override $$ -}"; + var markup = """ + abstract class CGoo + { + public virtual X Something(X arg) + { + return default(X); + } + } + class Derived : CGoo + { + override $$ + } + """; await VerifyItemExistsAsync(markup, "Something(X arg)"); } - #endregion - - #region "Commit tests" - [WpfFact] - public async Task CommitInEmptyClass() + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/77193")] + public async Task CommitBeforeAttribute1() { - var markupBeforeCommit = @"class c -{ - override $$ -}"; + var markupBeforeCommit = """ + namespace InteliSenseIssue + { + [AttributeUsage(AttributeTargets.All)] + public class ThatAttribute : Attribute {} + + internal class Program + { + override Eq$$ + + [That] + public int Disregard = 34; + } + } + """; - var expectedCodeAfterCommit = @"class c -{ - public override bool Equals(object obj) - { - return base.Equals(obj);$$ - } -}"; + var expectedCodeAfterCommit = """ + namespace InteliSenseIssue + { + [AttributeUsage(AttributeTargets.All)] + public class ThatAttribute : Attribute {} + + internal class Program + { + public override bool Equals(object obj) + { + return base.Equals(obj);$$ + } + + [That] + public int Disregard = 34; + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "Equals(object obj)", expectedCodeAfterCommit); } - [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/529714")] - public async Task CommitGenericMethodTypeParametersNotRenamed() - { - var markupBeforeCommit = @"abstract class CGoo -{ - public virtual X Something(X arg) - { - return default(X); - } -} -class Derived : CGoo -{ - override $$ -}"; - - var expectedCodeAfterCommit = @"abstract class CGoo -{ - public virtual X Something(X arg) - { - return default(X); - } -} -class Derived : CGoo -{ - public override X Something(X arg) - { - return base.Something(arg);$$ - } -}"; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, "Something(X arg)", expectedCodeAfterCommit); - } - - [WpfFact] - public async Task CommitMethodBeforeMethod() + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/77193")] + public async Task CommitBeforeAttribute2() { - var markupBeforeCommit = @"class c -{ - override $$ + var markupBeforeCommit = """ + namespace InteliSenseIssue + { + [AttributeUsage(AttributeTargets.All)] + public class ThatAttribute : Attribute {} + + internal class Program + { + override Eq$$ + + // This is a comment + [That] + public int Disregard = 34; + } + } + """; - public void goo() { } -}"; + var expectedCodeAfterCommit = """ + namespace InteliSenseIssue + { + [AttributeUsage(AttributeTargets.All)] + public class ThatAttribute : Attribute {} + + internal class Program + { + public override bool Equals(object obj) + { + return base.Equals(obj);$$ + } + + // This is a comment + [That] + public int Disregard = 34; + } + } + """; - var expectedCodeAfterCommit = @"class c -{ - public override bool Equals(object obj) - { - return base.Equals(obj);$$ + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "Equals(object obj)", expectedCodeAfterCommit); } - public void goo() { } -}"; + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/77193")] + public async Task CommitBeforeAttribute3() + { + var markupBeforeCommit = """ + namespace InteliSenseIssue + { + [AttributeUsage(AttributeTargets.All)] + public class ThatAttribute : Attribute {} + + internal class Program + { + override Eq$$ + + [That] public int Disregard = 34; + } + } + """; + + var expectedCodeAfterCommit = """ + namespace InteliSenseIssue + { + [AttributeUsage(AttributeTargets.All)] + public class ThatAttribute : Attribute {} + + internal class Program + { + public override bool Equals(object obj) + { + return base.Equals(obj);$$ + } + + [That] public int Disregard = 34; + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "Equals(object obj)", expectedCodeAfterCommit); } - [WpfFact] - public async Task CommitMethodAfterMethod() + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/77193")] + public async Task CommitBeforeAttribute4() { - var markupBeforeCommit = @"class c -{ - public void goo() { } + var markupBeforeCommit = """ + namespace InteliSenseIssue + { + [AttributeUsage(AttributeTargets.All)] + public class ThatAttribute : Attribute {} + + internal class Program + { + override Eq$$ + + [That] + // Comment after attribute + public int Disregard = 34; + } + } + """; - override $$ -}"; + var expectedCodeAfterCommit = """ + namespace InteliSenseIssue + { + [AttributeUsage(AttributeTargets.All)] + public class ThatAttribute : Attribute {} + + internal class Program + { + public override bool Equals(object obj) + { + return base.Equals(obj);$$ + } + + [That] + // Comment after attribute + public int Disregard = 34; + } + } + """; - var expectedCodeAfterCommit = @"class c -{ - public void goo() { } + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "Equals(object obj)", expectedCodeAfterCommit); + } - public override bool Equals(object obj) + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/77193")] + public async Task CommitBeforeAttribute5() { - return base.Equals(obj);$$ - } -}"; + var markupBeforeCommit = """ + namespace InteliSenseIssue + { + [AttributeUsage(AttributeTargets.All)] + public class ThatAttribute : Attribute {} + + internal class Program + { + override Eq$$ + + [That, System.Obsolete("")] + public int Disregard = 34; + } + } + """; + + var expectedCodeAfterCommit = """ + namespace InteliSenseIssue + { + [AttributeUsage(AttributeTargets.All)] + public class ThatAttribute : Attribute {} + + internal class Program + { + public override bool Equals(object obj) + { + return base.Equals(obj);$$ + } + + [That, System.Obsolete("")] + public int Disregard = 34; + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "Equals(object obj)", expectedCodeAfterCommit); } - [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543798")] - public async Task CommitOptionalParameterValuesAreGenerated() + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/77193")] + public async Task CommitBeforeAttribute6() { - var markupBeforeCommit = @"using System; + var markupBeforeCommit = """ + namespace InteliSenseIssue + { + [AttributeUsage(AttributeTargets.All)] + public class ThatAttribute : Attribute {} + + internal class Program + { + // Comment before the override. + override Eq$$ + // Comment after the override. -abstract public class Base -{ - public abstract void goo(int x = 42); -} + [That] + public int Disregard = 34; + } + } + """; -public class Derived : Base -{ - override $$ -}"; + var expectedCodeAfterCommit = """ + namespace InteliSenseIssue + { + [AttributeUsage(AttributeTargets.All)] + public class ThatAttribute : Attribute {} + + internal class Program + { + // Comment before the override. + public override bool Equals(object obj) + { + return base.Equals(obj);$$ + } + // Comment after the override. - var expectedCodeAfterCommit = @"using System; + [That] + public int Disregard = 34; + } + } + """; -abstract public class Base -{ - public abstract void goo(int x = 42); -} + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "Equals(object obj)", expectedCodeAfterCommit); + } -public class Derived : Base -{ - public override void goo(int x = 42) + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/77193")] + public async Task CommitBeforeAttribute7() { - throw new NotImplementedException();$$ - } -}"; + var markupBeforeCommit = """ + namespace InteliSenseIssue + { + [AttributeUsage(AttributeTargets.All)] + public class ThatAttribute : Attribute {} + + internal class Program + { + override Eq$$ + + [That] /* inline comment */ public int Disregard = 34; + } + } + """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo(int x = 42)", expectedCodeAfterCommit); + var expectedCodeAfterCommit = """ + namespace InteliSenseIssue + { + [AttributeUsage(AttributeTargets.All)] + public class ThatAttribute : Attribute {} + + internal class Program + { + public override bool Equals(object obj) + { + return base.Equals(obj);$$ + } + + [That] /* inline comment */ public int Disregard = 34; + } + } + """; + + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "Equals(object obj)", expectedCodeAfterCommit); } + #endregion - [WpfFact] - public async Task CommitAttributesAreNotGenerated() - { - var markupBeforeCommit = @"using System; + #region "Commit tests" -public class Base -{ - [Obsolete] - public virtual void goo() + [WpfFact] + public async Task CommitInEmptyClass() { - } -} - -public class Derived : Base -{ - override $$ -}"; + var markupBeforeCommit = """ + class c + { + override $$ + } + """; - var expectedCodeAfterCommit = @"using System; + var expectedCodeAfterCommit = """ + class c + { + public override bool Equals(object obj) + { + return base.Equals(obj);$$ + } + } + """; -public class Base -{ - [Obsolete] - public virtual void goo() - { + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "Equals(object obj)", expectedCodeAfterCommit); } -} -public class Derived : Base -{ - public override void goo() + [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/529714")] + public async Task CommitGenericMethodTypeParametersNotRenamed() { - base.goo();$$ - } -}"; + var markupBeforeCommit = """ + abstract class CGoo + { + public virtual X Something(X arg) + { + return default(X); + } + } + class Derived : CGoo + { + override $$ + } + """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo()", expectedCodeAfterCommit); + var expectedCodeAfterCommit = """ + abstract class CGoo + { + public virtual X Something(X arg) + { + return default(X); + } + } + class Derived : CGoo + { + public override X Something(X arg) + { + return base.Something(arg);$$ + } + } + """; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "Something(X arg)", expectedCodeAfterCommit); } [WpfFact] - public async Task CommitInaccessibleParameterAttributesAreNotGenerated() + public async Task CommitMethodBeforeMethod() { - var markupBeforeCommit = @"using System; - -public class Class1 -{ - private class MyPrivate : Attribute { } - public class MyPublic : Attribute { } - public virtual void M([MyPrivate, MyPublic] int i) { } -} - -public class Class2 : Class1 -{ - public override void $$ -}"; + var markupBeforeCommit = """ + class c + { + override $$ - var expectedCodeAfterCommit = @"using System; + public void goo() { } + } + """; -public class Class1 -{ - private class MyPrivate : Attribute { } - public class MyPublic : Attribute { } - public virtual void M([MyPrivate, MyPublic] int i) { } -} + var expectedCodeAfterCommit = """ + class c + { + public override bool Equals(object obj) + { + return base.Equals(obj);$$ + } -public class Class2 : Class1 -{ - public override void M([MyPublic] int i) - { - base.M(i);$$ - } -}"; + public void goo() { } + } + """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, "M(int i)", expectedCodeAfterCommit); + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "Equals(object obj)", expectedCodeAfterCommit); } [WpfFact] - public async Task CommitVoidMethod() + public async Task CommitMethodAfterMethod() { - var markupBeforeCommit = @"class c -{ - public virtual void goo() { } -} + var markupBeforeCommit = """ + class c + { + public void goo() { } -class d : c -{ - override $$ -}"; + override $$ + } + """; - var expectedCodeAfterCommit = @"class c -{ - public virtual void goo() { } -} + var expectedCodeAfterCommit = """ + class c + { + public void goo() { } -class d : c -{ - public override void goo() - { - base.goo();$$ - } -}"; + public override bool Equals(object obj) + { + return base.Equals(obj);$$ + } + } + """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo()", expectedCodeAfterCommit); + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "Equals(object obj)", expectedCodeAfterCommit); } - [WpfFact] - public async Task CommitVoidMethodWithParams() + [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543798")] + public async Task CommitOptionalParameterValuesAreGenerated() { - var markupBeforeCommit = @"class c -{ - public virtual void goo(int bar, int quux) { } -} + var markupBeforeCommit = """ + using System; -class d : c -{ - override $$ -}"; + abstract public class Base + { + public abstract void goo(int x = 42); + } - var expectedCodeAfterCommit = @"class c -{ - public virtual void goo(int bar, int quux) { } -} + public class Derived : Base + { + override $$ + } + """; -class d : c -{ - public override void goo(int bar, int quux) - { - base.goo(bar, quux);$$ - } -}"; + var expectedCodeAfterCommit = """ + using System; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo(int bar, int quux)", expectedCodeAfterCommit); + abstract public class Base + { + public abstract void goo(int x = 42); + } + + public class Derived : Base + { + public override void goo(int x = 42) + { + throw new NotImplementedException();$$ + } + } + """; + + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo(int x = 42)", expectedCodeAfterCommit); } [WpfFact] - public async Task CommitNonVoidMethod() + public async Task CommitAttributesAreNotGenerated() { - var markupBeforeCommit = @"class c -{ - public virtual int goo() { } -} + var markupBeforeCommit = """ + using System; -class d : c -{ - override $$ -}"; + public class Base + { + [Obsolete] + public virtual void goo() + { + } + } - var expectedCodeAfterCommit = @"class c -{ - public virtual int goo() { } -} + public class Derived : Base + { + override $$ + } + """; -class d : c -{ - public override int goo() - { - return base.goo();$$ - } -}"; + var expectedCodeAfterCommit = """ + using System; + + public class Base + { + [Obsolete] + public virtual void goo() + { + } + } + + public class Derived : Base + { + public override void goo() + { + base.goo();$$ + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo()", expectedCodeAfterCommit); } [WpfFact] - public async Task CommitNonVoidMethodWithParams() + public async Task CommitInaccessibleParameterAttributesAreNotGenerated() { - var markupBeforeCommit = @"class c -{ - public virtual int goo(int bar, int quux) { } -} + var markupBeforeCommit = """ + using System; -class d : c -{ - override $$ -}"; + public class Class1 + { + private class MyPrivate : Attribute { } + public class MyPublic : Attribute { } + public virtual void M([MyPrivate, MyPublic] int i) { } + } - var expectedCodeAfterCommit = @"class c -{ - public virtual int goo(int bar, int quux) { } -} + public class Class2 : Class1 + { + public override void $$ + } + """; -class d : c -{ - public override int goo(int bar, int quux) - { - return base.goo(bar, quux);$$ - } -}"; + var expectedCodeAfterCommit = """ + using System; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo(int bar, int quux)", expectedCodeAfterCommit); + public class Class1 + { + private class MyPrivate : Attribute { } + public class MyPublic : Attribute { } + public virtual void M([MyPrivate, MyPublic] int i) { } + } + + public class Class2 : Class1 + { + public override void M([MyPublic] int i) + { + base.M(i);$$ + } + } + """; + + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "M(int i)", expectedCodeAfterCommit); } [WpfFact] - public async Task CommitProtectedMethod() + public async Task CommitVoidMethod() { - var markupBeforeCommit = @"class c -{ - protected virtual void goo() { } -} + var markupBeforeCommit = """ + class c + { + public virtual void goo() { } + } -class d : c -{ - override $$ -}"; - var expectedCodeAfterCommit = @"class c -{ - protected virtual void goo() { } -} + class d : c + { + override $$ + } + """; -class d : c -{ - protected override void goo() - { - base.goo();$$ - } -}"; + var expectedCodeAfterCommit = """ + class c + { + public virtual void goo() { } + } + + class d : c + { + public override void goo() + { + base.goo();$$ + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo()", expectedCodeAfterCommit); } [WpfFact] - public async Task CommitInternalMethod() + public async Task CommitVoidMethodWithParams() { - var markupBeforeCommit = @"class c -{ - internal virtual void goo() { } -} + var markupBeforeCommit = """ + class c + { + public virtual void goo(int bar, int quux) { } + } -class d : c -{ - override $$ -}"; + class d : c + { + override $$ + } + """; - var expectedCodeAfterCommit = @"class c -{ - internal virtual void goo() { } -} + var expectedCodeAfterCommit = """ + class c + { + public virtual void goo(int bar, int quux) { } + } -class d : c -{ - internal override void goo() - { - base.goo();$$ - } -}"; + class d : c + { + public override void goo(int bar, int quux) + { + base.goo(bar, quux);$$ + } + } + """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo()", expectedCodeAfterCommit); + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo(int bar, int quux)", expectedCodeAfterCommit); } [WpfFact] - public async Task CommitProtectedInternalMethod() + public async Task CommitNonVoidMethod() { - var markupBeforeCommit = @"public class c -{ - protected internal virtual void goo() { } -} + var markupBeforeCommit = """ + class c + { + public virtual int goo() { } + } -class d : c -{ - override $$ -}"; + class d : c + { + override $$ + } + """; - var expectedCodeAfterCommit = @"public class c -{ - protected internal virtual void goo() { } -} + var expectedCodeAfterCommit = """ + class c + { + public virtual int goo() { } + } -class d : c -{ - protected internal override void goo() - { - base.goo();$$ - } -}"; + class d : c + { + public override int goo() + { + return base.goo();$$ + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo()", expectedCodeAfterCommit); } [WpfFact] - public async Task CommitAbstractMethodThrows() + public async Task CommitNonVoidMethodWithParams() { - var markupBeforeCommit = @"using System; + var markupBeforeCommit = """ + class c + { + public virtual int goo(int bar, int quux) { } + } -abstract class c -{ - public abstract void goo(); -} + class d : c + { + override $$ + } + """; -class d : c -{ - override $$ -}"; + var expectedCodeAfterCommit = """ + class c + { + public virtual int goo(int bar, int quux) { } + } - var expectedCodeAfterCommit = @"using System; + class d : c + { + public override int goo(int bar, int quux) + { + return base.goo(bar, quux);$$ + } + } + """; -abstract class c -{ - public abstract void goo(); -} + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo(int bar, int quux)", expectedCodeAfterCommit); + } -class d : c -{ - public override void goo() + [WpfFact] + public async Task CommitProtectedMethod() { - throw new NotImplementedException();$$ - } -}"; + var markupBeforeCommit = """ + class c + { + protected virtual void goo() { } + } + + class d : c + { + override $$ + } + """; + var expectedCodeAfterCommit = """ + class c + { + protected virtual void goo() { } + } + + class d : c + { + protected override void goo() + { + base.goo();$$ + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo()", expectedCodeAfterCommit); } [WpfFact] - public async Task CommitOverrideAsAbstract() + public async Task CommitInternalMethod() { - var markupBeforeCommit = @"class c -{ - public virtual void goo() { }; -} + var markupBeforeCommit = """ + class c + { + internal virtual void goo() { } + } -class d : c -{ - abstract override $$ -}"; + class d : c + { + override $$ + } + """; - var expectedCodeAfterCommit = @"class c -{ - public virtual void goo() { }; -} + var expectedCodeAfterCommit = """ + class c + { + internal virtual void goo() { } + } -class d : c -{ - public abstract override void goo();$$ -}"; + class d : c + { + internal override void goo() + { + base.goo();$$ + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo()", expectedCodeAfterCommit); } [WpfFact] - public async Task CommitOverrideAsUnsafeSealed() + public async Task CommitProtectedInternalMethod() { - var markupBeforeCommit = @"class c -{ - public virtual void goo() { }; -} + var markupBeforeCommit = """ + public class c + { + protected internal virtual void goo() { } + } -class d : c -{ - unsafe sealed override $$ -}"; + class d : c + { + override $$ + } + """; - var expectedCodeAfterCommit = @"class c -{ - public virtual void goo() { }; -} + var expectedCodeAfterCommit = """ + public class c + { + protected internal virtual void goo() { } + } -class d : c -{ - public sealed override unsafe void goo() - { - base.goo();$$ - } -}"; + class d : c + { + protected internal override void goo() + { + base.goo();$$ + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo()", expectedCodeAfterCommit); } [WpfFact] - public async Task CommitInsertProperty() + public async Task CommitAbstractMethodThrows() { - var markupBeforeCommit = @"public class c -{ - public virtual int goo { get; set; } -} + var markupBeforeCommit = """ + using System; -public class d : c -{ - override $$ -}"; + abstract class c + { + public abstract void goo(); + } - var expectedCodeAfterCommit = @"public class c -{ - public virtual int goo { get; set; } -} + class d : c + { + override $$ + } + """; -public class d : c -{ - public override int goo - { - get - { - return base.goo;$$ - } + var expectedCodeAfterCommit = """ + using System; - set - { - base.goo = value; - } - } -}"; + abstract class c + { + public abstract void goo(); + } - await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo", expectedCodeAfterCommit); + class d : c + { + public override void goo() + { + throw new NotImplementedException();$$ + } + } + """; + + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo()", expectedCodeAfterCommit); } [WpfFact] - public async Task CommitInsertPropertyAfterMethod() + public async Task CommitOverrideAsAbstract() { - var markupBeforeCommit = @"public class c -{ - public virtual int goo { get; set; } -} + var markupBeforeCommit = """ + class c + { + public virtual void goo() { }; + } -public class d : c -{ - public void a() { } - override $$ -}"; + class d : c + { + abstract override $$ + } + """; - var expectedCodeAfterCommit = @"public class c -{ - public virtual int goo { get; set; } -} + var expectedCodeAfterCommit = """ + class c + { + public virtual void goo() { }; + } -public class d : c -{ - public void a() { } - public override int goo - { - get - { - return base.goo;$$ - } + class d : c + { + public abstract override void goo();$$ + } + """; - set - { - base.goo = value; - } + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo()", expectedCodeAfterCommit); } -}"; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo", expectedCodeAfterCommit); + [WpfFact] + public async Task CommitOverrideAsUnsafeSealed() + { + var markupBeforeCommit = """ + class c + { + public virtual void goo() { }; + } + + class d : c + { + unsafe sealed override $$ + } + """; + + var expectedCodeAfterCommit = """ + class c + { + public virtual void goo() { }; + } + + class d : c + { + public sealed override unsafe void goo() + { + base.goo();$$ + } + } + """; + + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo()", expectedCodeAfterCommit); } [WpfFact] - public async Task CommitInsertPropertyBeforeMethod() + public async Task CommitInsertProperty() { - var markupBeforeCommit = @"public class c -{ - public virtual int goo { get; set; } -} + var markupBeforeCommit = """ + public class c + { + public virtual int goo { get; set; } + } -public class d : c -{ - override $$ - public void a() { } -}"; + public class d : c + { + override $$ + } + """; - var expectedCodeAfterCommit = @"public class c -{ - public virtual int goo { get; set; } -} + var expectedCodeAfterCommit = """ + public class c + { + public virtual int goo { get; set; } + } -public class d : c -{ - public override int goo - { - get - { - return base.goo;$$ - } + public class d : c + { + public override int goo + { + get + { + [|return base.goo;|] + } - set - { - base.goo = value; - } - } - public void a() { } -}"; + set + { + base.goo = value; + } + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo", expectedCodeAfterCommit); } [WpfFact] - public async Task CommitPropertyInaccessibleGet() + public async Task CommitInsertPropertyAfterMethod() { - var markupBeforeCommit = @"public class c -{ - public virtual int goo { private get; set; } -} + var markupBeforeCommit = """ + public class c + { + public virtual int goo { get; set; } + } -public class d : c -{ - override $$ -}"; + public class d : c + { + public void a() { } + override $$ + } + """; - var expectedCodeAfterCommit = @"public class c -{ - public virtual int goo { private get; set; } -} + var expectedCodeAfterCommit = """ + public class c + { + public virtual int goo { get; set; } + } -public class d : c -{ - public override int goo - { - set - { - base.goo = value;$$ - } - } -}"; + public class d : c + { + public void a() { } + public override int goo + { + get + { + [|return base.goo;|] + } + + set + { + base.goo = value; + } + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo", expectedCodeAfterCommit); } [WpfFact] - public async Task CommitPropertyInaccessibleSet() + public async Task CommitInsertPropertyBeforeMethod() { - var markupBeforeCommit = @"public class c -{ - public virtual int goo { private set; get; } -} + var markupBeforeCommit = """ + public class c + { + public virtual int goo { get; set; } + } -public class d : c -{ - override $$ -}"; + public class d : c + { + override $$ + public void a() { } + } + """; - var expectedCodeAfterCommit = @"public class c -{ - public virtual int goo { private set; get; } -} + var expectedCodeAfterCommit = """ + public class c + { + public virtual int goo { get; set; } + } -public class d : c -{ - public override int goo - { - get - { - return base.goo;$$ - } - } -}"; + public class d : c + { + public override int goo + { + get + { + [|return base.goo;|] + } + + set + { + base.goo = value; + } + } + public void a() { } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo", expectedCodeAfterCommit); } [WpfFact] - public async Task CommitInsertPropertyInaccessibleParameterAttributesAreNotGenerated() + public async Task CommitPropertyInaccessibleGet() { - var markupBeforeCommit = @"using System; + var markupBeforeCommit = """ + public class c + { + public virtual int goo { private get; set; } + } -namespace ClassLibrary1 -{ - public class Class1 - { - private class MyPrivate : Attribute { } + public class d : c + { + override $$ + } + """; - public class MyPublic : Attribute { } + var expectedCodeAfterCommit = """ + public class c + { + public virtual int goo { private get; set; } + } - public virtual int this[[MyPrivate, MyPublic]int i] - { - get { return 0; } - set { } - } + public class d : c + { + public override int goo + { + set + { + [|base.goo = value;|] + } + } + } + """; + + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo", expectedCodeAfterCommit); } - public class Class2 : Class1 + [WpfFact] + public async Task CommitPropertyInaccessibleSet() { - public override int $$ - } -}"; + var markupBeforeCommit = """ + public class c + { + public virtual int goo { private set; get; } + } - var expectedCodeAfterCommit = @"using System; + public class d : c + { + override $$ + } + """; -namespace ClassLibrary1 -{ - public class Class1 - { - private class MyPrivate : Attribute { } + var expectedCodeAfterCommit = """ + public class c + { + public virtual int goo { private set; get; } + } - public class MyPublic : Attribute { } + public class d : c + { + public override int goo + { + get + { + [|return base.goo;|] + } + } + } + """; - public virtual int this[[MyPrivate, MyPublic]int i] - { - get { return 0; } - set { } - } + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo", expectedCodeAfterCommit); } - public class Class2 : Class1 + [WpfFact] + public async Task CommitInsertPropertyInaccessibleParameterAttributesAreNotGenerated() { - public override int this[[MyPublic] int i] - { - get + var markupBeforeCommit = """ + using System; + + namespace ClassLibrary1 { - return base[i];$$ + public class Class1 + { + private class MyPrivate : Attribute { } + + public class MyPublic : Attribute { } + + public virtual int this[[MyPrivate, MyPublic]int i] + { + get { return 0; } + set { } + } + } + + public class Class2 : Class1 + { + public override int $$ + } } + """; + + var expectedCodeAfterCommit = """ + using System; - set + namespace ClassLibrary1 { - base[i] = value; + public class Class1 + { + private class MyPrivate : Attribute { } + + public class MyPublic : Attribute { } + + public virtual int this[[MyPrivate, MyPublic]int i] + { + get { return 0; } + set { } + } + } + + public class Class2 : Class1 + { + public override int this[[MyPublic] int i] + { + get + { + [|return base[i];|] + } + + set + { + base[i] = value; + } + } + } } - } - } -}"; + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "this[int i]", expectedCodeAfterCommit); } @@ -1664,27 +2120,31 @@ public override int this[[MyPublic] int i] [WpfFact] public async Task CommitAccessibleEvent() { - var markupBeforeCommit = @"using System; -public class a -{ - public virtual event EventHandler goo; -} + var markupBeforeCommit = """ + using System; + public class a + { + public virtual event EventHandler goo; + } -public class b : a -{ - override $$ -}"; + public class b : a + { + override $$ + } + """; - var expectedCodeAfterCommit = @"using System; -public class a -{ - public virtual event EventHandler goo; -} + var expectedCodeAfterCommit = """ + using System; + public class a + { + public virtual event EventHandler goo; + } -public class b : a -{ - public override event EventHandler goo;$$ -}"; + public class b : a + { + public override event EventHandler goo;$$ + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo", expectedCodeAfterCommit); } @@ -1692,31 +2152,35 @@ public class b : a [WpfFact] public async Task CommitEventAfterMethod() { - var markupBeforeCommit = @"using System; + var markupBeforeCommit = """ + using System; -public class a -{ - public virtual event EventHandler goo; -} + public class a + { + public virtual event EventHandler goo; + } -public class b : a -{ - void bar() { } - override $$ -}"; + public class b : a + { + void bar() { } + override $$ + } + """; - var expectedCodeAfterCommit = @"using System; + var expectedCodeAfterCommit = """ + using System; -public class a -{ - public virtual event EventHandler goo; -} + public class a + { + public virtual event EventHandler goo; + } -public class b : a -{ - void bar() { } - public override event EventHandler goo;$$ -}"; + public class b : a + { + void bar() { } + public override event EventHandler goo;$$ + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo", expectedCodeAfterCommit); } @@ -1724,32 +2188,36 @@ void bar() { } [WpfFact] public async Task CommitGenericMethod() { - var markupBeforeCommit = @"using System; + var markupBeforeCommit = """ + using System; -public class a -{ - public virtual void goo() { } -} + public class a + { + public virtual void goo() { } + } -public class b : a -{ - override $$ -}"; + public class b : a + { + override $$ + } + """; - var expectedCodeAfterCommit = @"using System; + var expectedCodeAfterCommit = """ + using System; -public class a -{ - public virtual void goo() { } -} + public class a + { + public virtual void goo() { } + } -public class b : a -{ - public override void goo() - { - base.goo();$$ - } -}"; + public class b : a + { + public override void goo() + { + base.goo();$$ + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo()", expectedCodeAfterCommit); } @@ -1757,34 +2225,36 @@ public override void goo() [WpfFact] public async Task CommitMethodWithNullableAttributes() { - var markupBeforeCommit = @" -#nullable enable + var markupBeforeCommit = """ + #nullable enable -class C -{ - public virtual string? Goo(string? s) { } -} + class C + { + public virtual string? Goo(string? s) { } + } -class D : C -{ - override $$ -}"; + class D : C + { + override $$ + } + """; - var expectedCodeAfterCommit = @" -#nullable enable + var expectedCodeAfterCommit = """ + #nullable enable -class C -{ - public virtual string? Goo(string? s) { } -} + class C + { + public virtual string? Goo(string? s) { } + } -class D : C -{ - public override string? Goo(string? s) - { - return base.Goo(s);$$ - } -}"; + class D : C + { + public override string? Goo(string? s) + { + return base.Goo(s);$$ + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "Goo(string? s)", expectedCodeAfterCommit); } @@ -1792,38 +2262,40 @@ class D : C [WpfFact] public async Task CommitMethodInNullableDisableContext() { - var markupBeforeCommit = @" -#nullable enable + var markupBeforeCommit = """ + #nullable enable -class C -{ - public virtual string? Goo(string? s) { } -} + class C + { + public virtual string? Goo(string? s) { } + } -#nullable disable + #nullable disable -class D : C -{ - override $$ -}"; + class D : C + { + override $$ + } + """; - var expectedCodeAfterCommit = @" -#nullable enable + var expectedCodeAfterCommit = """ + #nullable enable -class C -{ - public virtual string? Goo(string? s) { } -} + class C + { + public virtual string? Goo(string? s) { } + } -#nullable disable + #nullable disable -class D : C -{ - public override string Goo(string s) - { - return base.Goo(s);$$ - } -}"; + class D : C + { + public override string Goo(string s) + { + return base.Goo(s);$$ + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "Goo(string? s)", expectedCodeAfterCommit); } @@ -1831,40 +2303,42 @@ public override string Goo(string s) [WpfFact] public async Task CommitToStringIsExplicitlyNonNullReturning() { - var markupBeforeCommit = @" -#nullable enable + var markupBeforeCommit = """ + #nullable enable -namespace System -{ - public class Object - { - public virtual string? ToString() { } - } -} + namespace System + { + public class Object + { + public virtual string? ToString() { } + } + } -class D : System.Object -{ - override $$ -}"; + class D : System.Object + { + override $$ + } + """; - var expectedCodeAfterCommit = @" -#nullable enable + var expectedCodeAfterCommit = """ + #nullable enable -namespace System -{ - public class Object - { - public virtual string? ToString() { } - } -} + namespace System + { + public class Object + { + public virtual string? ToString() { } + } + } -class D : System.Object -{ - public override string ToString() - { - return base.ToString();$$ - } -}"; + class D : System.Object + { + public override string ToString() + { + return base.ToString();$$ + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "ToString()", expectedCodeAfterCommit); } @@ -1872,58 +2346,62 @@ public override string ToString() [WpfFact] public async Task CommitInsertIndexer() { - var markupBeforeCommit = @"public class MyIndexer -{ - private T[] arr = new T[100]; - public virtual T this[int i] - { - get - { - return arr[i]; - } - set - { - arr[i] = value; - } - } -} + var markupBeforeCommit = """ + public class MyIndexer + { + private T[] arr = new T[100]; + public virtual T this[int i] + { + get + { + return arr[i]; + } + set + { + arr[i] = value; + } + } + } -class d : MyIndexer -{ - override $$ -}"; + class d : MyIndexer + { + override $$ + } + """; - var expectedCodeAfterCommit = @"public class MyIndexer -{ - private T[] arr = new T[100]; - public virtual T this[int i] - { - get - { - return arr[i]; - } - set - { - arr[i] = value; - } - } -} + var expectedCodeAfterCommit = """ + public class MyIndexer + { + private T[] arr = new T[100]; + public virtual T this[int i] + { + get + { + return arr[i]; + } + set + { + arr[i] = value; + } + } + } -class d : MyIndexer -{ - public override T this[int i] - { - get - { - return base[i];$$ - } + class d : MyIndexer + { + public override T this[int i] + { + get + { + [|return base[i];|] + } - set - { - base[i] = value; - } - } -}"; + set + { + base[i] = value; + } + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "this[int i]", expectedCodeAfterCommit); } @@ -1931,38 +2409,42 @@ public override T this[int i] [WpfFact] public async Task CommitAbstractIndexer() { - var markupBeforeCommit = @"public class MyIndexer -{ - private T[] arr = new T[100]; - public abstract T this[int i] { get; set; } -} + var markupBeforeCommit = """ + public class MyIndexer + { + private T[] arr = new T[100]; + public abstract T this[int i] { get; set; } + } -class d : MyIndexer -{ - override $$ -}"; + class d : MyIndexer + { + override $$ + } + """; - var expectedCodeAfterCommit = @"public class MyIndexer -{ - private T[] arr = new T[100]; - public abstract T this[int i] { get; set; } -} + var expectedCodeAfterCommit = """ + public class MyIndexer + { + private T[] arr = new T[100]; + public abstract T this[int i] { get; set; } + } -class d : MyIndexer -{ - public override T this[int i] - { - get - { - throw new System.NotImplementedException();$$ - } + class d : MyIndexer + { + public override T this[int i] + { + get + { + [|throw new System.NotImplementedException();|] + } - set - { - throw new System.NotImplementedException(); - } - } -}"; + set + { + throw new System.NotImplementedException(); + } + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "this[int i]", expectedCodeAfterCommit); } @@ -1975,28 +2457,32 @@ public override T this[int i] [WpfFact] public async Task CommitFormats() { - var markupBeforeCommit = @"class Base -{ - public virtual void goo() { } -} + var markupBeforeCommit = """ + class Base + { + public virtual void goo() { } + } -class Derived : Base -{ -override $$ -}"; + class Derived : Base + { + override $$ + } + """; - var expectedCodeAfterCommit = @"class Base -{ - public virtual void goo() { } -} + var expectedCodeAfterCommit = """ + class Base + { + public virtual void goo() { } + } -class Derived : Base -{ - public override void goo() - { - base.goo();$$ - } -}"; + class Derived : Base + { + public override void goo() + { + base.goo();$$ + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo()", expectedCodeAfterCommit); } @@ -2004,32 +2490,36 @@ public override void goo() [WpfFact] public async Task CommitSimplifiesParameterTypes() { - var markupBeforeCommit = @"using System; + var markupBeforeCommit = """ + using System; -public abstract class Base -{ - public abstract void goo(System.Exception e); -} + public abstract class Base + { + public abstract void goo(System.Exception e); + } -public class SomeClass : Base -{ - override $$ -}"; + public class SomeClass : Base + { + override $$ + } + """; - var expectedCodeAfterCommit = @"using System; + var expectedCodeAfterCommit = """ + using System; -public abstract class Base -{ - public abstract void goo(System.Exception e); -} + public abstract class Base + { + public abstract void goo(System.Exception e); + } -public class SomeClass : Base -{ - public override void goo(Exception e) - { - throw new NotImplementedException();$$ - } -}"; + public class SomeClass : Base + { + public override void goo(Exception e) + { + throw new NotImplementedException();$$ + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo(Exception e)", expectedCodeAfterCommit); } @@ -2037,32 +2527,36 @@ public override void goo(Exception e) [WpfFact] public async Task CommitSimplifiesReturnType() { - var markupBeforeCommit = @"using System; + var markupBeforeCommit = """ + using System; -public abstract class Base -{ - public abstract System.ArgumentException goo(System.Exception e); -} + public abstract class Base + { + public abstract System.ArgumentException goo(System.Exception e); + } -public class SomeClass : Base -{ - override $$ -}"; + public class SomeClass : Base + { + override $$ + } + """; - var expectedCodeAfterCommit = @"using System; + var expectedCodeAfterCommit = """ + using System; -public abstract class Base -{ - public abstract System.ArgumentException goo(System.Exception e); -} + public abstract class Base + { + public abstract System.ArgumentException goo(System.Exception e); + } -public class SomeClass : Base -{ - public override ArgumentException goo(Exception e) - { - throw new NotImplementedException();$$ - } -}"; + public class SomeClass : Base + { + public override ArgumentException goo(Exception e) + { + throw new NotImplementedException();$$ + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo(Exception e)", expectedCodeAfterCommit); } @@ -2070,31 +2564,35 @@ public override ArgumentException goo(Exception e) [WpfFact] public async Task CommitEscapedMethodName() { - var markupBeforeCommit = @"using System; + var markupBeforeCommit = """ + using System; -public abstract class Base -{ - public abstract void @class(); -} + public abstract class Base + { + public abstract void @class(); + } -public class SomeClass : Base -{ - override $$ -}"; - var expectedCodeAfterCommit = @"using System; + public class SomeClass : Base + { + override $$ + } + """; + var expectedCodeAfterCommit = """ + using System; -public abstract class Base -{ - public abstract void @class(); -} + public abstract class Base + { + public abstract void @class(); + } -public class SomeClass : Base -{ - public override void @class() - { - throw new NotImplementedException();$$ - } -}"; + public class SomeClass : Base + { + public override void @class() + { + throw new NotImplementedException();$$ + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "@class()", expectedCodeAfterCommit); } @@ -2102,36 +2600,40 @@ public override void @class() [WpfFact] public async Task CommitEscapedPropertyName() { - var markupBeforeCommit = @"public abstract class Base -{ - public virtual int @class { get; set; } -} + var markupBeforeCommit = """ + public abstract class Base + { + public virtual int @class { get; set; } + } -public class SomeClass : Base -{ - override $$ -}"; + public class SomeClass : Base + { + override $$ + } + """; - var expectedCodeAfterCommit = @"public abstract class Base -{ - public virtual int @class { get; set; } -} + var expectedCodeAfterCommit = """ + public abstract class Base + { + public virtual int @class { get; set; } + } -public class SomeClass : Base -{ - public override int @class - { - get - { - return base.@class;$$ - } + public class SomeClass : Base + { + public override int @class + { + get + { + [|return base.@class;|] + } - set - { - base.@class = value; - } - } -}"; + set + { + base.@class = value; + } + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "@class", expectedCodeAfterCommit); } @@ -2139,32 +2641,36 @@ public override int @class [WpfFact] public async Task CommitEscapedParameterName() { - var markupBeforeCommit = @"using System; + var markupBeforeCommit = """ + using System; -public abstract class Base -{ - public abstract void goo(int @class); -} + public abstract class Base + { + public abstract void goo(int @class); + } -public class SomeClass : Base -{ - override $$ -}"; + public class SomeClass : Base + { + override $$ + } + """; - var expectedCodeAfterCommit = @"using System; + var expectedCodeAfterCommit = """ + using System; -public abstract class Base -{ - public abstract void goo(int @class); -} + public abstract class Base + { + public abstract void goo(int @class); + } -public class SomeClass : Base -{ - public override void goo(int @class) - { - throw new NotImplementedException();$$ - } -}"; + public class SomeClass : Base + { + public override void goo(int @class) + { + throw new NotImplementedException();$$ + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo(int @class)", expectedCodeAfterCommit); } @@ -2172,32 +2678,36 @@ public override void goo(int @class) [WpfFact] public async Task CommitRefParameter() { - var markupBeforeCommit = @"using System; + var markupBeforeCommit = """ + using System; -public abstract class Base -{ - public abstract void goo(int x, ref string y); -} + public abstract class Base + { + public abstract void goo(int x, ref string y); + } -public class SomeClass : Base -{ - override $$ -}"; + public class SomeClass : Base + { + override $$ + } + """; - var expectedCodeAfterCommit = @"using System; + var expectedCodeAfterCommit = """ + using System; -public abstract class Base -{ - public abstract void goo(int x, ref string y); -} + public abstract class Base + { + public abstract void goo(int x, ref string y); + } -public class SomeClass : Base -{ - public override void goo(int x, ref string y) - { - throw new NotImplementedException();$$ - } -}"; + public class SomeClass : Base + { + public override void goo(int x, ref string y) + { + throw new NotImplementedException();$$ + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo(int x, ref string y)", expectedCodeAfterCommit); } @@ -2205,32 +2715,36 @@ public override void goo(int x, ref string y) [WpfFact] public async Task CommitOutParameter() { - var markupBeforeCommit = @"using System; + var markupBeforeCommit = """ + using System; -public abstract class Base -{ - public abstract void goo(int x, out string y); -} + public abstract class Base + { + public abstract void goo(int x, out string y); + } -public class SomeClass : Base -{ - override $$ -}"; + public class SomeClass : Base + { + override $$ + } + """; - var expectedCodeAfterCommit = @"using System; + var expectedCodeAfterCommit = """ + using System; -public abstract class Base -{ - public abstract void goo(int x, out string y); -} + public abstract class Base + { + public abstract void goo(int x, out string y); + } -public class SomeClass : Base -{ - public override void goo(int x, out string y) - { - throw new NotImplementedException();$$ - } -}"; + public class SomeClass : Base + { + public override void goo(int x, out string y) + { + throw new NotImplementedException();$$ + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo(int x, out string y)", expectedCodeAfterCommit); } @@ -2239,33 +2753,37 @@ public override void goo(int x, out string y) public async Task TestUnsafe1() { var markupBeforeCommit = -@"public class A -{ - public unsafe virtual void F() - { - } -} + """ + public class A + { + public unsafe virtual void F() + { + } + } -public class B : A -{ - override $$ -}"; + public class B : A + { + override $$ + } + """; var expectedCodeAfterCommit = -@"public class A -{ - public unsafe virtual void F() - { - } -} + """ + public class A + { + public unsafe virtual void F() + { + } + } -public class B : A -{ - public override void F() - { - base.F();$$ - } -}"; + public class B : A + { + public override void F() + { + base.F();$$ + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "F()", expectedCodeAfterCommit); } @@ -2274,33 +2792,37 @@ public override void F() public async Task TestUnsafe2() { var markupBeforeCommit = -@"public class A -{ - public unsafe virtual void F() - { - } -} + """ + public class A + { + public unsafe virtual void F() + { + } + } -public class B : A -{ - override unsafe $$ -}"; + public class B : A + { + override unsafe $$ + } + """; var expectedCodeAfterCommit = -@"public class A -{ - public unsafe virtual void F() - { - } -} + """ + public class A + { + public unsafe virtual void F() + { + } + } -public class B : A -{ - public override unsafe void F() - { - base.F();$$ - } -}"; + public class B : A + { + public override unsafe void F() + { + base.F();$$ + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "F()", expectedCodeAfterCommit); } @@ -2309,33 +2831,37 @@ public override unsafe void F() public async Task TestUnsafe3() { var markupBeforeCommit = -@"public class A -{ - public unsafe virtual void F() - { - } -} + """ + public class A + { + public unsafe virtual void F() + { + } + } -public class B : A -{ - unsafe override $$ -}"; + public class B : A + { + unsafe override $$ + } + """; var expectedCodeAfterCommit = -@"public class A -{ - public unsafe virtual void F() - { - } -} + """ + public class A + { + public unsafe virtual void F() + { + } + } -public class B : A -{ - public override unsafe void F() - { - base.F();$$ - } -}"; + public class B : A + { + public override unsafe void F() + { + base.F();$$ + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "F()", expectedCodeAfterCommit); } @@ -2344,33 +2870,37 @@ public override unsafe void F() public async Task TestUnsafe4() { var markupBeforeCommit = -@"public class A -{ - public virtual void F(int* i) - { - } -} + """ + public class A + { + public virtual void F(int* i) + { + } + } -public class B : A -{ - override $$ -}"; + public class B : A + { + override $$ + } + """; var expectedCodeAfterCommit = -@"public class A -{ - public virtual void F(int* i) - { - } -} + """ + public class A + { + public virtual void F(int* i) + { + } + } -public class B : A -{ - public override unsafe void F(int* i) - { - base.F(i);$$ - } -}"; + public class B : A + { + public override unsafe void F(int* i) + { + base.F(i);$$ + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "F(int* i)", expectedCodeAfterCommit); } @@ -2379,38 +2909,42 @@ public override unsafe void F(int* i) public async Task TestPrivateVirtualProperty() { var markupBeforeCommit = -@"public class B -{ - public virtual int Goo - { - get; private set; - } + """ + public class B + { + public virtual int Goo + { + get; private set; + } - class C : B - { - override $$ - } -}"; + class C : B + { + override $$ + } + } + """; var expectedCodeAfterCommit = -@"public class B -{ - public virtual int Goo - { - get; private set; - } - - class C : B - { - public override int Goo - { - get + """ + public class B { - return base.Goo;$$ + public virtual int Goo + { + get; private set; + } + + class C : B + { + public override int Goo + { + get + { + [|return base.Goo;|] + } + } + } } - } - } -}"; + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "Goo", expectedCodeAfterCommit); } @@ -2418,47 +2952,51 @@ public override int Goo [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/636706")] public async Task CrossLanguageParameterizedPropertyOverride() { - var vbFile = @"Public Class Goo - Public Overridable Property Bar(bay As Integer) As Integer - Get - Return 23 - End Get - Set(value As Integer) - - End Set - End Property -End Class -"; - var csharpFile = @"class Program : Goo -{ - override $$ -} -"; - var csharpFileAfterCommit = @"class Program : Goo -{ - public override int get_Bar(int bay) - { - return base.get_Bar(bay);$$ - } - public override void set_Bar(int bay, int value) - { - base.set_Bar(bay, value); - } -} -"; - var xmlString = string.Format(@" - - - VBProject - {1} - - - -{3} - - - -", LanguageNames.CSharp, csharpFile, LanguageNames.VisualBasic, vbFile); + var vbFile = """ + Public Class Goo + Public Overridable Property Bar(bay As Integer) As Integer + Get + Return 23 + End Get + Set(value As Integer) + + End Set + End Property + End Class + """; + var csharpFile = """ + class Program : Goo + { + override $$ + } + """; + var csharpFileAfterCommit = """ + class Program : Goo + { + public override int get_Bar(int bay) + { + return base.get_Bar(bay);$$ + } + public override void set_Bar(int bay, int value) + { + base.set_Bar(bay, value); + } + } + """; + var xmlString = string.Format(""" + + + VBProject + {1} + + + + {3} + + + + + """, LanguageNames.CSharp, csharpFile, LanguageNames.VisualBasic, vbFile); using var testWorkspace = EditorTestWorkspace.Create(xmlString, composition: GetComposition()); var testDocument = testWorkspace.Documents.Single(d => d.Name == "CSharpDocument"); @@ -2470,248 +3008,478 @@ public override void set_Bar(int bay, int value) var document = solution.GetRequiredDocument(documentId); var triggerInfo = CompletionTrigger.Invoke; - var service = GetCompletionService(document.Project); - var completionList = await GetCompletionListAsync(service, document, position, triggerInfo); - var completionItem = completionList.ItemsList.First(i => CompareItems(i.DisplayText, "Bar[int bay]")); + var service = GetCompletionService(document.Project); + var completionList = await GetCompletionListAsync(service, document, position, triggerInfo); + var completionItem = completionList.ItemsList.First(i => CompareItems(i.DisplayText, "Bar[int bay]")); + + if (service.GetProvider(completionItem, document.Project) is ICustomCommitCompletionProvider customCommitCompletionProvider) + { + var textView = testDocument.GetTextView(); + customCommitCompletionProvider.Commit(completionItem, document, textView, textView.TextBuffer, textView.TextSnapshot, '\t'); + var actualCodeAfterCommit = textView.TextBuffer.CurrentSnapshot.AsText().ToString(); + var caretPosition = textView.Caret.Position.BufferPosition.Position; + MarkupTestFile.GetPosition(csharpFileAfterCommit, out var actualExpectedCode, out int expectedCaretPosition); + + Assert.Equal(actualExpectedCode, actualCodeAfterCommit); + Assert.Equal(expectedCaretPosition, caretPosition); + } + } + + #endregion + + #region "Commit: With Trivia" + + [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/529199")] + public async Task CommitSurroundingTriviaDirective() + { + var markupBeforeCommit = """ + class Base + { + public virtual void goo() { } + } + + class Derived : Base + { + #if true + override $$ + #endif + } + """; + + var expectedCodeAfterCommit = """ + class Base + { + public virtual void goo() { } + } + + class Derived : Base + { + #if true + public override void goo() + { + base.goo();$$ + } + #endif + } + """; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo()", expectedCodeAfterCommit); + } + + [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/529199")] + public async Task CommitBeforeTriviaDirective() + { + var markupBeforeCommit = """ + class Base + { + public virtual void goo() { } + } + + class Derived : Base + { + override $$ + #if true + #endif + } + """; + + var expectedCodeAfterCommit = """ + class Base + { + public virtual void goo() { } + } + + class Derived : Base + { + public override void goo() + { + base.goo();$$ + } + #if true + #endif + } + """; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo()", expectedCodeAfterCommit); + } + + [WpfFact] + public async Task CommitAfterTriviaDirective() + { + var markupBeforeCommit = """ + class Base + { + public virtual void goo() { } + } + + class Derived : Base + { + #if true + #endif + override $$ + } + """; + + var expectedCodeAfterCommit = """ + class Base + { + public virtual void goo() { } + } + + class Derived : Base + { + #if true + #endif + public override void goo() + { + base.goo();$$ + } + } + """; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo()", expectedCodeAfterCommit); + } + + [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/529199")] + public async Task CommitBeforeComment1() + { + var markupBeforeCommit = """ + class Base + { + public virtual void goo() { } + } + + class Derived : Base + { + override $$ + /* comment */ + } + """; + + var expectedCodeAfterCommit = """ + class Base + { + public virtual void goo() { } + } + + class Derived : Base + { + public override void goo() + { + base.goo();$$ + } + /* comment */ + } + """; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo()", expectedCodeAfterCommit); + } + + [WpfFact] + public async Task CommitBeforeComment2() + { + var markupBeforeCommit = """ + class Base + { + public virtual void goo() { } + } + + class Derived : Base + { + override $$/* comment */ + } + """; - if (service.GetProvider(completionItem, document.Project) is ICustomCommitCompletionProvider customCommitCompletionProvider) - { - var textView = testDocument.GetTextView(); - customCommitCompletionProvider.Commit(completionItem, document, textView, textView.TextBuffer, textView.TextSnapshot, '\t'); - var actualCodeAfterCommit = textView.TextBuffer.CurrentSnapshot.AsText().ToString(); - var caretPosition = textView.Caret.Position.BufferPosition.Position; - MarkupTestFile.GetPosition(csharpFileAfterCommit, out var actualExpectedCode, out int expectedCaretPosition); + var expectedCodeAfterCommit = """ + class Base + { + public virtual void goo() { } + } - Assert.Equal(actualExpectedCode, actualCodeAfterCommit); - Assert.Equal(expectedCaretPosition, caretPosition); - } + class Derived : Base + { + public override void goo() + { + base.goo();$$ + } /* comment */ + } + """; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo()", expectedCodeAfterCommit); } - #endregion + [WpfFact] + public async Task CommitBeforeComment3() + { + var markupBeforeCommit = """ + class Base + { + public virtual void goo() { } + } - #region "Commit: With Trivia" + class Derived : Base + { + override go$$/* comment */ + } + """; - [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/529199")] - public async Task CommitSurroundingTriviaDirective() + var expectedCodeAfterCommit = """ + class Base + { + public virtual void goo() { } + } + + class Derived : Base + { + public override void goo() + { + base.goo();$$ + } /* comment */ + } + """; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo()", expectedCodeAfterCommit); + } + + [WpfFact] + public async Task CommitAfterComment1() { - var markupBeforeCommit = @"class Base -{ - public virtual void goo() { } -} + var markupBeforeCommit = """ + class Base + { + public virtual void goo() { } + } -class Derived : Base -{ -#if true -override $$ -#endif -}"; + class Derived : Base + { + /* comment */ + override $$ + } + """; - var expectedCodeAfterCommit = @"class Base -{ - public virtual void goo() { } -} + var expectedCodeAfterCommit = """ + class Base + { + public virtual void goo() { } + } -class Derived : Base -{ -#if true - public override void goo() - { - base.goo();$$ - } -#endif -}"; + class Derived : Base + { + /* comment */ + public override void goo() + { + base.goo();$$ + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo()", expectedCodeAfterCommit); } - [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/529199")] - public async Task CommitBeforeTriviaDirective() + [WpfFact] + public async Task CommitAfterComment2() { - var markupBeforeCommit = @"class Base -{ - public virtual void goo() { } -} + var markupBeforeCommit = """ + class Base + { + public virtual void goo() { } + } -class Derived : Base -{ -override $$ - #if true - #endif -}"; + class Derived : Base + { + /* comment */ + // another comment + override $$ + } + """; - var expectedCodeAfterCommit = @"class Base -{ - public virtual void goo() { } -} + var expectedCodeAfterCommit = """ + class Base + { + public virtual void goo() { } + } -class Derived : Base -{ - public override void goo() - { - base.goo();$$ - } -#if true -#endif -}"; + class Derived : Base + { + /* comment */ + // another comment + public override void goo() + { + base.goo();$$ + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo()", expectedCodeAfterCommit); } [WpfFact] - public async Task CommitAfterTriviaDirective() + public async Task CommitAfterComment3() { - var markupBeforeCommit = @"class Base -{ - public virtual void goo() { } -} + var markupBeforeCommit = """ + class Base + { + public virtual void goo() { } + } -class Derived : Base -{ -#if true -#endif -override $$ -}"; + class Derived : Base + { + /* comment */ override $$ + } + """; - var expectedCodeAfterCommit = @"class Base -{ - public virtual void goo() { } -} + var expectedCodeAfterCommit = """ + class Base + { + public virtual void goo() { } + } -class Derived : Base -{ -#if true -#endif - public override void goo() - { - base.goo();$$ - } -}"; + class Derived : Base + { + /* comment */ + public override void goo() + { + base.goo();$$ + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo()", expectedCodeAfterCommit); } - [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/529199")] - public async Task CommitBeforeComment() + [WpfFact] + public async Task CommitAfterComment4() { - var markupBeforeCommit = @"class Base -{ - public virtual void goo() { } -} + var markupBeforeCommit = """ + class Base + { + public virtual void goo() { } + } -class Derived : Base -{ -override $$ - /* comment */ -}"; + class Derived : Base + { + /* comment */ override go$$ + } + """; - var expectedCodeAfterCommit = @"class Base -{ - public virtual void goo() { } -} + var expectedCodeAfterCommit = """ + class Base + { + public virtual void goo() { } + } -class Derived : Base -{ - public override void goo() - { - base.goo();$$ - } - /* comment */ -}"; + class Derived : Base + { + /* comment */ + public override void goo() + { + base.goo();$$ + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo()", expectedCodeAfterCommit); } [WpfFact] - public async Task CommitAfterComment() + public async Task CommitBeforeAndAfterComment() { - var markupBeforeCommit = @"class Base -{ - public virtual void goo() { } -} + var markupBeforeCommit = """ + class Base + { + public virtual void goo() { } + } -class Derived : Base -{ - /* comment */ -override $$ -}"; + class Derived : Base + { + // Comment + override $$ + /* comment */ + } + """; - var expectedCodeAfterCommit = @"class Base -{ - public virtual void goo() { } -} + var expectedCodeAfterCommit = """ + class Base + { + public virtual void goo() { } + } -class Derived : Base -{ - /* comment */ - public override void goo() - { - base.goo();$$ - } -}"; + class Derived : Base + { + // Comment + public override void goo() + { + base.goo();$$ + } + /* comment */ + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo()", expectedCodeAfterCommit); } [WpfFact] public async Task DoNotFormatFile() { - var markupBeforeCommit = @"class Program -{ -int zip; - public virtual void goo() - { - - } -} + var markupBeforeCommit = """ + class Program + { + int zip; + public virtual void goo() + { -class C : Program -{ -int bar; - override $$ -}"; + } + } - var expectedCodeAfterCommit = @"class Program -{ -int zip; - public virtual void goo() - { - - } -} + class C : Program + { + int bar; + override $$ + } + """; -class C : Program -{ -int bar; - public override void goo() - { - base.goo();$$ - } -}"; + var expectedCodeAfterCommit = """ + class Program + { + int zip; + public virtual void goo() + { + + } + } + + class C : Program + { + int bar; + public override void goo() + { + base.goo();$$ + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo()", expectedCodeAfterCommit); } [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/736742")] public async Task AcrossPartialTypes1() { - var file1 = @"partial class c -{ -} -"; - var file2 = @"partial class c -{ - override $$ -} -"; - var csharpFileAfterCommit = @"partial class c -{ - public override bool Equals(object obj) - { - return base.Equals(obj);$$ - } -} -"; - var xmlString = string.Format(@" - - - {1} - {2} - -", LanguageNames.CSharp, file1, file2); + var file1 = """ + partial class c + { + } + """; + var file2 = """ + partial class c + { + override $$ + } + """; + var csharpFileAfterCommit = """ + partial class c + { + public override bool Equals(object obj) + { + return base.Equals(obj);$$ + } + } + """; + var xmlString = string.Format(""" + + + {1} + {2} + + + """, LanguageNames.CSharp, file1, file2); using var testWorkspace = EditorTestWorkspace.Create(xmlString, composition: GetComposition()); var testDocument = testWorkspace.Documents.Single(d => d.Name == "CSharpDocument2"); @@ -2741,32 +3509,36 @@ public override bool Equals(object obj) } [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/736742")] - public async Task AcrossPartialTypes2() - { - var file1 = @"partial class c -{ -} -"; - var file2 = @"partial class c -{ - override $$ -} -"; - var csharpFileAfterCommit = @"partial class c -{ - public override bool Equals(object obj) + public async Task AcrossPartialTypes2() { - return base.Equals(obj);$$ - } -} -"; - var xmlString = string.Format(@" - - - {1} - {2} - -", LanguageNames.CSharp, file2, file1); + var file1 = """ + partial class c + { + } + """; + var file2 = """ + partial class c + { + override $$ + } + """; + var csharpFileAfterCommit = """ + partial class c + { + public override bool Equals(object obj) + { + return base.Equals(obj);$$ + } + } + """; + var xmlString = string.Format(""" + + + {1} + {2} + + + """, LanguageNames.CSharp, file2, file1); using var testWorkspace = EditorTestWorkspace.Create(xmlString, composition: GetComposition()); var testDocument = testWorkspace.Documents.Single(d => d.Name == "CSharpDocument"); @@ -2822,7 +3594,7 @@ public override required int Prop { get { - return base.Prop;$$ + [|return base.Prop;|] } } } @@ -2835,19 +3607,21 @@ public override required int Prop [InlineData("override required")] public async Task CommitRequiredKeywordPreserved(string ordering) { - var markupBeforeCommit = $@" - - class Base -{{ - public virtual required int Prop {{ get; }} -}} + var markupBeforeCommit = $$""" + + + class Base + { + public virtual required int Prop { get; } + } -class Derived : Base -{{ - {ordering} $$ -}} - -"; + class Derived : Base + { + {{ordering}} $$ + } + + + """; var expectedCodeAfterCommit = """ class Base @@ -2861,7 +3635,7 @@ public override required int Prop { get { - return base.Prop;$$ + [|return base.Prop;|] } } } @@ -2874,19 +3648,21 @@ public override required int Prop [InlineData("override required")] public async Task CommitRequiredKeywordPreservedWhenBaseIsNotRequired(string ordering) { - var markupBeforeCommit = $@" - - class Base -{{ - public virtual int Prop {{ get; }} -}} + var markupBeforeCommit = $$""" + + + class Base + { + public virtual int Prop { get; } + } -class Derived : Base -{{ - {ordering} $$ -}} - -"; + class Derived : Base + { + {{ordering}} $$ + } + + + """; var expectedCodeAfterCommit = """ class Base @@ -2900,7 +3676,7 @@ public override required int Prop { get { - return base.Prop;$$ + [|return base.Prop;|] } } } @@ -2967,7 +3743,7 @@ public override int this[int i] { get { - return base[i];$$ + [|return base[i];|] } set @@ -2987,17 +3763,19 @@ public override int this[int i] [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545678")] public async Task EditorBrowsable_IgnoredWhenOverridingMethods() { - var markup = @" -class D : B -{ - override $$ -}"; - var referencedCode = @" -public class B -{ - [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] - public virtual void Goo() {} -}"; + var markup = """ + class D : B + { + override $$ + } + """; + var referencedCode = """ + public class B + { + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public virtual void Goo() {} + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -3013,48 +3791,54 @@ await VerifyItemInEditorBrowsableContextsAsync( [WpfFact] public async Task DuplicateMember() { - var markupBeforeCommit = @"class Program -{ - public virtual void goo() {} - public virtual void goo() {} -} + var markupBeforeCommit = """ + class Program + { + public virtual void goo() {} + public virtual void goo() {} + } -class C : Program -{ - override $$ -}"; + class C : Program + { + override $$ + } + """; - var expectedCodeAfterCommit = @"class Program -{ - public virtual void goo() {} - public virtual void goo() {} -} + var expectedCodeAfterCommit = """ + class Program + { + public virtual void goo() {} + public virtual void goo() {} + } -class C : Program -{ - public override void goo() - { - base.goo();$$ - } -}"; + class C : Program + { + public override void goo() + { + base.goo();$$ + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo()", expectedCodeAfterCommit); } [WpfFact] public async Task LeaveTrailingTriviaAlone() { - var text = @" -namespace ConsoleApplication46 -{ - class Program - { - static void Main(string[] args) - { - } + var text = """ - override $$ - } -}"; + namespace ConsoleApplication46 + { + class Program + { + static void Main(string[] args) + { + } + + override $$ + } + } + """; 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(); @@ -3077,36 +3861,40 @@ static void Main(string[] args) [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/8257")] public async Task NotImplementedQualifiedWhenSystemUsingNotPresent_Property() { - var markupBeforeCommit = @"abstract class C -{ - public abstract int goo { get; set; }; -} + var markupBeforeCommit = """ + abstract class C + { + public abstract int goo { get; set; }; + } -class Program : C -{ - override $$ -}"; + class Program : C + { + override $$ + } + """; - var expectedCodeAfterCommit = @"abstract class C -{ - public abstract int goo { get; set; }; -} + var expectedCodeAfterCommit = """ + abstract class C + { + public abstract int goo { get; set; }; + } -class Program : C -{ - public override int goo - { - get - { - throw new System.NotImplementedException();$$ - } + class Program : C + { + public override int goo + { + get + { + [|throw new System.NotImplementedException();|] + } - set - { - throw new System.NotImplementedException(); - } - } -}"; + set + { + throw new System.NotImplementedException(); + } + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo", expectedCodeAfterCommit); } @@ -3114,28 +3902,32 @@ public override int goo [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/8257")] public async Task NotImplementedQualifiedWhenSystemUsingNotPresent_Method() { - var markupBeforeCommit = @"abstract class C -{ - public abstract void goo(); -} + var markupBeforeCommit = """ + abstract class C + { + public abstract void goo(); + } -class Program : C -{ - override $$ -}"; + class Program : C + { + override $$ + } + """; - var expectedCodeAfterCommit = @"abstract class C -{ - public abstract void goo(); -} + var expectedCodeAfterCommit = """ + abstract class C + { + public abstract void goo(); + } -class Program : C -{ - public override void goo() - { - throw new System.NotImplementedException();$$ - } -}"; + class Program : C + { + public override void goo() + { + throw new System.NotImplementedException();$$ + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "goo()", expectedCodeAfterCommit); } @@ -3143,38 +3935,40 @@ public override void goo() [Fact] public async Task FilterOutMethodsWithNonRoundTrippableSymbolKeys() { - var text = XElement.Parse(@" - - - - - - -namespace ClassLibrary2 -{ - public class Missing {} -} - - - - P2 - -namespace ClassLibrary7 -{ - public class Class1 - { - public virtual void Goo(ClassLibrary2.Missing m) {} - public virtual void Bar() {} - } -} - - -"); + var text = XElement.Parse(""" + + + + + + + + namespace ClassLibrary2 + { + public class Missing {} + } + + + + P2 + + namespace ClassLibrary7 + { + public class Class1 + { + public virtual void Goo(ClassLibrary2.Missing m) {} + public virtual void Bar() {} + } + } + + + + """); // P3 has a project ref to Project P2 and uses the type "Missing" from P2 // as the return type of a virtual method. @@ -3207,34 +4001,38 @@ public virtual void Bar() {} [WpfFact] public async Task TestInParameter() { - var source = XElement.Parse(@" - - - - -"); + var markup = """ + public class SomeClass : Base + { + override $$ + } + """; + var source = XElement.Parse($""" + + + + + + + """); using var workspace = EditorTestWorkspace.Create(source, composition: GetComposition()); - var before = @" -public abstract class Base -{ - public abstract void M(in int x); -}"; + var before = """ + public abstract class Base + { + public abstract void M(in int x); + } + """; - var after = @" -public class SomeClass : Base -{ - public override void M(in int x) - { - throw new System.NotImplementedException(); - } -} -"; + var after = """ + public class SomeClass : Base + { + public override void M(in int x) + { + throw new System.NotImplementedException(); + } + } + """; var origComp = await workspace.CurrentSolution.Projects.Single().GetRequiredCompilationAsync(CancellationToken.None); var options = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Latest); @@ -3271,61 +4069,63 @@ public override void M(in int x) [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/39909")] public async Task CommitAddsMissingImports() { - var markupBeforeCommit = @" -namespace NS1 -{ - using NS2; + var markupBeforeCommit = """ + namespace NS1 + { + using NS2; - public class Goo - { - public virtual bool Bar(Baz baz) => true; - } -} + public class Goo + { + public virtual bool Bar(Baz baz) => true; + } + } -namespace NS2 -{ - public class Baz {} -} + namespace NS2 + { + public class Baz {} + } -namespace NS3 -{ - using NS1; + namespace NS3 + { + using NS1; - class D : Goo - { - override $$ - } -}"; + class D : Goo + { + override $$ + } + } + """; - var expectedCodeAfterCommit = @" -namespace NS1 -{ - using NS2; + var expectedCodeAfterCommit = """ + namespace NS1 + { + using NS2; - public class Goo - { - public virtual bool Bar(Baz baz) => true; - } -} + public class Goo + { + public virtual bool Bar(Baz baz) => true; + } + } -namespace NS2 -{ - public class Baz {} -} + namespace NS2 + { + public class Baz {} + } -namespace NS3 -{ - using NS1; - using NS2; + namespace NS3 + { + using NS1; + using NS2; - class D : Goo - { - public override bool Bar(Baz baz) - { - return base.Bar(baz);$$ - } - } -}"; + class D : Goo + { + public override bool Bar(Baz baz) + { + return base.Bar(baz);$$ + } + } + } + """; await VerifyCustomCommitProviderAsync(markupBeforeCommit, "Bar(NS2.Baz baz)", expectedCodeAfterCommit); } @@ -3333,21 +4133,25 @@ public override bool Bar(Baz baz) [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/47941")] public async Task OverrideInRecordWithoutExplicitOverriddenMember() { - await VerifyItemExistsAsync(@"record Program -{ - override $$ -}", "ToString()"); + await VerifyItemExistsAsync(""" + record Program + { + override $$ + } + """, "ToString()"); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/47941")] public async Task OverrideInRecordWithExplicitOverriddenMember() { - await VerifyItemIsAbsentAsync(@"record Program -{ - public override string ToString() => ""; + await VerifyItemIsAbsentAsync(""" + record Program + { + public override string ToString() => "; - override $$ -}", "ToString()"); + override $$ + } + """, "ToString()"); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/47973")] @@ -3360,60 +4164,66 @@ public async Task NoCloneInOverriddenRecord() var cloneMemberName = (string)typeof(WellKnownMemberNames).GetField("CloneMethodName", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null); Assert.Equal("$", cloneMemberName); - await VerifyItemIsAbsentAsync(@" -record Base(); + await VerifyItemIsAbsentAsync(""" + record Base(); -record Program : Base -{ - override $$ -}", cloneMemberName); + record Program : Base + { + override $$ + } + """, cloneMemberName); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/48640")] public async Task ObjectEqualsInClass() { - await VerifyItemExistsAsync(@" -class Program -{ - override $$ -}", "Equals(object obj)"); + await VerifyItemExistsAsync(""" + class Program + { + override $$ + } + """, "Equals(object obj)"); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/48640")] public async Task NoObjectEqualsInOverriddenRecord1() { - await VerifyItemIsAbsentAsync(@" -record Program -{ - override $$ -}", "Equals(object obj)"); + await VerifyItemIsAbsentAsync(""" + record Program + { + override $$ + } + """, "Equals(object obj)"); - await VerifyItemExistsAsync(@" -record Program -{ - override $$ -}", "ToString()"); + await VerifyItemExistsAsync(""" + record Program + { + override $$ + } + """, "ToString()"); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/48640")] public async Task NoObjectEqualsInOverriddenRecord() { - await VerifyItemIsAbsentAsync(@" -record Base(); + await VerifyItemIsAbsentAsync(""" + record Base(); -record Program : Base -{ - override $$ -}", "Equals(object obj)"); + record Program : Base + { + override $$ + } + """, "Equals(object obj)"); - await VerifyItemExistsAsync(@" -record Base(); + await VerifyItemExistsAsync(""" + record Base(); -record Program : Base -{ - override $$ -}", "ToString()"); + record Program : Base + { + override $$ + } + """, "ToString()"); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/64887")] diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests_ExpressionBody.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests_ExpressionBody.cs index 9be11ad9073a2..44b6bea63e94b 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests_ExpressionBody.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests_ExpressionBody.cs @@ -51,7 +51,7 @@ class B public virtual int A { get; set; } class C : B { - public override int A { get => base.A$$; set => base.A = value; } + public override int A { get => [|base.A|]; set => base.A = value; } } } """; @@ -79,7 +79,7 @@ class B public virtual int A { get; } class C : B { - public override int A => base.A;$$ + public override int A => [|base.A|]; } } """; @@ -107,7 +107,7 @@ class B public virtual int A() => 2; class C : B { - public override int A() => base.A();$$ + public override int A() => [|base.A()|]; } } """; diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/PartialMethodCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/PartialMethodCompletionProviderTests.cs index ad53c33da24ba..6b09c636c744f 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/PartialMethodCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/PartialMethodCompletionProviderTests.cs @@ -417,7 +417,7 @@ partial class c partial void goo() { - throw new System.NotImplementedException();$$ + [|throw new System.NotImplementedException();|] } } """; @@ -444,7 +444,7 @@ partial class c public partial void goo() { - throw new System.NotImplementedException();$$ + [|throw new System.NotImplementedException();|] } } """; @@ -471,7 +471,7 @@ partial class c partial void goo(T bar) { - throw new System.NotImplementedException();$$ + [|throw new System.NotImplementedException();|] } } """; @@ -498,7 +498,7 @@ partial class c public partial void goo(T bar) { - throw new System.NotImplementedException();$$ + [|throw new System.NotImplementedException();|] } } """; @@ -525,7 +525,7 @@ partial class c partial void goo() { - throw new System.NotImplementedException();$$ + [|throw new System.NotImplementedException();|] } } """; @@ -552,7 +552,7 @@ partial class c private partial void goo() { - throw new System.NotImplementedException();$$ + [|throw new System.NotImplementedException();|] } } """; @@ -585,7 +585,7 @@ partial class c { partial void goo() { - throw new System.NotImplementedException();$$ + [|throw new System.NotImplementedException();|] } } """; @@ -618,7 +618,7 @@ partial class c { public partial void goo() { - throw new System.NotImplementedException();$$ + [|throw new System.NotImplementedException();|] } } """; @@ -645,7 +645,7 @@ partial struct c partial void goo() { - throw new System.NotImplementedException();$$ + [|throw new System.NotImplementedException();|] } } """; @@ -744,7 +744,7 @@ partial class Bar async partial void Goo() { - throw new NotImplementedException();$$ + [|throw new NotImplementedException();|] } } """; @@ -775,7 +775,7 @@ partial class Bar public async partial void Goo() { - throw new NotImplementedException();$$ + [|throw new NotImplementedException();|] } } """; @@ -806,7 +806,7 @@ partial class Bar partial void Goo() { - throw new NotImplementedException();$$ + [|throw new NotImplementedException();|] } } """; @@ -838,7 +838,7 @@ partial class PClass partial void PMethod(int i) { - throw new System.NotImplementedException();$$ + [|throw new System.NotImplementedException();|] } } } @@ -870,7 +870,7 @@ partial class PClass public partial void PMethod(int i) { - throw new System.NotImplementedException();$$ + [|throw new System.NotImplementedException();|] } } } @@ -903,7 +903,7 @@ partial class Bar partial class Bar { partial void Foo(); - partial void Foo() => throw new NotImplementedException();$$ + partial void Foo() => [|throw new NotImplementedException()|]; } """; @@ -936,7 +936,7 @@ partial class Bar partial class Bar { public partial void Foo(); - public partial void Foo() => throw new NotImplementedException();$$ + public partial void Foo() => [|throw new NotImplementedException()|]; } """ ; diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SuggestionModeCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SuggestionModeCompletionProviderTests.cs index eea714b6f5cb6..eafd50df635d8 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SuggestionModeCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SuggestionModeCompletionProviderTests.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion; diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs index 852c05cdd1aed..e852e3ab07c26 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs @@ -15080,6 +15080,22 @@ await VerifyExpectedItemsAsync(markup, [ ]); } + [Theory, CombinatorialData] + public async Task PartialPropertyOrConstructor( + [CombinatorialValues("class", "struct", "record", "record class", "record struct", "interface")] string typeKind, + [CombinatorialValues("", "public", "private", "static", "extern")] string modifiers) + { + var markup = $$""" + partial {{typeKind}} C + { + {{modifiers}} partial $$ + } + """; + await VerifyExpectedItemsAsync(markup, [ + ItemExpectation.Exists("C"), + ]); + } + private static string MakeMarkup([StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string source, string languageVersion = "Preview") { return $$""" diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs index 898774278f37c..eaa5f45171cc0 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs @@ -13,8 +13,8 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.UnitTests; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Serialization; using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.UnitTests.Diagnostics; @@ -49,7 +49,9 @@ public async Task DiagnosticAnalyzerDriverAllInOne() SyntaxKind.RecordDeclaration, SyntaxKind.CollectionExpression, SyntaxKind.ExpressionElement, - SyntaxKind.SpreadElement + SyntaxKind.SpreadElement, + // Tracked by https://github.com/dotnet/roslyn/issues/76130 Add to all-in-one + SyntaxKind.ExtensionDeclaration, }; var analyzer = new CSharpTrackingDiagnosticAnalyzer(); @@ -775,6 +777,7 @@ private static async Task TestNuGetAndVsixAnalyzerCoreAsync( if (nugetAnalyzerReferences.Count > 0) { project = project.WithAnalyzerReferences([new AnalyzerImageReference([.. nugetAnalyzerReferences])]); + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences); } var document = project.Documents.Single(); diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTrackingServiceTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTrackingServiceTests.cs index fa125e94658f5..3330a4014a865 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTrackingServiceTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTrackingServiceTests.cs @@ -4,7 +4,6 @@ #nullable disable -using System.Collections.Immutable; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -14,7 +13,6 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; -using Roslyn.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.EditAndContinue.UnitTests; diff --git a/src/EditorFeatures/CSharpTest/ExtractInterface/ExtractInterfaceTests.cs b/src/EditorFeatures/CSharpTest/ExtractInterface/ExtractInterfaceTests.cs index 2116634f0c926..13eb5390aa1f5 100644 --- a/src/EditorFeatures/CSharpTest/ExtractInterface/ExtractInterfaceTests.cs +++ b/src/EditorFeatures/CSharpTest/ExtractInterface/ExtractInterfaceTests.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.ExtractInterface; +using Microsoft.CodeAnalysis.CSharp.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.UnitTests; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Editor.UnitTests.Extensions; @@ -2087,4 +2088,24 @@ public static void M() { } await TestExtractInterfaceCodeActionCSharpAsync(markup, expectedMarkup); } + + [WpfFact] + public async Task ExtractInterface_Invocation_FromExtension() + { + var markup = """ + using System; + + static class C + { + $$extension(string s) + { + public void Goo() { } + } + } + """; + + await TestExtractInterfaceCommandCSharpAsync( + markup, expectedSuccess: false, + parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersionExtensions.CSharpNext)); + } } diff --git a/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs b/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs index 3a71fabe43350..e34b8bd657eba 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs @@ -11,7 +11,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.AddImport; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeStyle; @@ -22,7 +21,6 @@ using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Editor.UnitTests; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; diff --git a/src/EditorFeatures/CSharpTest/Formatting/RazorLineFormattingOptionsTests.cs b/src/EditorFeatures/CSharpTest/Formatting/RazorLineFormattingOptionsTests.cs index 443014bd748e9..38c007dd89a04 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/RazorLineFormattingOptionsTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/RazorLineFormattingOptionsTests.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.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.UnitTests; diff --git a/src/EditorFeatures/CSharpTest/Intents/IntentTestsBase.cs b/src/EditorFeatures/CSharpTest/Intents/IntentTestsBase.cs index 760b1ca4465a7..e1f1635e7463c 100644 --- a/src/EditorFeatures/CSharpTest/Intents/IntentTestsBase.cs +++ b/src/EditorFeatures/CSharpTest/Intents/IntentTestsBase.cs @@ -115,7 +115,7 @@ internal static async Task> GetIntentsAsync( // Get the text change to pass into the API that rewinds the current document to the prior document. var currentDocument = currentTextBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); var textDiffService = workspace.CurrentSolution.Services.GetRequiredService(); - var changes = await textDiffService.GetTextChangesAsync(currentDocument, priorDocument, CancellationToken.None).ConfigureAwait(false); + var changes = await textDiffService.GetTextChangesAsync(currentDocument!, priorDocument, CancellationToken.None).ConfigureAwait(false); // Get the current snapshot span to pass in. var currentSnapshot = new SnapshotSpan(currentTextBuffer.CurrentSnapshot, new Span(0, currentTextBuffer.CurrentSnapshot.Length)); diff --git a/src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs b/src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs index e51030176bce5..9bd49914cde6a 100644 --- a/src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs +++ b/src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs @@ -1532,4 +1532,34 @@ struct MyType2 { {"A.MyType", "B.MyType" } }); + + [Theory] + [InlineData("class MyClass[||](int x, int y)")] + [InlineData("class [||]MyClass(int x, int y)")] + [InlineData("class MyC[||]lass(int x, int y)")] + public Task MoveToNamespace_PrimaryConstructor(string decl) + => TestMoveToNamespaceAsync( + $$""" + namespace A; + + {{decl}} + { + public int X => x; + public int Y => y; + } + """, + expectedMarkup: """ + namespace {|Warning:B|}; + + class MyClass(int x, int y) + { + public int X => x; + public int Y => y; + } + """, + targetNamespace: "B", + expectedSymbolChanges: new Dictionary() + { + {"A.MyClass", "B.MyClass" } + }); } diff --git a/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToSearcherTests.cs b/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToSearcherTests.cs index 8b2080aeaf537..636fe5c32e1f9 100644 --- a/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToSearcherTests.cs +++ b/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToSearcherTests.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Concurrent; using System.Collections.Immutable; using System.Linq; using System.Threading; @@ -12,6 +13,7 @@ using Microsoft.CodeAnalysis.NavigateTo; using Microsoft.CodeAnalysis.Navigation; using Microsoft.CodeAnalysis.PatternMatching; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Moq; @@ -354,6 +356,151 @@ public class D Assert.True(searchGeneratedDocumentsAsyncCalled); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/77051")] + public async Task DocumentScopeRelatedDocuments_Inheritance() + { + using var workspace = EditorTestWorkspace.Create(""" + + + + public class C : Base + { + // Starting search here. + void Goo1() { } + } + + + public class Base + { + // Should find this. + void Goo2() { } + } + public class Other + { + // Should not find this. + void Goo3() { } + } + + + + """, composition: FirstActiveAndVisibleComposition); + + var hostMock = new Mock(MockBehavior.Strict); + hostMock.Setup(h => h.IsFullyLoadedAsync(It.IsAny())).Returns(() => new ValueTask(true)); + + var project = workspace.CurrentSolution.Projects.Single(); + var searchService = project.GetRequiredLanguageService(); + + hostMock.Setup(h => h.GetNavigateToSearchService(It.IsAny())).Returns(() => searchService); + + var callback = new TestNavigateToSearchCallback(); + + var searcher = NavigateToSearcher.Create( + workspace.CurrentSolution, + callback, + "Goo", + kinds: searchService.KindsProvided, + hostMock.Object); + + await searcher.SearchAsync(NavigateToSearchScope.Document, CancellationToken.None); + + Assert.Equal(2, callback.Results.Count); + + var firstDocument = project.Documents.Single(d => d.FilePath!.Contains("file1")); + var secondDocument = project.Documents.Single(d => d.FilePath!.Contains("file2")); + + var firstDocumentResult = Assert.Single(callback.Results, r => r.NavigableItem.Document.Id == firstDocument.Id); + var secondDocumentResult = Assert.Single(callback.Results, r => r.NavigableItem.Document.Id == secondDocument.Id); + + Assert.Equal("Goo1", firstDocumentResult.Name); + Assert.Equal("Goo2", secondDocumentResult.Name); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/77051")] + public async Task DocumentScopeRelatedDocuments_Partial() + { + using var workspace = EditorTestWorkspace.Create(""" + + + + public partial class C + { + // Starting search here. + void Goo1() { } + } + + + public class Base + { + // Should not find this. + void Goo2() { } + } + public partial class C + { + // Should find this. + void Goo3() { } + } + + + + """, composition: FirstActiveAndVisibleComposition); + + var hostMock = new Mock(MockBehavior.Strict); + hostMock.Setup(h => h.IsFullyLoadedAsync(It.IsAny())).Returns(() => new ValueTask(true)); + + var project = workspace.CurrentSolution.Projects.Single(); + var searchService = project.GetRequiredLanguageService(); + + hostMock.Setup(h => h.GetNavigateToSearchService(It.IsAny())).Returns(() => searchService); + + var callback = new TestNavigateToSearchCallback(); + + var searcher = NavigateToSearcher.Create( + workspace.CurrentSolution, + callback, + "Goo", + kinds: searchService.KindsProvided, + hostMock.Object); + + await searcher.SearchAsync(NavigateToSearchScope.Document, CancellationToken.None); + + Assert.Equal(2, callback.Results.Count); + + var firstDocument = project.Documents.Single(d => d.FilePath!.Contains("file1")); + var secondDocument = project.Documents.Single(d => d.FilePath!.Contains("file2")); + + var firstDocumentResult = Assert.Single(callback.Results, r => r.NavigableItem.Document.Id == firstDocument.Id); + var secondDocumentResult = Assert.Single(callback.Results, r => r.NavigableItem.Document.Id == secondDocument.Id); + + Assert.Equal("Goo1", firstDocumentResult.Name); + Assert.Equal("Goo3", secondDocumentResult.Name); + } + + private sealed class TestNavigateToSearchCallback : INavigateToSearchCallback + { + public readonly ConcurrentBag Results = []; + + public void Done(bool isFullyLoaded) + { + } + + public void ReportIncomplete() + { + } + + public Task AddResultsAsync(ImmutableArray results, CancellationToken cancellationToken) + { + foreach (var result in results) + this.Results.Add(result); + + return Task.CompletedTask; + } + + public void ReportProgress(int current, int maximum) + { + } + } + private sealed class MockAdvancedNavigateToSearchService : IAdvancedNavigateToSearchService { public IImmutableSet KindsProvided => AbstractNavigateToSearchService.AllKinds; diff --git a/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToTests.cs b/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToTests.cs index a38c21e711418..da281b494c550 100644 --- a/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToTests.cs +++ b/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToTests.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.Linq; using System.Threading.Tasks; using System.Xml.Linq; @@ -40,45 +39,45 @@ await TestAsync(testHost, composition, "", async w => public async Task FindClass(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -class Goo -{ -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("Goo")).Single(x => x.Kind != "Method"); - VerifyNavigateToResultItem(item, "Goo", "[|Goo|]", PatternMatchKind.Exact, NavigateToItemKind.Class, Glyph.ClassInternal); - }); + testHost, composition, """ + class Goo + { + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("Goo")).Single(x => x.Kind != "Method"); + VerifyNavigateToResultItem(item, "Goo", "[|Goo|]", PatternMatchKind.Exact, NavigateToItemKind.Class, Glyph.ClassInternal); + }); } [Theory, CombinatorialData] public async Task FindRecord(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -record Goo -{ -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("Goo")).Single(x => x.Kind != "Method"); - VerifyNavigateToResultItem(item, "Goo", "[|Goo|]", PatternMatchKind.Exact, NavigateToItemKind.Class, Glyph.ClassInternal); - }); + testHost, composition, """ + record Goo + { + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("Goo")).Single(x => x.Kind != "Method"); + VerifyNavigateToResultItem(item, "Goo", "[|Goo|]", PatternMatchKind.Exact, NavigateToItemKind.Class, Glyph.ClassInternal); + }); } [Theory, CombinatorialData] public async Task FindRecordClass(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -record class Goo -{ -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("Goo")).Single(x => x.Kind != "Method"); - VerifyNavigateToResultItem(item, "Goo", "[|Goo|]", PatternMatchKind.Exact, NavigateToItemKind.Class, Glyph.ClassInternal); - }); + testHost, composition, """ + record class Goo + { + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("Goo")).Single(x => x.Kind != "Method"); + VerifyNavigateToResultItem(item, "Goo", "[|Goo|]", PatternMatchKind.Exact, NavigateToItemKind.Class, Glyph.ClassInternal); + }); } [Theory, CombinatorialData] @@ -126,324 +125,322 @@ await TestAsync(testHost, composition, content, async w => public async Task FindVerbatimClass(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -class @static -{ -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("static")).Single(x => x.Kind != "Method"); - VerifyNavigateToResultItem(item, "static", "[|static|]", PatternMatchKind.Exact, NavigateToItemKind.Class, Glyph.ClassInternal); + testHost, composition, """ + class @static + { + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("static")).Single(x => x.Kind != "Method"); + VerifyNavigateToResultItem(item, "static", "[|static|]", PatternMatchKind.Exact, NavigateToItemKind.Class, Glyph.ClassInternal); - // Check searching for @static too - item = (await _aggregator.GetItemsAsync("@static")).Single(x => x.Kind != "Method"); - VerifyNavigateToResultItem(item, "static", "[|static|]", PatternMatchKind.Exact, NavigateToItemKind.Class, Glyph.ClassInternal); - }); + // Check searching for @static too + item = (await _aggregator.GetItemsAsync("@static")).Single(x => x.Kind != "Method"); + VerifyNavigateToResultItem(item, "static", "[|static|]", PatternMatchKind.Exact, NavigateToItemKind.Class, Glyph.ClassInternal); + }); } [Theory, CombinatorialData] public async Task FindNestedClass(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -class Goo -{ - class Bar - { - internal class DogBed - { - } - } -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("DogBed")).Single(x => x.Kind != "Method"); - VerifyNavigateToResultItem(item, "DogBed", "[|DogBed|]", PatternMatchKind.Exact, NavigateToItemKind.Class, Glyph.ClassInternal); - }); + testHost, composition, """ + class Goo + { + class Bar + { + internal class DogBed + { + } + } + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("DogBed")).Single(x => x.Kind != "Method"); + VerifyNavigateToResultItem(item, "DogBed", "[|DogBed|]", PatternMatchKind.Exact, NavigateToItemKind.Class, Glyph.ClassInternal); + }); } [Theory, CombinatorialData] public async Task FindMemberInANestedClass(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -class Goo -{ - class Bar - { - class DogBed - { - public void Method() + testHost, composition, """ + class Goo { + class Bar + { + class DogBed + { + public void Method() + { + } + } + } } - } - } -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("Method")).Single(); - VerifyNavigateToResultItem(item, "Method", "[|Method|]()", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPublic, string.Format(FeaturesResources.in_0_project_1, "Goo.Bar.DogBed", "Test")); - }); + """, async w => + { + var item = (await _aggregator.GetItemsAsync("Method")).Single(); + VerifyNavigateToResultItem(item, "Method", "[|Method|]()", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPublic, string.Format(FeaturesResources.in_0_project_1, "Goo.Bar.DogBed", "Test")); + }); } [Theory, CombinatorialData] public async Task FindGenericClassWithConstraints(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -using System.Collections; + testHost, composition, """ + using System.Collections; -class Goo where T : IEnumerable -{ -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("Goo")).Single(x => x.Kind != "Method"); - VerifyNavigateToResultItem(item, "Goo", "[|Goo|]", PatternMatchKind.Exact, NavigateToItemKind.Class, Glyph.ClassInternal); - }); + class Goo where T : IEnumerable + { + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("Goo")).Single(x => x.Kind != "Method"); + VerifyNavigateToResultItem(item, "Goo", "[|Goo|]", PatternMatchKind.Exact, NavigateToItemKind.Class, Glyph.ClassInternal); + }); } [Theory, CombinatorialData] public async Task FindGenericMethodWithConstraints(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -using System; + testHost, composition, """ + using System; -class Goo -{ - public void Bar(T item) where T : IComparable - { - } -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("Bar")).Single(); - VerifyNavigateToResultItem(item, "Bar", "[|Bar|](T)", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPublic, string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); - }); + class Goo + { + public void Bar(T item) where T : IComparable + { + } + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("Bar")).Single(); + VerifyNavigateToResultItem(item, "Bar", "[|Bar|](T)", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPublic, string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); + }); } [Theory, CombinatorialData] public async Task FindPartialClass(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -public partial class Goo -{ - int a; -} - -partial class Goo -{ - int b; -} -""", async w => - { - var expecteditem1 = new NavigateToItem("Goo", NavigateToItemKind.Class, "csharp", null, null, s_emptyExactPatternMatch, null); - var expecteditems = new List { expecteditem1, expecteditem1 }; + testHost, composition, """ + public partial class Goo + { + int a; + } - var items = await _aggregator.GetItemsAsync("Goo"); + partial class Goo + { + int b; + } + """, async w => + { + var items = await _aggregator.GetItemsAsync("Goo"); - VerifyNavigateToResultItems(expecteditems, items); - }); + var expecteditem1 = new NavigateToItem("Goo", NavigateToItemKind.Class, "csharp", null, null, s_emptyExactPatternMatch, null); + VerifyNavigateToResultItems([expecteditem1, expecteditem1], items); + }); } [Theory, CombinatorialData] public async Task FindTypesInMetadata(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -using System; + testHost, composition, """ + using System; -Class Program { FileStyleUriParser f; } -""", async w => - { - var items = await _aggregator.GetItemsAsync("FileStyleUriParser"); - Assert.Equal(0, items.Count()); - }); + Class Program { FileStyleUriParser f; } + """, async w => + { + var items = await _aggregator.GetItemsAsync("FileStyleUriParser"); + Assert.Equal(0, items.Count()); + }); } [Theory, CombinatorialData] public async Task FindClassInNamespace(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -namespace Bar -{ - class Goo - { - } -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("Goo")).Single(x => x.Kind != "Method"); - VerifyNavigateToResultItem(item, "Goo", "[|Goo|]", PatternMatchKind.Exact, NavigateToItemKind.Class, Glyph.ClassInternal); - }); + testHost, composition, """ + namespace Bar + { + class Goo + { + } + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("Goo")).Single(x => x.Kind != "Method"); + VerifyNavigateToResultItem(item, "Goo", "[|Goo|]", PatternMatchKind.Exact, NavigateToItemKind.Class, Glyph.ClassInternal); + }); } [Theory, CombinatorialData] public async Task FindStruct(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -struct Bar -{ -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("B")).Single(x => x.Kind != "Method"); - VerifyNavigateToResultItem(item, "Bar", "[|B|]ar", PatternMatchKind.Prefix, NavigateToItemKind.Structure, Glyph.StructureInternal); - }); + testHost, composition, """ + struct Bar + { + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("B")).Single(x => x.Kind != "Method"); + VerifyNavigateToResultItem(item, "Bar", "[|B|]ar", PatternMatchKind.Prefix, NavigateToItemKind.Structure, Glyph.StructureInternal); + }); } [Theory, CombinatorialData] public async Task FindEnum(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -enum Colors -{ - Red, - Green, - Blue -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("Colors")).Single(x => x.Kind != "Method"); - VerifyNavigateToResultItem(item, "Colors", "[|Colors|]", PatternMatchKind.Exact, NavigateToItemKind.Enum, Glyph.EnumInternal); - }); + testHost, composition, """ + enum Colors + { + Red, + Green, + Blue + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("Colors")).Single(x => x.Kind != "Method"); + VerifyNavigateToResultItem(item, "Colors", "[|Colors|]", PatternMatchKind.Exact, NavigateToItemKind.Enum, Glyph.EnumInternal); + }); } [Theory, CombinatorialData] public async Task FindEnumMember(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -enum Colors -{ - Red, - Green, - Blue -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("R")).Single(); - VerifyNavigateToResultItem(item, "Red", "[|R|]ed", PatternMatchKind.Prefix, NavigateToItemKind.EnumItem, Glyph.EnumMemberPublic); - }); + testHost, composition, """ + enum Colors + { + Red, + Green, + Blue + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("R")).Single(); + VerifyNavigateToResultItem(item, "Red", "[|R|]ed", PatternMatchKind.Prefix, NavigateToItemKind.EnumItem, Glyph.EnumMemberPublic); + }); } [Theory, CombinatorialData] public async Task FindField1(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -class Goo -{ - int bar; -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("b")).Single(); - VerifyNavigateToResultItem(item, "bar", "[|b|]ar", PatternMatchKind.Prefix, NavigateToItemKind.Field, Glyph.FieldPrivate, additionalInfo: string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); - }); + testHost, composition, """ + class Goo + { + int bar; + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("b")).Single(); + VerifyNavigateToResultItem(item, "bar", "[|b|]ar", PatternMatchKind.Prefix, NavigateToItemKind.Field, Glyph.FieldPrivate, additionalInfo: string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); + }); } [Theory, CombinatorialData] public async Task FindField2(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -class Goo -{ - int bar; -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("ba")).Single(); - VerifyNavigateToResultItem(item, "bar", "[|ba|]r", PatternMatchKind.Prefix, NavigateToItemKind.Field, Glyph.FieldPrivate, additionalInfo: string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); - }); + testHost, composition, """ + class Goo + { + int bar; + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("ba")).Single(); + VerifyNavigateToResultItem(item, "bar", "[|ba|]r", PatternMatchKind.Prefix, NavigateToItemKind.Field, Glyph.FieldPrivate, additionalInfo: string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); + }); } [Theory, CombinatorialData] public async Task FindField3(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -class Goo -{ - int bar; -} -""", async w => - { - Assert.Empty(await _aggregator.GetItemsAsync("ar")); - }); + testHost, composition, """ + class Goo + { + int bar; + } + """, async w => + { + Assert.Empty(await _aggregator.GetItemsAsync("ar")); + }); } [Theory, CombinatorialData] public async Task FindVerbatimField(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -class Goo -{ - int @string; -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("string")).Single(); - VerifyNavigateToResultItem(item, "string", "[|string|]", PatternMatchKind.Exact, NavigateToItemKind.Field, Glyph.FieldPrivate, additionalInfo: string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); + testHost, composition, """ + class Goo + { + int @string; + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("string")).Single(); + VerifyNavigateToResultItem(item, "string", "[|string|]", PatternMatchKind.Exact, NavigateToItemKind.Field, Glyph.FieldPrivate, additionalInfo: string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); - // Check searching for@string too - item = (await _aggregator.GetItemsAsync("@string")).Single(); - VerifyNavigateToResultItem(item, "string", "[|string|]", PatternMatchKind.Exact, NavigateToItemKind.Field, Glyph.FieldPrivate, additionalInfo: string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); - }); + // Check searching for@string too + item = (await _aggregator.GetItemsAsync("@string")).Single(); + VerifyNavigateToResultItem(item, "string", "[|string|]", PatternMatchKind.Exact, NavigateToItemKind.Field, Glyph.FieldPrivate, additionalInfo: string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); + }); } [Theory, CombinatorialData] public async Task FindPtrField1(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -class Goo -{ - int* bar; -} -""", async w => - { - Assert.Empty(await _aggregator.GetItemsAsync("ar")); - }); + testHost, composition, """ + class Goo + { + int* bar; + } + """, async w => + { + Assert.Empty(await _aggregator.GetItemsAsync("ar")); + }); } [Theory, CombinatorialData] public async Task FindPtrField2(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -class Goo -{ - int* bar; -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("b")).Single(); - VerifyNavigateToResultItem(item, "bar", "[|b|]ar", PatternMatchKind.Prefix, NavigateToItemKind.Field, Glyph.FieldPrivate); - }); + testHost, composition, """ + class Goo + { + int* bar; + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("b")).Single(); + VerifyNavigateToResultItem(item, "bar", "[|b|]ar", PatternMatchKind.Prefix, NavigateToItemKind.Field, Glyph.FieldPrivate); + }); } [Theory, CombinatorialData] public async Task FindConstField(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -class Goo -{ - const int bar = 7; -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("ba")).Single(); - VerifyNavigateToResultItem(item, "bar", "[|ba|]r", PatternMatchKind.Prefix, NavigateToItemKind.Constant, Glyph.ConstantPrivate); - }); + testHost, composition, """ + class Goo + { + const int bar = 7; + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("ba")).Single(); + VerifyNavigateToResultItem(item, "bar", "[|ba|]r", PatternMatchKind.Prefix, NavigateToItemKind.Constant, Glyph.ConstantPrivate); + }); } [Theory, CombinatorialData] @@ -472,124 +469,124 @@ await TestAsync(testHost, composition, program, async w => public async Task FindAutoProperty(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -class Goo -{ - int Bar { get; set; } -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("B")).Single(); - VerifyNavigateToResultItem(item, "Bar", "[|B|]ar", PatternMatchKind.Prefix, NavigateToItemKind.Property, Glyph.PropertyPrivate, additionalInfo: string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); - }); + testHost, composition, """ + class Goo + { + int Bar { get; set; } + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("B")).Single(); + VerifyNavigateToResultItem(item, "Bar", "[|B|]ar", PatternMatchKind.Prefix, NavigateToItemKind.Property, Glyph.PropertyPrivate, additionalInfo: string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); + }); } [Theory, CombinatorialData] public async Task FindMethod(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -class Goo -{ - void DoSomething(); -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("DS")).Single(); - VerifyNavigateToResultItem(item, "DoSomething", "[|D|]o[|S|]omething()", PatternMatchKind.CamelCaseExact, NavigateToItemKind.Method, Glyph.MethodPrivate, string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); - }); + testHost, composition, """ + class Goo + { + void DoSomething(); + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("DS")).Single(); + VerifyNavigateToResultItem(item, "DoSomething", "[|D|]o[|S|]omething()", PatternMatchKind.CamelCaseExact, NavigateToItemKind.Method, Glyph.MethodPrivate, string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); + }); } [Theory, CombinatorialData] public async Task FindVerbatimMethod(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -class Goo -{ - void @static(); -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("static")).Single(); - VerifyNavigateToResultItem(item, "static", "[|static|]()", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPrivate, string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); + testHost, composition, """ + class Goo + { + void @static(); + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("static")).Single(); + VerifyNavigateToResultItem(item, "static", "[|static|]()", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPrivate, string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); - // Verify if we search for @static too - item = (await _aggregator.GetItemsAsync("@static")).Single(); - VerifyNavigateToResultItem(item, "static", "[|static|]()", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPrivate, string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); - }); + // Verify if we search for @static too + item = (await _aggregator.GetItemsAsync("@static")).Single(); + VerifyNavigateToResultItem(item, "static", "[|static|]()", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPrivate, string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); + }); } [Theory, CombinatorialData] public async Task FindParameterizedMethod(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -class Goo -{ - void DoSomething(int a, string b) - { - } -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("DS")).Single(); - VerifyNavigateToResultItem(item, "DoSomething", "[|D|]o[|S|]omething(int, string)", PatternMatchKind.CamelCaseExact, NavigateToItemKind.Method, Glyph.MethodPrivate, string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); - }); + testHost, composition, """ + class Goo + { + void DoSomething(int a, string b) + { + } + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("DS")).Single(); + VerifyNavigateToResultItem(item, "DoSomething", "[|D|]o[|S|]omething(int, string)", PatternMatchKind.CamelCaseExact, NavigateToItemKind.Method, Glyph.MethodPrivate, string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); + }); } [Theory, CombinatorialData] public async Task FindConstructor(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -class Goo -{ - public Goo() - { - } -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("Goo")).Single(t => t.Kind == NavigateToItemKind.Method); - VerifyNavigateToResultItem(item, "Goo", "[|Goo|]()", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPublic, string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); - }); + testHost, composition, """ + class Goo + { + public Goo() + { + } + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("Goo")).Single(t => t.Kind == NavigateToItemKind.Method); + VerifyNavigateToResultItem(item, "Goo", "[|Goo|]()", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPublic, string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); + }); } [Theory, CombinatorialData] public async Task FindParameterizedConstructor(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -class Goo -{ - public Goo(int i) - { - } -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("Goo")).Single(t => t.Kind == NavigateToItemKind.Method); - VerifyNavigateToResultItem(item, "Goo", "[|Goo|](int)", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPublic, string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); - }); + testHost, composition, """ + class Goo + { + public Goo(int i) + { + } + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("Goo")).Single(t => t.Kind == NavigateToItemKind.Method); + VerifyNavigateToResultItem(item, "Goo", "[|Goo|](int)", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPublic, string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); + }); } [Theory, CombinatorialData] public async Task FindStaticConstructor(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -class Goo -{ - static Goo() - { - } -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("Goo")).Single(t => t.Kind == NavigateToItemKind.Method && t.Name != ".ctor"); - VerifyNavigateToResultItem(item, "Goo", "[|Goo|].static Goo()", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPrivate, string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); - }); + testHost, composition, """ + class Goo + { + static Goo() + { + } + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("Goo")).Single(t => t.Kind == NavigateToItemKind.Method && t.Name != ".ctor"); + VerifyNavigateToResultItem(item, "Goo", "[|Goo|].static Goo()", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPrivate, string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); + }); } [Theory, CombinatorialData] @@ -598,11 +595,10 @@ public async Task FindPartialMethods(TestHost testHost, Composition composition) await TestAsync(testHost, composition, "partial class Goo { partial void Bar(); } partial class Goo { partial void Bar() { Console.Write(\"hello\"); } }", async w => { var expecteditem1 = new NavigateToItem("Bar", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null); - var expecteditems = new List { expecteditem1, expecteditem1 }; var items = await _aggregator.GetItemsAsync("Bar"); - VerifyNavigateToResultItems(expecteditems, items); + VerifyNavigateToResultItems([expecteditem1, expecteditem1], items); }); } @@ -612,46 +608,81 @@ public async Task FindPartialProperties(TestHost testHost, Composition compositi await TestAsync(testHost, composition, "partial class Goo { partial int Prop { get; set; } } partial class Goo { partial int Prop { get => 1; set { } } }", async w => { var expecteditem1 = new NavigateToItem("Prop", NavigateToItemKind.Property, "csharp", null, null, s_emptyExactPatternMatch, null); - var expecteditems = new List { expecteditem1, expecteditem1 }; var items = await _aggregator.GetItemsAsync("Prop"); - VerifyNavigateToResultItems(expecteditems, items); + VerifyNavigateToResultItems([expecteditem1, expecteditem1], items); }); } [Theory, CombinatorialData] - public async Task FindPartialMethodDefinitionOnly(TestHost testHost, Composition composition) + public async Task FindPartialEvents(TestHost testHost, Composition composition) { - await TestAsync( -testHost, composition, """ -partial class Goo -{ - partial void Bar(); -} -""", async w => + await TestAsync(testHost, composition, """ + partial class C + { + partial event System.Action E; + partial event System.Action E { add { } remove { } } + } + """, async w => { - var item = (await _aggregator.GetItemsAsync("Bar")).Single(); - VerifyNavigateToResultItem(item, "Bar", "[|Bar|]()", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPrivate, string.Format(FeaturesResources.in_0_1_2, "Goo", "test1.cs", "Test")); + var expecteditem1 = new NavigateToItem("E", NavigateToItemKind.Event, "csharp", null, null, s_emptyExactPatternMatch, null); + var items = await _aggregator.GetItemsAsync("E"); + + VerifyNavigateToResultItems([expecteditem1, expecteditem1], items); }); } + [Theory, CombinatorialData] + public async Task FindPartialConstructors(TestHost testHost, Composition composition) + { + await TestAsync(testHost, composition, """ + partial class C + { + public partial C(); + public partial C() { } + } + """, async w => + { + var expecteditem1 = new NavigateToItem("C", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null); + var items = (await _aggregator.GetItemsAsync("C")).Where(t => t.Kind == NavigateToItemKind.Method); + + VerifyNavigateToResultItems([expecteditem1, expecteditem1], items); + }); + } + + [Theory, CombinatorialData] + public async Task FindPartialMethodDefinitionOnly(TestHost testHost, Composition composition) + { + await TestAsync( + testHost, composition, """ + partial class Goo + { + partial void Bar(); + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("Bar")).Single(); + VerifyNavigateToResultItem(item, "Bar", "[|Bar|]()", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPrivate, string.Format(FeaturesResources.in_0_1_2, "Goo", "test1.cs", "Test")); + }); + } + [Theory, CombinatorialData] public async Task FindPartialMethodImplementationOnly(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -partial class Goo -{ - partial void Bar() - { - } -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("Bar")).Single(); - VerifyNavigateToResultItem(item, "Bar", "[|Bar|]()", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPrivate, string.Format(FeaturesResources.in_0_1_2, "Goo", "test1.cs", "Test")); - }); + testHost, composition, """ + partial class Goo + { + partial void Bar() + { + } + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("Bar")).Single(); + VerifyNavigateToResultItem(item, "Bar", "[|Bar|]()", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPrivate, string.Format(FeaturesResources.in_0_1_2, "Goo", "test1.cs", "Test")); + }); } [Theory, CombinatorialData] @@ -661,11 +692,10 @@ public async Task FindOverriddenMembers(TestHost testHost, Composition compositi await TestAsync(testHost, composition, program, async w => { var expecteditem1 = new NavigateToItem("Name", NavigateToItemKind.Property, "csharp", null, null, s_emptyExactPatternMatch, null); - var expecteditems = new List { expecteditem1, expecteditem1 }; var items = await _aggregator.GetItemsAsync("Name"); - VerifyNavigateToResultItems(expecteditems, items); + VerifyNavigateToResultItems([expecteditem1, expecteditem1], items); var item = items.ElementAt(1); var itemDisplay = item.DisplayFactory.CreateItemDisplay(item); @@ -687,15 +717,15 @@ await TestAsync(testHost, composition, program, async w => public async Task FindInterface(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -public interface IGoo -{ -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("IG")).Single(); - VerifyNavigateToResultItem(item, "IGoo", "[|IG|]oo", PatternMatchKind.Prefix, NavigateToItemKind.Interface, Glyph.InterfacePublic); - }); + testHost, composition, """ + public interface IGoo + { + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("IG")).Single(); + VerifyNavigateToResultItem(item, "IGoo", "[|IG|]oo", PatternMatchKind.Prefix, NavigateToItemKind.Interface, Glyph.InterfacePublic); + }); } [Theory, CombinatorialData] @@ -813,76 +843,73 @@ void Bar() public async Task FindDelegateInNamespace(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -namespace Goo -{ - delegate void DoStuff(); -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("DoStuff")).Single(x => x.Kind != "Method"); - VerifyNavigateToResultItem(item, "DoStuff", "[|DoStuff|]", PatternMatchKind.Exact, NavigateToItemKind.Delegate, Glyph.DelegateInternal); - }); + testHost, composition, """ + namespace Goo + { + delegate void DoStuff(); + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("DoStuff")).Single(x => x.Kind != "Method"); + VerifyNavigateToResultItem(item, "DoStuff", "[|DoStuff|]", PatternMatchKind.Exact, NavigateToItemKind.Delegate, Glyph.DelegateInternal); + }); } [Theory, CombinatorialData] public async Task FindLambdaExpression(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -using System; + testHost, composition, """ + using System; -class Goo -{ - Func sqr = x => x * x; -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("sqr")).Single(); - VerifyNavigateToResultItem(item, "sqr", "[|sqr|]", PatternMatchKind.Exact, NavigateToItemKind.Field, Glyph.FieldPrivate, string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); - }); + class Goo + { + Func sqr = x => x * x; + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("sqr")).Single(); + VerifyNavigateToResultItem(item, "sqr", "[|sqr|]", PatternMatchKind.Exact, NavigateToItemKind.Field, Glyph.FieldPrivate, string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); + }); } [Theory, CombinatorialData] public async Task FindArray(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -class Goo -{ - object[] itemArray; -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("itemArray")).Single(); - VerifyNavigateToResultItem(item, "itemArray", "[|itemArray|]", PatternMatchKind.Exact, NavigateToItemKind.Field, Glyph.FieldPrivate, string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); - }); + testHost, composition, """ + class Goo + { + object[] itemArray; + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("itemArray")).Single(); + VerifyNavigateToResultItem(item, "itemArray", "[|itemArray|]", PatternMatchKind.Exact, NavigateToItemKind.Field, Glyph.FieldPrivate, string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); + }); } [Theory, CombinatorialData] public async Task FindClassAndMethodWithSameName(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -class Goo -{ -} + testHost, composition, """ + class Goo + { + } -class Test -{ - void Goo() - { - } -} -""", async w => - { - var expectedItems = new List + class Test { - new NavigateToItem("Goo", NavigateToItemKind.Class, "csharp", "Goo", null, s_emptyExactPatternMatch, null), - new NavigateToItem("Goo", NavigateToItemKind.Method, "csharp", "Goo", null, s_emptyExactPatternMatch, null), - }; + void Goo() + { + } + } + """, async w => + { var items = await _aggregator.GetItemsAsync("Goo"); - VerifyNavigateToResultItems(expectedItems, items); + VerifyNavigateToResultItems([ + new("Goo", NavigateToItemKind.Class, "csharp", "Goo", null, s_emptyExactPatternMatch, null), + new("Goo", NavigateToItemKind.Method, "csharp", "Goo", null, s_emptyExactPatternMatch, null)], items); }); } @@ -890,80 +917,77 @@ void Goo() public async Task FindMethodNestedInGenericTypes(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -class A -{ - class B - { - struct C - { - void M() + testHost, composition, """ + class A { + class B + { + struct C + { + void M() + { + } + } + } } - } - } -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("M")).Single(); - VerifyNavigateToResultItem(item, "M", "[|M|]()", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPrivate, additionalInfo: string.Format(FeaturesResources.in_0_project_1, "A.B.C", "Test")); - }); + """, async w => + { + var item = (await _aggregator.GetItemsAsync("M")).Single(); + VerifyNavigateToResultItem(item, "M", "[|M|]()", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPrivate, additionalInfo: string.Format(FeaturesResources.in_0_project_1, "A.B.C", "Test")); + }); } [Theory, CombinatorialData] public async Task OrderingOfConstructorsAndTypes(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -class C1 -{ - C1(int i) - { - } -} + testHost, composition, """ + class C1 + { + C1(int i) + { + } + } -class C2 -{ - C2(float f) - { - } + class C2 + { + C2(float f) + { + } - static C2() - { - } -} -""", async w => - { - var expecteditems = new List - { - new NavigateToItem("C1", NavigateToItemKind.Class, "csharp", "C1", null, s_emptyPrefixPatternMatch, null), - new NavigateToItem("C1", NavigateToItemKind.Method, "csharp", "C1", null, s_emptyPrefixPatternMatch, null), - new NavigateToItem("C2", NavigateToItemKind.Class, "csharp", "C2", null, s_emptyPrefixPatternMatch, null), - new NavigateToItem("C2", NavigateToItemKind.Method, "csharp", "C2", null, s_emptyPrefixPatternMatch, null), // this is the static ctor - new NavigateToItem("C2", NavigateToItemKind.Method, "csharp", "C2", null, s_emptyPrefixPatternMatch, null), - }; - var items = (await _aggregator.GetItemsAsync("C")).ToList(); - items.Sort(CompareNavigateToItems); - VerifyNavigateToResultItems(expecteditems, items); - }); + static C2() + { + } + } + """, async w => + { + var items = (await _aggregator.GetItemsAsync("C")).ToList(); + items.Sort(CompareNavigateToItems); + VerifyNavigateToResultItems([ + new("C1", NavigateToItemKind.Class, "csharp", "C1", null, s_emptyPrefixPatternMatch, null), + new("C1", NavigateToItemKind.Method, "csharp", "C1", null, s_emptyPrefixPatternMatch, null), + new("C2", NavigateToItemKind.Class, "csharp", "C2", null, s_emptyPrefixPatternMatch, null), + new("C2", NavigateToItemKind.Method, "csharp", "C2", null, s_emptyPrefixPatternMatch, null), // this is the static ctor + new("C2", NavigateToItemKind.Method, "csharp", "C2", null, s_emptyPrefixPatternMatch, null)], items); + }); } [Theory, CombinatorialData] public async Task NavigateToMethodWithNullableParameter(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -class C -{ - void M(object? o) - { - } -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("M")).Single(); - VerifyNavigateToResultItem(item, "M", "[|M|](object?)", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPrivate); - }); + testHost, composition, """ + class C + { + void M(object? o) + { + } + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("M")).Single(); + VerifyNavigateToResultItem(item, "M", "[|M|](object?)", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPrivate); + }); } [Theory, CombinatorialData] @@ -971,23 +995,23 @@ public async Task StartStopSanity(TestHost testHost, Composition composition) { // Verify that multiple calls to start/stop and dispose don't blow up await TestAsync( -testHost, composition, """ -public class Goo -{ -} -""", async w => - { - // Do one set of queries - Assert.Single((await _aggregator.GetItemsAsync("Goo")), x => x.Kind != "Method"); - _provider.StopSearch(); + testHost, composition, """ + public class Goo + { + } + """, async w => + { + // Do one set of queries + Assert.Single((await _aggregator.GetItemsAsync("Goo")), x => x.Kind != "Method"); + _provider.StopSearch(); - // Do the same query again, make sure nothing was left over - Assert.Single((await _aggregator.GetItemsAsync("Goo")), x => x.Kind != "Method"); - _provider.StopSearch(); + // Do the same query again, make sure nothing was left over + Assert.Single((await _aggregator.GetItemsAsync("Goo")), x => x.Kind != "Method"); + _provider.StopSearch(); - // Dispose the provider - _provider.Dispose(); - }); + // Dispose the provider + _provider.Dispose(); + }); } [Theory, CombinatorialData] @@ -1026,13 +1050,10 @@ await TestAsync(testHost, composition, source, async w => var expecteditem1 = new NavigateToItem("get_keyword", NavigateToItemKind.Field, "csharp", null, null, s_emptyCamelCaseNonContiguousPrefixPatternMatch_NotCaseSensitive, null); var expecteditem2 = new NavigateToItem("get_key_word", NavigateToItemKind.Field, "csharp", null, null, s_emptyCamelCaseNonContiguousPrefixPatternMatch_NotCaseSensitive, null); var expecteditem3 = new NavigateToItem("GetKeyWord", NavigateToItemKind.Field, "csharp", null, null, s_emptyCamelCasePrefixPatternMatch, null); - var expecteditems = new List { expecteditem1, expecteditem2, expecteditem3 }; var items = await _aggregator.GetItemsAsync("GK"); - Assert.Equal(expecteditems.Count, items.Count()); - - VerifyNavigateToResultItems(expecteditems, items); + VerifyNavigateToResultItems([expecteditem1, expecteditem2, expecteditem3], items); }); } @@ -1044,11 +1065,10 @@ await TestAsync(testHost, composition, source, async w => { var expecteditem1 = new NavigateToItem("get_key_word", NavigateToItemKind.Field, "csharp", null, null, s_emptyCamelCaseNonContiguousPrefixPatternMatch_NotCaseSensitive, null); var expecteditem2 = new NavigateToItem("GetKeyWord", NavigateToItemKind.Field, "csharp", null, null, s_emptyCamelCaseExactPatternMatch, null); - var expecteditems = new List { expecteditem1, expecteditem2 }; var items = await _aggregator.GetItemsAsync("GKW"); - VerifyNavigateToResultItems(expecteditems, items); + VerifyNavigateToResultItems([expecteditem1, expecteditem2], items); }); } @@ -1060,11 +1080,10 @@ await TestAsync(testHost, composition, source, async w => { var expecteditem1 = new NavigateToItem("get_key_word", NavigateToItemKind.Field, "csharp", null, null, s_emptyCamelCaseSubstringPatternMatch_NotCaseSensitive, null); var expecteditem2 = new NavigateToItem("GetKeyWord", NavigateToItemKind.Field, "csharp", null, null, s_emptySubstringPatternMatch, null); - var expecteditems = new List { expecteditem1, expecteditem2 }; var items = await _aggregator.GetItemsAsync("K W"); - VerifyNavigateToResultItems(expecteditems, items); + VerifyNavigateToResultItems([expecteditem1, expecteditem2], items); }); } @@ -1096,17 +1115,13 @@ public async Task TermSplittingTest6(TestHost testHost, Composition composition) var source = "class SyllableBreaking {int GetKeyWord; int get_key_word; string get_keyword; int getkeyword; int wake;}"; await TestAsync(testHost, composition, source, async w => { - var expecteditems = new List - { - new NavigateToItem("getkeyword", NavigateToItemKind.Field, "csharp", null, null, s_emptyFuzzyPatternMatch, null), - new NavigateToItem("get_keyword", NavigateToItemKind.Field, "csharp", null, null, s_emptyFuzzyPatternMatch, null), - new NavigateToItem("get_key_word", NavigateToItemKind.Field, "csharp", null, null,s_emptySubstringPatternMatch, null), - new NavigateToItem("GetKeyWord", NavigateToItemKind.Field, "csharp", null, null, s_emptySubstringPatternMatch_NotCaseSensitive, null) - }; - var items = await _aggregator.GetItemsAsync("get word"); - VerifyNavigateToResultItems(expecteditems, items); + VerifyNavigateToResultItems([ + new("getkeyword", NavigateToItemKind.Field, "csharp", null, null, s_emptyFuzzyPatternMatch, null), + new("get_keyword", NavigateToItemKind.Field, "csharp", null, null, s_emptyFuzzyPatternMatch, null), + new("get_key_word", NavigateToItemKind.Field, "csharp", null, null,s_emptySubstringPatternMatch, null), + new("GetKeyWord", NavigateToItemKind.Field, "csharp", null, null, s_emptySubstringPatternMatch_NotCaseSensitive, null)], items); }); } @@ -1142,14 +1157,9 @@ void Goo() """; await TestAsync(testHost, composition, source, async w => { - var expecteditems = new List - { - new NavigateToItem("this", NavigateToItemKind.Property, "csharp", null, null, s_emptyExactPatternMatch, null), - }; - var items = await _aggregator.GetItemsAsync("this"); - VerifyNavigateToResultItems(expecteditems, items); + VerifyNavigateToResultItems([new("this", NavigateToItemKind.Property, "csharp", null, null, s_emptyExactPatternMatch, null)], items); }); } @@ -1159,14 +1169,9 @@ public async Task DottedPattern1(TestHost testHost, Composition composition) var source = "namespace Goo { namespace Bar { class Baz { void Quux() { } } } }"; await TestAsync(testHost, composition, source, async w => { - var expecteditems = new List - { - new NavigateToItem("Quux", NavigateToItemKind.Method, "csharp", null, null, s_emptyPrefixPatternMatch, null) - }; - var items = await _aggregator.GetItemsAsync("B.Q"); - VerifyNavigateToResultItems(expecteditems, items); + VerifyNavigateToResultItems([new("Quux", NavigateToItemKind.Method, "csharp", null, null, s_emptyPrefixPatternMatch, null)], items); }); } @@ -1176,13 +1181,9 @@ public async Task DottedPattern2(TestHost testHost, Composition composition) var source = "namespace Goo { namespace Bar { class Baz { void Quux() { } } } }"; await TestAsync(testHost, composition, source, async w => { - var expecteditems = new List - { - }; - var items = await _aggregator.GetItemsAsync("C.Q"); - VerifyNavigateToResultItems(expecteditems, items); + VerifyNavigateToResultItems([], items); }); } @@ -1192,14 +1193,9 @@ public async Task DottedPattern3(TestHost testHost, Composition composition) var source = "namespace Goo { namespace Bar { class Baz { void Quux() { } } } }"; await TestAsync(testHost, composition, source, async w => { - var expecteditems = new List - { - new NavigateToItem("Quux", NavigateToItemKind.Method, "csharp", null, null, s_emptyPrefixPatternMatch, null) - }; - var items = await _aggregator.GetItemsAsync("B.B.Q"); - VerifyNavigateToResultItems(expecteditems, items); + VerifyNavigateToResultItems([new("Quux", NavigateToItemKind.Method, "csharp", null, null, s_emptyPrefixPatternMatch, null)], items); }); } @@ -1209,14 +1205,9 @@ public async Task DottedPattern4(TestHost testHost, Composition composition) var source = "namespace Goo { namespace Bar { class Baz { void Quux() { } } } }"; await TestAsync(testHost, composition, source, async w => { - var expecteditems = new List - { - new NavigateToItem("Quux", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null) - }; - var items = await _aggregator.GetItemsAsync("Baz.Quux"); - VerifyNavigateToResultItems(expecteditems, items); + VerifyNavigateToResultItems([new("Quux", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null)], items); }); } @@ -1226,14 +1217,9 @@ public async Task DottedPattern5(TestHost testHost, Composition composition) var source = "namespace Goo { namespace Bar { class Baz { void Quux() { } } } }"; await TestAsync(testHost, composition, source, async w => { - var expecteditems = new List - { - new NavigateToItem("Quux", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null) - }; - var items = await _aggregator.GetItemsAsync("G.B.B.Quux"); - VerifyNavigateToResultItems(expecteditems, items); + VerifyNavigateToResultItems([new("Quux", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null)], items); }); } @@ -1243,13 +1229,9 @@ public async Task DottedPattern6(TestHost testHost, Composition composition) var source = "namespace Goo { namespace Bar { class Baz { void Quux() { } } } }"; await TestAsync(testHost, composition, source, async w => { - var expecteditems = new List - { - }; - var items = await _aggregator.GetItemsAsync("F.F.B.B.Quux"); - VerifyNavigateToResultItems(expecteditems, items); + VerifyNavigateToResultItems([], items); }); } @@ -1260,14 +1242,9 @@ public async Task DottedPattern7(TestHost testHost, Composition composition) var source = "namespace Goo { namespace Bar { class Baz { void Quux() { } } } }"; await TestAsync(testHost, composition, source, async w => { - var expecteditems = new List - { - new NavigateToItem("Quux", NavigateToItemKind.Method, "csharp", null, null, s_emptyPrefixPatternMatch, null) - }; - var items = await _aggregator.GetItemsAsync("Baz.Q"); - VerifyNavigateToResultItems(expecteditems, items); + VerifyNavigateToResultItems([new("Quux", NavigateToItemKind.Method, "csharp", null, null, s_emptyPrefixPatternMatch, null)], items); }); } @@ -1278,15 +1255,11 @@ public async Task DottedPatternMatchKind(TestHost testHost, Composition composit var source = "namespace System { class Console { void Write(string s) { } void WriteLine(string s) { } } }"; await TestAsync(testHost, composition, source, async w => { - var expecteditems = new List - { - new NavigateToItem("Write", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null), - new NavigateToItem("WriteLine", NavigateToItemKind.Method, "csharp", null, null, s_emptyPrefixPatternMatch, null) - }; - var items = await _aggregator.GetItemsAsync("Console.Write"); - VerifyNavigateToResultItems(expecteditems, items); + VerifyNavigateToResultItems([ + new("Write", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null), + new("WriteLine", NavigateToItemKind.Method, "csharp", null, null, s_emptyPrefixPatternMatch, null)], items); }); } @@ -1323,15 +1296,12 @@ public void VisibleMethod_Generated() { } _aggregator = new NavigateToTestAggregator(_provider); var items = await _aggregator.GetItemsAsync("VisibleMethod"); - var expectedItems = new List() - { - new NavigateToItem("VisibleMethod", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null), - new NavigateToItem("VisibleMethod_Generated", NavigateToItemKind.Method, "csharp", null, null, s_emptyPrefixPatternMatch, null) - }; // The pattern matcher should match 'VisibleMethod' to both 'VisibleMethod' and 'VisibleMethod_Not', except that // the _Not method is declared in a generated file. - VerifyNavigateToResultItems(expectedItems, items); + VerifyNavigateToResultItems([ + new("VisibleMethod", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null), + new("VisibleMethod_Generated", NavigateToItemKind.Method, "csharp", null, null, s_emptyPrefixPatternMatch, null)], items); } [Theory, WorkItem("https://github.com/dotnet/roslyn/pull/11474")] @@ -1339,18 +1309,18 @@ public void VisibleMethod_Generated() { } public async Task FindFuzzy1(TestHost testHost, Composition composition) { await TestAsync( -testHost, composition, """ -class C -{ - public void ToError() - { - } -} -""", async w => - { - var item = (await _aggregator.GetItemsAsync("ToEror")).Single(); - VerifyNavigateToResultItem(item, "ToError", "ToError()", PatternMatchKind.Fuzzy, NavigateToItemKind.Method, Glyph.MethodPublic); - }); + testHost, composition, """ + class C + { + public void ToError() + { + } + } + """, async w => + { + var item = (await _aggregator.GetItemsAsync("ToEror")).Single(); + VerifyNavigateToResultItem(item, "ToError", "ToError()", PatternMatchKind.Fuzzy, NavigateToItemKind.Method, Glyph.MethodPublic); + }); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/18843")] @@ -1749,13 +1719,10 @@ public void VisibleMethod() { } _aggregator = new NavigateToTestAggregator(_provider); var items = await _aggregator.GetItemsAsync("VisibleMethod"); - var expectedItems = new List() - { - new NavigateToItem("VisibleMethod", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null), - new NavigateToItem("VisibleMethod", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null) - }; - VerifyNavigateToResultItems(expectedItems, items); + VerifyNavigateToResultItems([ + new("VisibleMethod", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null), + new("VisibleMethod", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null)], items); Assert.Single(items, i => i.SecondarySort.StartsWith("0000") && IsFromFile(i, "File1.cs")); Assert.Single(items, i => i.SecondarySort.StartsWith("0001") && IsFromFile(i, "File2.cs")); @@ -1794,13 +1761,10 @@ public void VisibleMethod() { } _aggregator = new NavigateToTestAggregator(_provider); var items = await _aggregator.GetItemsAsync("VisibleMethod"); - var expectedItems = new List() - { - new NavigateToItem("VisibleMethod", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null), - new NavigateToItem("VisibleMethod", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null) - }; - VerifyNavigateToResultItems(expectedItems, items); + VerifyNavigateToResultItems([ + new("VisibleMethod", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null), + new("VisibleMethod", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null)], items); Assert.Single(items, i => i.SecondarySort.StartsWith("0000") && IsFromFile(i, "File1.cs")); Assert.Single(items, i => i.SecondarySort.StartsWith("0001") && IsFromFile(i, "File2.cs")); @@ -1839,13 +1803,10 @@ public void VisibleMethod() { } _aggregator = new NavigateToTestAggregator(_provider); var items = await _aggregator.GetItemsAsync("VisibleMethod"); - var expectedItems = new List() - { - new NavigateToItem("VisibleMethod", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null), - new NavigateToItem("VisibleMethod", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null) - }; - VerifyNavigateToResultItems(expectedItems, items); + VerifyNavigateToResultItems([ + new("VisibleMethod", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null), + new("VisibleMethod", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null)], items); Assert.Single(items, i => i.SecondarySort.StartsWith("0000") && IsFromFile(i, "File1.cs")); Assert.Single(items, i => i.SecondarySort.StartsWith("0002") && IsFromFile(i, "File2.cs")); @@ -1884,13 +1845,10 @@ public void VisibleMethod() { } _aggregator = new NavigateToTestAggregator(_provider); var items = await _aggregator.GetItemsAsync("VisibleMethod"); - var expectedItems = new List() - { - new NavigateToItem("VisibleMethod", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null), - new NavigateToItem("VisibleMethod", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null) - }; - VerifyNavigateToResultItems(expectedItems, items); + VerifyNavigateToResultItems([ + new("VisibleMethod", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null), + new("VisibleMethod", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null)], items); Assert.Single(items, i => i.SecondarySort.StartsWith("0000") && IsFromFile(i, "File1.cs")); Assert.Single(items, i => i.SecondarySort.StartsWith("0002") && IsFromFile(i, "File2.cs")); @@ -1929,17 +1887,93 @@ public void VisibleMethod() { } _aggregator = new NavigateToTestAggregator(_provider); var items = await _aggregator.GetItemsAsync("VisibleMethod"); - var expectedItems = new List() - { - new NavigateToItem("VisibleMethod", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null), - new NavigateToItem("VisibleMethod", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null) - }; - VerifyNavigateToResultItems(expectedItems, items); + VerifyNavigateToResultItems([ + new("VisibleMethod", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null), + new("VisibleMethod", NavigateToItemKind.Method, "csharp", null, null, s_emptyExactPatternMatch, null)], items); Assert.Single(items, i => i.SecondarySort.StartsWith("0000") && IsFromFile(i, "File1.cs")); Assert.Single(items, i => i.SecondarySort.StartsWith("0003") && IsFromFile(i, "File2.cs")); }); } + + [Theory, CombinatorialData] + public async Task FindModernExtensionMethod1(TestHost testHost, Composition composition) + { + var content = XElement.Parse(""" + + + + static class Class + { + extension(string s) + { + public void Goo() + { + } + } + } + + + + """); + await TestAsync(testHost, composition, content, async w => + { + var item = (await _aggregator.GetItemsAsync("Goo")).Single(); + VerifyNavigateToResultItem(item, "Goo", "[|Goo|]()", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPublic); + }); + } + + [Theory, CombinatorialData] + public async Task FindModernExtensionMethod2(TestHost testHost, Composition composition) + { + var content = XElement.Parse(""" + + + + static class Class + { + extension(string s) + { + public static void Goo() + { + } + } + } + + + + """); + await TestAsync(testHost, composition, content, async w => + { + var item = (await _aggregator.GetItemsAsync("Goo")).Single(); + VerifyNavigateToResultItem(item, "Goo", "[|Goo|]()", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPublic); + }); + } + + [Theory, CombinatorialData] + public async Task FindModernExtensionProperty(TestHost testHost, Composition composition) + { + var content = XElement.Parse(""" + + + + static class Class + { + extension(string s) + { + public int Goo => 0; + } + } + + + + """); + await TestAsync(testHost, composition, content, async w => + { + var item = (await _aggregator.GetItemsAsync("Goo")).Single(); + VerifyNavigateToResultItem(item, "Goo", "[|Goo|]", PatternMatchKind.Exact, NavigateToItemKind.Property, Glyph.PropertyPublic); + }); + } } #pragma warning restore CS0618 // MatchKind is obsolete diff --git a/src/EditorFeatures/CSharpTest/OnTheFlyDocs/OnTheFlyDocsUtilitiesTests.cs b/src/EditorFeatures/CSharpTest/OnTheFlyDocs/OnTheFlyDocsUtilitiesTests.cs new file mode 100644 index 0000000000000..d52c79cb9d1c3 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/OnTheFlyDocs/OnTheFlyDocsUtilitiesTests.cs @@ -0,0 +1,130 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Linq; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp.QuickInfo; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.OnTheFlyDocs; + +[UseExportProvider] +[Trait(Traits.Feature, Traits.Features.OnTheFlyDocs)] +public sealed class OnTheFlyDocsUtilitiesTests +{ + [Fact] + public async Task TestAdditionalContextNoContext() + { + var testCode = """ + class C + { + void AddMethod(int a, int b) + { + return a + b; + } + } + """; + + using var workspace = EditorTestWorkspace.CreateCSharp(testCode); + var solution = workspace.CurrentSolution; + var document = solution.Projects.First().Documents.First(); + + var syntaxTree = await document.GetSyntaxTreeAsync(); + var semanticModel = await document.GetSemanticModelAsync(); + + var methodDeclaration = syntaxTree!.GetRoot() + .DescendantNodes() + .OfType() + .First(); + + var methodSymbol = semanticModel!.GetDeclaredSymbol(methodDeclaration); + + var result = OnTheFlyDocsUtilities.GetAdditionalOnTheFlyDocsContext(solution, methodSymbol!); + Assert.True(result.All(item => item == null)); + } + + [Fact] + public async Task TestAdditionalContextWithTypeParameters() + { + var testCode = """ + class C + { + int AddMethod(A a, int b) + { + return a.x + b; + } + } + + class A + { + public int x; + } + """; + + using var workspace = EditorTestWorkspace.CreateCSharp(testCode); + var solution = workspace.CurrentSolution; + var document = solution.Projects.First().Documents.First(); + + var syntaxTree = await document.GetSyntaxTreeAsync(); + var semanticModel = await document.GetSemanticModelAsync(); + + var methodDeclaration = syntaxTree!.GetRoot() + .DescendantNodes() + .OfType() + .First(); + + var methodSymbol = semanticModel!.GetDeclaredSymbol(methodDeclaration); + + var result = OnTheFlyDocsUtilities.GetAdditionalOnTheFlyDocsContext(solution, methodSymbol!); + Assert.NotNull(result.First()); + Assert.Null(result.Last()); + } + + [Fact] + public async Task TestAdditionalContextWithTypeArguments() + { + var testCode = """ + class C + { + void Method(T t, U u) where T : class where U : struct + { + } + + void CallMethod() + { + Method(new CustomClass(), new CustomStruct()); + } + } + + class CustomClass + { + public string Name { get; set; } + } + + struct CustomStruct + { + public int Value { get; set; } + } + """; + + using var workspace = EditorTestWorkspace.CreateCSharp(testCode); + var solution = workspace.CurrentSolution; + var document = solution.Projects.First().Documents.First(); + + var syntaxTree = await document.GetSyntaxTreeAsync(); + var semanticModel = await document.GetSemanticModelAsync(); + + var methodInvocation = syntaxTree!.GetRoot() + .DescendantNodes() + .OfType() + .First(); + + var methodSymbol = semanticModel!.GetSymbolInfo(methodInvocation).Symbol; + + var result = OnTheFlyDocsUtilities.GetAdditionalOnTheFlyDocsContext(solution, methodSymbol!); + Assert.True(result.All(item => item is not null)); + } +} diff --git a/src/EditorFeatures/CSharpTest/PdbSourceDocument/AbstractPdbSourceDocumentTests.cs b/src/EditorFeatures/CSharpTest/PdbSourceDocument/AbstractPdbSourceDocumentTests.cs index 151b4737bdb03..0f20492573709 100644 --- a/src/EditorFeatures/CSharpTest/PdbSourceDocument/AbstractPdbSourceDocumentTests.cs +++ b/src/EditorFeatures/CSharpTest/PdbSourceDocument/AbstractPdbSourceDocumentTests.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.IO; using System.Linq; using System.Text; diff --git a/src/EditorFeatures/CSharpTest/PdbSourceDocument/NullResultMetadataAsSourceFileProvider.cs b/src/EditorFeatures/CSharpTest/PdbSourceDocument/NullResultMetadataAsSourceFileProvider.cs index ddc805beef25f..2f6bdcc2eae60 100644 --- a/src/EditorFeatures/CSharpTest/PdbSourceDocument/NullResultMetadataAsSourceFileProvider.cs +++ b/src/EditorFeatures/CSharpTest/PdbSourceDocument/NullResultMetadataAsSourceFileProvider.cs @@ -7,7 +7,6 @@ using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.MetadataAsSource; using Microsoft.CodeAnalysis.PdbSourceDocument; @@ -26,7 +25,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.PdbSourceDocument; internal class NullResultMetadataAsSourceFileProvider : IMetadataAsSourceFileProvider { // Represents a null result - public static MetadataAsSourceFile NullResult = new("", null, null, null); + public static MetadataAsSourceFile NullResult = new("", null!, null!, null!); [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] diff --git a/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentLoaderServiceTests.cs b/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentLoaderServiceTests.cs index d4efd62b990da..7500179017f49 100644 --- a/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentLoaderServiceTests.cs +++ b/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentLoaderServiceTests.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Immutable; using System.IO; using System.Security.Cryptography; using System.Text; diff --git a/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs b/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs index f4c7b4efab924..c6ab0fa35d695 100644 --- a/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs +++ b/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs @@ -7998,6 +7998,44 @@ void N() NullabilityAnalysis(string.Format(FeaturesResources._0_is_not_null_here, "s"))); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/77219")] + public async Task NullableBackingFieldThatIsMaybeNull() + { + await TestWithOptionsAsync(TestOptions.RegularPreview, + """ + #nullable enable + + class X + { + string? P + { + get => $$field; + } + } + """, + MainDescription($"({FeaturesResources.field}) string? X.P.field"), + NullabilityAnalysis(string.Format(FeaturesResources._0_may_be_null_here, "P.field"))); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/77219")] + public async Task NullableBackingFieldThatIsNotNull() + { + await TestWithOptionsAsync(TestOptions.RegularPreview, + """ + #nullable enable + + class X + { + string P + { + get => $$field; + } = "a"; + } + """, + MainDescription($"({FeaturesResources.field}) string X.P.field"), + NullabilityAnalysis(string.Format(FeaturesResources._0_is_not_null_here, "P.field"))); + } + [Fact] public async Task NullablePropertyThatIsMaybeNull() { @@ -10663,4 +10701,164 @@ void M(IMyInterface i) """, MainDescription($"({CSharpFeaturesResources.awaitable}) ValueTask IAsyncDisposable.DisposeAsync()")); } + + [Fact] + public async Task TestModernExtension1() + { + await TestWithOptionsAsync( + CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Preview), + """ + using System; + using System.Threading.Tasks; + + static class Extensions + { + extension(string s) + { + public void Goo() { } + } + } + + class C + { + void M(string s) + { + s.$$Goo(); + } + } + """, + MainDescription($"void Extensions.extension(string).Goo()")); + } + + [Fact] + public async Task TestModernExtension2() + { + await TestWithOptionsAsync( + CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Preview), + """ + using System; + using System.Threading.Tasks; + + static class Extensions + { + extension(string s) + { + public void Goo() { } + public void Goo(int i) { } + } + } + + class C + { + void M(string s) + { + s.$$Goo(); + } + } + """, + MainDescription($"void Extensions.extension(string).Goo() (+ 1 {FeaturesResources.overload})")); + } + + [Fact] + public async Task TestModernExtension3() + { + await TestWithOptionsAsync( + CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Preview), + """ + using System; + using System.Threading.Tasks; + + static class Extensions + { + extension(string s) + { + public void Goo() { } + public void Goo(int i) { } + } + } + + class C + { + void M(string s) + { + s.$$Goo(0); + } + } + """, + MainDescription($"void Extensions.extension(string).Goo(int i) (+ 1 {FeaturesResources.overload})")); + } + + [Fact] + public async Task TestModernExtension4() + { + await TestWithOptionsAsync( + CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Preview), + """ + using System; + using System.Threading.Tasks; + + static class Extensions + { + extension(string s) + { + public int Prop => 0; + } + } + + class C + { + void M(string s) + { + var v = s.$$Prop; + } + } + """, + MainDescription($$"""int Extensions.extension(string).Prop { get; }""")); + } + + [Fact] + public async Task TestModernExtension5() + { + await TestWithOptionsAsync( + CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Preview), + """ + using System; + using System.Threading.Tasks; + + static class Extensions + { + extension(string s) + { + public void Goo() + { + Console.WriteLine($$s); + } + } + } + """, + MainDescription($"({FeaturesResources.parameter}) string s")); + } + + [Fact] + public async Task TestModernExtension6() + { + await TestWithOptionsAsync( + CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Preview), + """ + using System; + using System.Threading.Tasks; + + static class Extensions + { + $$extension(string s) + { + public void Goo() + { + Console.WriteLine(s); + } + } + } + """, + MainDescription($"Extensions.extension(System.String)")); + } } diff --git a/src/EditorFeatures/CSharpTest/RawStringLiteral/RawStringLiteralCommandHandlerTests.cs b/src/EditorFeatures/CSharpTest/RawStringLiteral/RawStringLiteralCommandHandlerTests.cs index c91609f2d7a65..03ddbbb1a3364 100644 --- a/src/EditorFeatures/CSharpTest/RawStringLiteral/RawStringLiteralCommandHandlerTests.cs +++ b/src/EditorFeatures/CSharpTest/RawStringLiteral/RawStringLiteralCommandHandlerTests.cs @@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.RawStringLiteral; [UseExportProvider] -public class RawStringLiteralCommandHandlerTests +public sealed class RawStringLiteralCommandHandlerTests { internal sealed class RawStringLiteralTestState : AbstractCommandHandlerTestState { @@ -520,6 +520,48 @@ public void TestReturnWithinEndQuotesInMultilineRawString() testState.SendReturn(handled: false); } + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/76773")] + public void TestReturnPriorToStartingQuotes1() + { + using var testState = RawStringLiteralTestState.CreateTestState( + """" + var v = Goo($$""" + bar); + """ + """"); + + // Should not handle this as we're not inside the raw string. + testState.SendReturn(handled: false); + } + + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/76773")] + public void TestReturnPriorToStartingQuotes2() + { + using var testState = RawStringLiteralTestState.CreateTestState( + """" + var v = Goo("$$"" + bar); + """ + """"); + + // Should not handle this as we're not inside the raw string. + testState.SendReturn(handled: false); + } + + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/76773")] + public void TestReturnPriorToStartingQuotes3() + { + using var testState = RawStringLiteralTestState.CreateTestState( + """" + var v = Goo(""$$" + bar); + """ + """"); + + // Should not handle this as we're not inside the raw string. + testState.SendReturn(handled: false); + } + #endregion #region generate initial empty raw string @@ -574,6 +616,27 @@ public void TestGenerateWithInterpolatedString_TwoDollarSigns() """", withSpansOnly: true); } + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/77724")] + public void TestGenerateWithInterpolatedString_TwoDollarSigns_InLocalFunction() + { + using var testState = RawStringLiteralTestState.CreateTestState( + """ + void M() + { + var v = $$""[||] + } + """, withSpansOnly: true); + + testState.SendTypeChar('"'); + testState.AssertCodeIs( + """" + void M() + { + var v = $$"""[||]""" + } + """", withSpansOnly: true); + } + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/66538")] public void TestGenerateWithInterpolatedString_TwoDollarSigns_FourthDoubleQuote() { diff --git a/src/EditorFeatures/CSharpTest/Rename/CSharpInlineRenameServiceTests.cs b/src/EditorFeatures/CSharpTest/Rename/CSharpInlineRenameServiceTests.cs index b1d9a20568333..351a3d29e7509 100644 --- a/src/EditorFeatures/CSharpTest/Rename/CSharpInlineRenameServiceTests.cs +++ b/src/EditorFeatures/CSharpTest/Rename/CSharpInlineRenameServiceTests.cs @@ -5,9 +5,7 @@ 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; diff --git a/src/EditorFeatures/CSharpTest/SignatureHelp/AbstractCSharpSignatureHelpProviderTests.cs b/src/EditorFeatures/CSharpTest/SignatureHelp/AbstractCSharpSignatureHelpProviderTests.cs index 125b4b6e3baed..dd566e4d83910 100644 --- a/src/EditorFeatures/CSharpTest/SignatureHelp/AbstractCSharpSignatureHelpProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/SignatureHelp/AbstractCSharpSignatureHelpProviderTests.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 Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Editor.UnitTests.SignatureHelp; diff --git a/src/EditorFeatures/CSharpTest/SignatureHelp/AttributeSignatureHelpProviderTests.cs b/src/EditorFeatures/CSharpTest/SignatureHelp/AttributeSignatureHelpProviderTests.cs index bcdde03575248..4fae40dec048c 100644 --- a/src/EditorFeatures/CSharpTest/SignatureHelp/AttributeSignatureHelpProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/SignatureHelp/AttributeSignatureHelpProviderTests.cs @@ -7,7 +7,6 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.SignatureHelp; using Microsoft.CodeAnalysis.Editor.UnitTests.SignatureHelp; using Microsoft.CodeAnalysis.Test.Utilities; diff --git a/src/EditorFeatures/CSharpTest/SignatureHelp/InitializerExpressionSignatureHelpProviderTests.cs b/src/EditorFeatures/CSharpTest/SignatureHelp/InitializerExpressionSignatureHelpProviderTests.cs index 39350549bccfe..b153378e84216 100644 --- a/src/EditorFeatures/CSharpTest/SignatureHelp/InitializerExpressionSignatureHelpProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/SignatureHelp/InitializerExpressionSignatureHelpProviderTests.cs @@ -2,21 +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. -#nullable disable - using System; -using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.SignatureHelp; -using Microsoft.CodeAnalysis.Editor.UnitTests.SignatureHelp; using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.SignatureHelp; [Trait(Traits.Feature, Traits.Features.SignatureHelp)] -public class InitializerExpressionSignatureHelpProviderTests : AbstractCSharpSignatureHelpProviderTests +public sealed class InitializerExpressionSignatureHelpProviderTests : AbstractCSharpSignatureHelpProviderTests { internal override Type GetSignatureHelpProviderType() => typeof(InitializerExpressionSignatureHelpProvider); @@ -36,12 +32,7 @@ void Goo() } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("void List.Add(int item)", currentParameterIndex: 0) - }; - - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [new("void List.Add(int item)", currentParameterIndex: 0)]); } [Fact] @@ -59,12 +50,7 @@ void Goo() } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("void Dictionary.Add(int key, string value)", currentParameterIndex: 0) - }; - - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [new("void Dictionary.Add(int key, string value)", currentParameterIndex: 0)]); } [Fact] @@ -82,12 +68,7 @@ void Goo() } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("void Dictionary.Add(int key, string value)", currentParameterIndex: 1) - }; - - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [new("void Dictionary.Add(int key, string value)", currentParameterIndex: 1)]); } [Fact] @@ -110,12 +91,7 @@ void Goo() } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("void Dictionary.Add(int key, string value)", currentParameterIndex: 0) - }; - - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [new("void Dictionary.Add(int key, string value)", currentParameterIndex: 0)]); } [Fact] @@ -136,12 +112,7 @@ void Goo() new Bar { D = { { $$ """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("void Dictionary.Add(int key, string value)", currentParameterIndex: 0) - }; - - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [new("void Dictionary.Add(int key, string value)", currentParameterIndex: 0)]); } [Fact] @@ -164,14 +135,10 @@ void Goo() new Bar { { $$ """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("void Bar.Add(int i)", currentParameterIndex: 0), - new SignatureHelpTestItem("void Bar.Add(int i, string s)", currentParameterIndex: 0, isSelected: true), - new SignatureHelpTestItem("void Bar.Add(int i, string s, bool b)", currentParameterIndex: 0) - }; - - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [ + new("void Bar.Add(int i)", currentParameterIndex: 0), + new("void Bar.Add(int i, string s)", currentParameterIndex: 0, isSelected: true), + new("void Bar.Add(int i, string s, bool b)", currentParameterIndex: 0)]); } [Fact] @@ -194,9 +161,7 @@ void Goo() new Bar { { $$ """; - var expectedOrderedItems = new List(); - - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, expectedOrderedItemsOrNull: []); } [Fact] @@ -223,13 +188,9 @@ void Goo() new Bar { { $$ """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem($"({CSharpFeaturesResources.extension}) void Bar.Add(int i)", currentParameterIndex: 0), - new SignatureHelpTestItem($"({CSharpFeaturesResources.extension}) void Bar.Add(int i, string s)", currentParameterIndex: 0, isSelected: true), - new SignatureHelpTestItem($"({CSharpFeaturesResources.extension}) void Bar.Add(int i, string s, bool b)", currentParameterIndex: 0) - }; - - await TestAsync(markup, expectedOrderedItems, sourceCodeKind: SourceCodeKind.Regular); + await TestAsync(markup, [ + new($"({CSharpFeaturesResources.extension}) void Bar.Add(int i)", currentParameterIndex: 0), + new($"({CSharpFeaturesResources.extension}) void Bar.Add(int i, string s)", currentParameterIndex: 0, isSelected: true), + new($"({CSharpFeaturesResources.extension}) void Bar.Add(int i, string s, bool b)", currentParameterIndex: 0)], sourceCodeKind: SourceCodeKind.Regular); } } diff --git a/src/EditorFeatures/CSharpTest/SignatureHelp/ObjectCreationExpressionSignatureHelpProviderTests.cs b/src/EditorFeatures/CSharpTest/SignatureHelp/ObjectCreationExpressionSignatureHelpProviderTests.cs index 6c3e92d69569e..7d61c2498d611 100644 --- a/src/EditorFeatures/CSharpTest/SignatureHelp/ObjectCreationExpressionSignatureHelpProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/SignatureHelp/ObjectCreationExpressionSignatureHelpProviderTests.cs @@ -16,7 +16,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.SignatureHelp; [Trait(Traits.Feature, Traits.Features.SignatureHelp)] -public class ObjectCreationExpressionSignatureHelpProviderTests : AbstractCSharpSignatureHelpProviderTests +public sealed class ObjectCreationExpressionSignatureHelpProviderTests : AbstractCSharpSignatureHelpProviderTests { internal override Type GetSignatureHelpProviderType() => typeof(ObjectCreationExpressionSignatureHelpProvider); @@ -36,12 +36,7 @@ void goo() } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("C()", string.Empty, null, currentParameterIndex: 0) - }; - - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [new("C()", string.Empty, null, currentParameterIndex: 0)]); } [Fact] @@ -63,12 +58,7 @@ void M() """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("C()", string.Empty, null, currentParameterIndex: 0) - }; - - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [new("C()", string.Empty, null, currentParameterIndex: 0)]); } [Fact] @@ -89,11 +79,7 @@ void Goo() } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("C()", "Summary for C", null, currentParameterIndex: 0) - }; - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [new("C()", "Summary for C", null, currentParameterIndex: 0)]); } [Fact] @@ -111,12 +97,7 @@ void Goo() } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("C(int a, int b)", string.Empty, string.Empty, currentParameterIndex: 0) - }; - - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [new("C(int a, int b)", string.Empty, string.Empty, currentParameterIndex: 0)]); } [Fact] @@ -134,12 +115,7 @@ void M() } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("C(int a, int b)", string.Empty, string.Empty, currentParameterIndex: 0) - }; - - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [new("C(int a, int b)", string.Empty, string.Empty, currentParameterIndex: 0)]); } [Fact] @@ -162,12 +138,7 @@ void Goo() } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("C(int a, int b)", "Summary for C", "Param a", currentParameterIndex: 0) - }; - - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [new("C(int a, int b)", "Summary for C", "Param a", currentParameterIndex: 0)]); } [Fact] @@ -184,12 +155,8 @@ void Goo() } } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("C(int a, int b)", string.Empty, string.Empty, currentParameterIndex: 1) - }; - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [new("C(int a, int b)", string.Empty, string.Empty, currentParameterIndex: 1)]); } [Fact] @@ -211,12 +178,8 @@ void Goo() } } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("C(int a, int b)", "Summary for C", "Param b", currentParameterIndex: 1) - }; - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [new("C(int a, int b)", "Summary for C", "Param b", currentParameterIndex: 1)]); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/25830")] @@ -234,13 +197,10 @@ void M() D(int i) => throw null; } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("D(int i)", currentParameterIndex: 0, isSelected: true), - new SignatureHelpTestItem("D(string i)", currentParameterIndex: 0), - }; - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [ + new("D(int i)", currentParameterIndex: 0, isSelected: true), + new("D(string i)", currentParameterIndex: 0),]); } [Fact] @@ -258,13 +218,10 @@ void M() D(int i) => throw null; } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("D(int i)", currentParameterIndex: 0, isSelected: true), - new SignatureHelpTestItem("D(string i)", currentParameterIndex: 0), - }; - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [ + new("D(int i)", currentParameterIndex: 0, isSelected: true), + new("D(string i)", currentParameterIndex: 0),]); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/25830")] @@ -282,13 +239,10 @@ void M() D(int i) => throw null; } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("D(int i)", currentParameterIndex: 0), - new SignatureHelpTestItem("D(string i)", currentParameterIndex: 0, isSelected: true), - }; - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [ + new("D(int i)", currentParameterIndex: 0), + new("D(string i)", currentParameterIndex: 0, isSelected: true),]); } [Fact] @@ -306,13 +260,10 @@ void M() D(int i) => throw null; } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("D(int i)", currentParameterIndex: 0), - new SignatureHelpTestItem("D(string i)", currentParameterIndex: 0, isSelected: true), - }; - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [ + new("D(int i)", currentParameterIndex: 0), + new("D(string i)", currentParameterIndex: 0, isSelected: true),]); } [Fact] @@ -328,12 +279,7 @@ void goo() } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("C()", string.Empty, null, currentParameterIndex: 0) - }; - - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [new("C()", string.Empty, null, currentParameterIndex: 0)]); } [Fact] @@ -351,12 +297,7 @@ void Goo() } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("C(int a, int b)", string.Empty, string.Empty, currentParameterIndex: 0) - }; - - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [new("C(int a, int b)", string.Empty, string.Empty, currentParameterIndex: 0)]); } [Fact] @@ -374,12 +315,7 @@ void Goo() } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("C(int a, int b)", string.Empty, string.Empty, currentParameterIndex: 1) - }; - - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [new("C(int a, int b)", string.Empty, string.Empty, currentParameterIndex: 1)]); } [Fact] @@ -397,12 +333,7 @@ void goo() } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("Action(void (int, int) target)", string.Empty, string.Empty, currentParameterIndex: 0, isSelected: true) - }; - - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [new("Action(void (int, int) target)", string.Empty, string.Empty, currentParameterIndex: 0, isSelected: true)]); } #endregion @@ -446,12 +377,7 @@ void goo() } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("C()", string.Empty, null, currentParameterIndex: 0) - }; - - await TestAsync(markup, expectedOrderedItems, usePreviousCharAsTrigger: true); + await TestAsync(markup, [new("C()", string.Empty, null, currentParameterIndex: 0)], usePreviousCharAsTrigger: true); } [Fact] @@ -471,12 +397,7 @@ void goo() } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("C(int a, string b)", string.Empty, string.Empty, currentParameterIndex: 1) - }; - - await TestAsync(markup, expectedOrderedItems, usePreviousCharAsTrigger: true); + await TestAsync(markup, [new("C(int a, string b)", string.Empty, string.Empty, currentParameterIndex: 1)], usePreviousCharAsTrigger: true); } [Fact] @@ -496,8 +417,7 @@ void goo() } """; - var expectedOrderedItems = new List(); - await TestAsync(markup, expectedOrderedItems, usePreviousCharAsTrigger: true); + await TestAsync(markup, expectedOrderedItemsOrNull: [], usePreviousCharAsTrigger: true); } [Fact] @@ -537,15 +457,16 @@ public Goo(int x) var expectedOrderedItems = new List { - new SignatureHelpTestItem("Goo(int x)", string.Empty, string.Empty, currentParameterIndex: 0) + new("Goo(int x)", string.Empty, string.Empty, currentParameterIndex: 0) }; - await TestSignatureHelpInEditorBrowsableContextsAsync(markup: markup, - referencedCode: referencedCode, - expectedOrderedItemsMetadataReference: expectedOrderedItems, - expectedOrderedItemsSameSolution: expectedOrderedItems, - sourceLanguage: LanguageNames.CSharp, - referencedLanguage: LanguageNames.CSharp); + await TestSignatureHelpInEditorBrowsableContextsAsync( + markup: markup, + referencedCode: referencedCode, + expectedOrderedItemsMetadataReference: expectedOrderedItems, + expectedOrderedItemsSameSolution: expectedOrderedItems, + sourceLanguage: LanguageNames.CSharp, + referencedLanguage: LanguageNames.CSharp); } [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] @@ -571,17 +492,13 @@ public Goo(int x) } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("Goo(int x)", string.Empty, string.Empty, currentParameterIndex: 0) - }; - - await TestSignatureHelpInEditorBrowsableContextsAsync(markup: markup, - referencedCode: referencedCode, - expectedOrderedItemsMetadataReference: new List(), - expectedOrderedItemsSameSolution: expectedOrderedItems, - sourceLanguage: LanguageNames.CSharp, - referencedLanguage: LanguageNames.CSharp); + await TestSignatureHelpInEditorBrowsableContextsAsync( + markup: markup, + referencedCode: referencedCode, + expectedOrderedItemsMetadataReference: [], + expectedOrderedItemsSameSolution: [new("Goo(int x)", string.Empty, string.Empty, currentParameterIndex: 0)], + sourceLanguage: LanguageNames.CSharp, + referencedLanguage: LanguageNames.CSharp); } [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] @@ -608,16 +525,17 @@ public Goo() """; var expectedOrderedItems = new List { - new SignatureHelpTestItem("Goo()", string.Empty, null, currentParameterIndex: 0) + new("Goo()", string.Empty, null, currentParameterIndex: 0) }; - await TestSignatureHelpInEditorBrowsableContextsAsync(markup: markup, - referencedCode: referencedCode, - expectedOrderedItemsMetadataReference: new List(), - expectedOrderedItemsSameSolution: expectedOrderedItems, - sourceLanguage: LanguageNames.CSharp, - referencedLanguage: LanguageNames.CSharp, - hideAdvancedMembers: true); + await TestSignatureHelpInEditorBrowsableContextsAsync( + markup: markup, + referencedCode: referencedCode, + expectedOrderedItemsMetadataReference: new List(), + expectedOrderedItemsSameSolution: expectedOrderedItems, + sourceLanguage: LanguageNames.CSharp, + referencedLanguage: LanguageNames.CSharp, + hideAdvancedMembers: true); await TestSignatureHelpInEditorBrowsableContextsAsync(markup: markup, referencedCode: referencedCode, @@ -654,23 +572,16 @@ public Goo(long y) } } """; - var expectedOrderedItemsMetadataReference = new List - { - new SignatureHelpTestItem("Goo(int x)", string.Empty, string.Empty, currentParameterIndex: 0) - }; - - var expectedOrderedItemsSameSolution = new List - { - new SignatureHelpTestItem("Goo(int x)", string.Empty, string.Empty, currentParameterIndex: 0), - new SignatureHelpTestItem("Goo(long y)", string.Empty, string.Empty, currentParameterIndex: 0) - }; - await TestSignatureHelpInEditorBrowsableContextsAsync(markup: markup, - referencedCode: referencedCode, - expectedOrderedItemsMetadataReference: expectedOrderedItemsMetadataReference, - expectedOrderedItemsSameSolution: expectedOrderedItemsSameSolution, - sourceLanguage: LanguageNames.CSharp, - referencedLanguage: LanguageNames.CSharp); + await TestSignatureHelpInEditorBrowsableContextsAsync( + markup: markup, + referencedCode: referencedCode, + expectedOrderedItemsMetadataReference: [new("Goo(int x)", string.Empty, string.Empty, currentParameterIndex: 0)], + expectedOrderedItemsSameSolution: [ + new("Goo(int x)", string.Empty, string.Empty, currentParameterIndex: 0), + new("Goo(long y)", string.Empty, string.Empty, currentParameterIndex: 0)], + sourceLanguage: LanguageNames.CSharp, + referencedLanguage: LanguageNames.CSharp); } #endregion @@ -702,8 +613,9 @@ 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, [expectedDescription], false); + + await VerifyItemWithReferenceWorkerAsync( + markup, [new($"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)], false); } [Fact] @@ -740,8 +652,8 @@ 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, [expectedDescription], false); + await VerifyItemWithReferenceWorkerAsync( + markup, [new($"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)], false); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1067933")] @@ -785,12 +697,7 @@ public C M() } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("C(object o)", currentParameterIndex: 0) - }; - - await TestAsync(markup, expectedOrderedItems, usePreviousCharAsTrigger: true); + await TestAsync(markup, [new("C(object o)", currentParameterIndex: 0)], usePreviousCharAsTrigger: true); } [Fact] @@ -808,12 +715,7 @@ public C M() } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("C(object o)", currentParameterIndex: 0) - }; - - await TestAsync(markup, expectedOrderedItems, usePreviousCharAsTrigger: true); + await TestAsync(markup, [new("C(object o)", currentParameterIndex: 0)], usePreviousCharAsTrigger: true); } [Fact] @@ -831,12 +733,7 @@ public C M() } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("C(object o)", currentParameterIndex: 0) - }; - - await TestAsync(markup, expectedOrderedItems, usePreviousCharAsTrigger: true); + await TestAsync(markup, [new("C(object o)", currentParameterIndex: 0)], usePreviousCharAsTrigger: true); } [Fact] @@ -854,12 +751,7 @@ public C M() } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("C(object o)", currentParameterIndex: 0) - }; - - await TestAsync(markup, expectedOrderedItems, usePreviousCharAsTrigger: true); + await TestAsync(markup, [new("C(object o)", currentParameterIndex: 0)], usePreviousCharAsTrigger: true); } [Theory] @@ -892,13 +784,10 @@ static void M() """; var index = 0; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("Program(int i, string s)", currentParameterIndex: expectedParameterIndex, isSelected: expecteSelectedIndex == index++), - new SignatureHelpTestItem("Program(string s, string s2)", currentParameterIndex: expectedParameterIndex, isSelected: expecteSelectedIndex == index++), - }; - await TestAsync(markup.Replace("ARGUMENTS", arguments), expectedOrderedItems); + await TestAsync(markup.Replace("ARGUMENTS", arguments), [ + new("Program(int i, string s)", currentParameterIndex: expectedParameterIndex, isSelected: expecteSelectedIndex == index++), + new("Program(string s, string s2)", currentParameterIndex: expectedParameterIndex, isSelected: expecteSelectedIndex == index++),]); } [Theory] diff --git a/src/EditorFeatures/CSharpTest/SignatureHelp/PrimaryConstructorBaseTypeSignatureHelpProviderTests.cs b/src/EditorFeatures/CSharpTest/SignatureHelp/PrimaryConstructorBaseTypeSignatureHelpProviderTests.cs index bf0b98ffba5e3..2a6cebd5a3577 100644 --- a/src/EditorFeatures/CSharpTest/SignatureHelp/PrimaryConstructorBaseTypeSignatureHelpProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/SignatureHelp/PrimaryConstructorBaseTypeSignatureHelpProviderTests.cs @@ -16,7 +16,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.SignatureHelp; [Trait(Traits.Feature, Traits.Features.SignatureHelp)] -public class PrimaryConstructorBaseTypeSignatureHelpProviderTests : AbstractCSharpSignatureHelpProviderTests +public sealed class PrimaryConstructorBaseTypeSignatureHelpProviderTests : AbstractCSharpSignatureHelpProviderTests { internal override Type GetSignatureHelpProviderType() => typeof(PrimaryConstructorBaseTypeSignatureHelpProvider); @@ -32,13 +32,9 @@ private Base(string ignored) : this(1, 2) { } record Derived(int Other) : [|Base($$1|]); """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("Base(Base original)", string.Empty, null, currentParameterIndex: 0), - new SignatureHelpTestItem("Base(int Identifier)", string.Empty, null, currentParameterIndex: 0, isSelected: true) - }; - - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [ + new("Base(Base original)", string.Empty, null, currentParameterIndex: 0), + new("Base(int Identifier)", string.Empty, null, currentParameterIndex: 0, isSelected: true)]); } [Fact] @@ -52,12 +48,7 @@ private Base(string ignored) : this(1, 2) { } class Derived(int Other) : [|Base($$1|]); """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("Base(int Identifier)", string.Empty, null, currentParameterIndex: 0, isSelected: true) - }; - - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [new("Base(int Identifier)", string.Empty, null, currentParameterIndex: 0, isSelected: true)]); } [Fact] @@ -71,14 +62,10 @@ protected Base(string name) : this(1, 2) { } record Derived(int Other) : [|Base(1, $$2|]); """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("Base(Base original)", string.Empty, null, currentParameterIndex: 1), - new SignatureHelpTestItem("Base(string name)", string.Empty, null, currentParameterIndex: 1), - new SignatureHelpTestItem("Base(int Identifier1, int Identifier2)", string.Empty, null, currentParameterIndex: 1, isSelected: true) - }; - - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [ + new("Base(Base original)", string.Empty, null, currentParameterIndex: 1), + new("Base(string name)", string.Empty, null, currentParameterIndex: 1), + new("Base(int Identifier1, int Identifier2)", string.Empty, null, currentParameterIndex: 1, isSelected: true)]); } [Fact] @@ -92,13 +79,9 @@ protected Base(string name) : this(1, 2) { } class Derived(int Other) : [|Base(1, $$2|]); """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("Base(string name)", string.Empty, null, currentParameterIndex: 1), - new SignatureHelpTestItem("Base(int Identifier1, int Identifier2)", string.Empty, null, currentParameterIndex: 1, isSelected: true) - }; - - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [ + new("Base(string name)", string.Empty, null, currentParameterIndex: 1), + new("Base(int Identifier1, int Identifier2)", string.Empty, null, currentParameterIndex: 1, isSelected: true)]); } [Fact] @@ -113,14 +96,10 @@ protected Base(string name) : this(1, 2) { } record Derived(int Other) : [|Base(1, $$2|]); """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("Base(Base original)", string.Empty, null, currentParameterIndex: 1), - new SignatureHelpTestItem("Base(string name)", "Summary for constructor", null, currentParameterIndex: 1), - new SignatureHelpTestItem("Base(int Identifier1, int Identifier2)", string.Empty, null, currentParameterIndex: 1, isSelected: true) - }; - - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [ + new("Base(Base original)", string.Empty, null, currentParameterIndex: 1), + new("Base(string name)", "Summary for constructor", null, currentParameterIndex: 1), + new("Base(int Identifier1, int Identifier2)", string.Empty, null, currentParameterIndex: 1, isSelected: true)]); } [Fact] @@ -135,13 +114,9 @@ protected Base(string name) : this(1, 2) { } class Derived(int Other) : [|Base(1, $$2|]); """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("Base(string name)", "Summary for constructor", null, currentParameterIndex: 1), - new SignatureHelpTestItem("Base(int Identifier1, int Identifier2)", string.Empty, null, currentParameterIndex: 1, isSelected: true) - }; - - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [ + new("Base(string name)", "Summary for constructor", null, currentParameterIndex: 1), + new("Base(int Identifier1, int Identifier2)", string.Empty, null, currentParameterIndex: 1, isSelected: true)]); } [Fact] @@ -157,14 +132,10 @@ protected Base(string name) : this(1, 2) { } record Derived(int Other) : [|Base($$1, 2|]); """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("Base(Base original)", string.Empty, null, currentParameterIndex: 0), - new SignatureHelpTestItem("Base(string name)", "Summary for constructor", "Param name", currentParameterIndex: 0), - new SignatureHelpTestItem("Base(int Identifier1, int Identifier2)", string.Empty, null, currentParameterIndex: 0, isSelected: true) - }; - - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [ + new("Base(Base original)", string.Empty, null, currentParameterIndex: 0), + new("Base(string name)", "Summary for constructor", "Param name", currentParameterIndex: 0), + new("Base(int Identifier1, int Identifier2)", string.Empty, null, currentParameterIndex: 0, isSelected: true)]); } [Fact] @@ -180,13 +151,9 @@ protected Base(string name) : this(1, 2) { } class Derived(int Other) : [|Base($$1, 2|]); """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("Base(string name)", "Summary for constructor", "Param name", currentParameterIndex: 0), - new SignatureHelpTestItem("Base(int Identifier1, int Identifier2)", string.Empty, null, currentParameterIndex: 0, isSelected: true) - }; - - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [ + new("Base(string name)", "Summary for constructor", "Param name", currentParameterIndex: 0), + new("Base(int Identifier1, int Identifier2)", string.Empty, null, currentParameterIndex: 0, isSelected: true)]); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/70106")] @@ -199,11 +166,6 @@ abstract class Base(int Identifier) class Derived(int Other) : [|Base($$1|]); """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("Base(int Identifier)", string.Empty, null, currentParameterIndex: 0, isSelected: true) - }; - - await TestAsync(markup, expectedOrderedItems); + await TestAsync(markup, [new("Base(int Identifier)", string.Empty, null, currentParameterIndex: 0, isSelected: true)]); } } diff --git a/src/EditorFeatures/CSharpTest/SignatureHelp/TupleConstructionSignatureHelpProviderTests.cs b/src/EditorFeatures/CSharpTest/SignatureHelp/TupleConstructionSignatureHelpProviderTests.cs index 7233e31edad96..a17595a6e197b 100644 --- a/src/EditorFeatures/CSharpTest/SignatureHelp/TupleConstructionSignatureHelpProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/SignatureHelp/TupleConstructionSignatureHelpProviderTests.cs @@ -2,13 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; -using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp.SignatureHelp; -using Microsoft.CodeAnalysis.Editor.UnitTests.SignatureHelp; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; @@ -16,7 +12,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.SignatureHelp; [Trait(Traits.Feature, Traits.Features.SignatureHelp)] -public class TupleConstructionSignatureHelpProviderTests : AbstractCSharpSignatureHelpProviderTests +public sealed class TupleConstructionSignatureHelpProviderTests : AbstractCSharpSignatureHelpProviderTests { internal override Type GetSignatureHelpProviderType() => typeof(TupleConstructionSignatureHelpProvider); @@ -31,12 +27,7 @@ class C |]} """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("(int, int)", currentParameterIndex: 0, parameterDocumentation: "") - }; - - await TestAsync(markup, expectedOrderedItems, usePreviousCharAsTrigger: true); + await TestAsync(markup, [new("(int, int)", currentParameterIndex: 0, parameterDocumentation: "")], usePreviousCharAsTrigger: true); } [Fact] @@ -49,12 +40,7 @@ class C |]} """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("(string?, string)", currentParameterIndex: 0) - }; - - await TestAsync(markup, expectedOrderedItems, usePreviousCharAsTrigger: true); + await TestAsync(markup, [new("(string?, string)", currentParameterIndex: 0)], usePreviousCharAsTrigger: true); } [Fact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/655607")] @@ -70,12 +56,7 @@ void M() } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("(object a, object)", currentParameterIndex: 0) - }; - - await TestAsync(markup, expectedOrderedItems, usePreviousCharAsTrigger: true); + await TestAsync(markup, [new("(object a, object)", currentParameterIndex: 0)], usePreviousCharAsTrigger: true); } [Fact] @@ -88,12 +69,7 @@ class C } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("(int, int)", currentParameterIndex: 0) - }; - - await TestAsync(markup, expectedOrderedItems, usePreviousCharAsTrigger: true); + await TestAsync(markup, [new("(int, int)", currentParameterIndex: 0)], usePreviousCharAsTrigger: true); } [Fact] @@ -106,12 +82,7 @@ class C |]} """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("(int, int)", currentParameterIndex: 1, parameterDocumentation: "") - }; - - await TestAsync(markup, expectedOrderedItems, usePreviousCharAsTrigger: true); + await TestAsync(markup, [new("(int, int)", currentParameterIndex: 1, parameterDocumentation: "")], usePreviousCharAsTrigger: true); } [Fact] @@ -124,12 +95,7 @@ class C } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("(int, int)", currentParameterIndex: 1) - }; - - await TestAsync(markup, expectedOrderedItems, usePreviousCharAsTrigger: true); + await TestAsync(markup, [new("(int, int)", currentParameterIndex: 1)], usePreviousCharAsTrigger: true); } [Fact] @@ -142,15 +108,11 @@ class C |]} """; - var expectedOrderedItems = new List - { + await TestAsync(markup, [ // currentParameterIndex only considers the position in the argument list // and not names, hence passing 0 even though the controller will highlight // "int b" in the actual display - new SignatureHelpTestItem("(int a, int b)", currentParameterIndex: 0) - }; - - await TestAsync(markup, expectedOrderedItems); + new("(int a, int b)", currentParameterIndex: 0)]); } [Fact(Skip = "https://github.com/dotnet/roslyn/issues/14277")] @@ -163,12 +125,7 @@ class C |]} """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("(int b, int c)", currentParameterIndex: 0) - }; - - await TestAsync(markup, expectedOrderedItems, usePreviousCharAsTrigger: true); + await TestAsync(markup, [new("(int b, int c)", currentParameterIndex: 0)], usePreviousCharAsTrigger: true); } [Fact] @@ -181,12 +138,7 @@ class C |]} """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("(int, object)", currentParameterIndex: 1) - }; - - await TestAsync(markup, expectedOrderedItems, usePreviousCharAsTrigger: true); + await TestAsync(markup, [new("(int, object)", currentParameterIndex: 1)], usePreviousCharAsTrigger: true); } [Fact] @@ -199,12 +151,7 @@ class C |]} """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("(int, object)", currentParameterIndex: 1) - }; - - await TestAsync(markup, expectedOrderedItems, usePreviousCharAsTrigger: true); + await TestAsync(markup, [new("(int, object)", currentParameterIndex: 1)], usePreviousCharAsTrigger: true); } [Fact] @@ -217,12 +164,7 @@ class C |]} """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("(int, object)", currentParameterIndex: 1) - }; - - await TestAsync(markup, expectedOrderedItems, usePreviousCharAsTrigger: true); + await TestAsync(markup, [new("(int, object)", currentParameterIndex: 1)], usePreviousCharAsTrigger: true); } [Fact] @@ -235,12 +177,7 @@ class C |]} """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("(object, object)", currentParameterIndex: 0) - }; - - await TestAsync(markup, expectedOrderedItems, usePreviousCharAsTrigger: true); + await TestAsync(markup, [new("(object, object)", currentParameterIndex: 0)], usePreviousCharAsTrigger: true); } [Fact] @@ -259,13 +196,9 @@ static void Do1((string, string) s) { } } """; - var expectedOrderedItems = new List - { - new SignatureHelpTestItem("(int, int)", currentParameterIndex: 0), - new SignatureHelpTestItem("(string, string)", currentParameterIndex: 0) - }; - - await TestAsync(markup, expectedOrderedItems, usePreviousCharAsTrigger: true); + await TestAsync(markup, [ + new("(int, int)", currentParameterIndex: 0), + new("(string, string)", currentParameterIndex: 0)], usePreviousCharAsTrigger: true); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14793")] @@ -295,7 +228,7 @@ void goo() """; - var expectedDescription = new SignatureHelpTestItem($"(int, string)", currentParameterIndex: 0); - await VerifyItemWithReferenceWorkerAsync(markup, [expectedDescription], false); + await VerifyItemWithReferenceWorkerAsync( + markup, [new($"(int, string)", currentParameterIndex: 0)], hideAdvancedMembers: false); } } diff --git a/src/EditorFeatures/CSharpTest/Structure/CommentStructureTests.cs b/src/EditorFeatures/CSharpTest/Structure/CommentStructureTests.cs index 9071be18f4622..8607f9f65d2ac 100644 --- a/src/EditorFeatures/CSharpTest/Structure/CommentStructureTests.cs +++ b/src/EditorFeatures/CSharpTest/Structure/CommentStructureTests.cs @@ -9,7 +9,6 @@ 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; using Microsoft.CodeAnalysis.Test.Utilities; @@ -47,7 +46,7 @@ internal override async Task> GetBlockSpansWorkerAsync return CreateCommentBlockSpan(token.TrailingTrivia); } - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } [Fact] diff --git a/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyCompilationsTests.cs b/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyCompilationsTests.cs index a7882ee2881ef..5cb0f22646bef 100644 --- a/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyCompilationsTests.cs +++ b/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyCompilationsTests.cs @@ -192,6 +192,64 @@ public partial class C1 Assert.Equal(implementation, ResolveSymbol(implementation, comp, SymbolKeyComparison.None)); } + [Fact] + public void ExtendedPartialEventDefinitionAndImplementationResolveCorrectly() + { + var src = """ + using System; + namespace NS + { + public partial class C1 + { + public partial event System.Action Event; + public partial event System.Action Event { add { } remove { } } + } + } + """; + + var comp = (Compilation)CreateCompilation(src, assemblyName: "Test"); + + var ns = comp.SourceModule.GlobalNamespace.GetMembers("NS").Single() as INamespaceSymbol; + var type = ns.GetTypeMembers("C1").FirstOrDefault(); + var definition = type.GetMembers("Event").First() as IEventSymbol; + var implementation = definition.PartialImplementationPart; + Assert.NotNull(implementation); + Assert.NotEqual(implementation, definition); + + // Assert that both the definition and implementation resolve back to themselves + Assert.Equal(definition, ResolveSymbol(definition, comp, SymbolKeyComparison.None)); + Assert.Equal(implementation, ResolveSymbol(implementation, comp, SymbolKeyComparison.None)); + } + + [Fact] + public void ExtendedPartialConstructorDefinitionAndImplementationResolveCorrectly() + { + var src = """ + using System; + namespace NS + { + public partial class C1 + { + public partial C1(); + public partial C1() { } + } + } + """; + + var comp = (Compilation)CreateCompilation(src, assemblyName: "Test"); + + var ns = comp.SourceModule.GlobalNamespace.GetMembers("NS").Single() as INamespaceSymbol; + var type = ns.GetTypeMembers("C1").FirstOrDefault(); + var definition = type.GetMembers(".ctor").First() as IMethodSymbol; + var implementation = definition.PartialImplementationPart; + Assert.NotNull(implementation); + Assert.NotEqual(implementation, definition); + + // Assert that both the definition and implementation resolve back to themselves + Assert.Equal(definition, ResolveSymbol(definition, comp, SymbolKeyComparison.None)); + Assert.Equal(implementation, ResolveSymbol(implementation, comp, SymbolKeyComparison.None)); + } + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/916341")] public void ExplicitIndexerImplementationResolvesCorrectly() { diff --git a/src/EditorFeatures/CSharpTest/TextStructureNavigation/TextStructureNavigatorTests.cs b/src/EditorFeatures/CSharpTest/TextStructureNavigation/TextStructureNavigatorTests.cs index 89159b427b39f..0d4299d121c1b 100644 --- a/src/EditorFeatures/CSharpTest/TextStructureNavigation/TextStructureNavigatorTests.cs +++ b/src/EditorFeatures/CSharpTest/TextStructureNavigation/TextStructureNavigatorTests.cs @@ -561,4 +561,13 @@ public void TestClampStringLiteral(string content) { AssertExtent(content); } + + [WpfTheory, WorkItem("https://github.com/dotnet/roslyn/issues/77401")] + [InlineData(@"{|Significant:""|}$$")] + [InlineData(@"{|Significant:""""""|}$$")] + [InlineData(@"""""""{|Significant:u8|}$$")] + public void TestClampStringLiteral_Invalid(string content) + { + AssertExtent(content); + } } diff --git a/src/EditorFeatures/CSharpTest/Workspaces/WorkspaceTests_EditorFeatures.cs b/src/EditorFeatures/CSharpTest/Workspaces/WorkspaceTests_EditorFeatures.cs index 27f3d213052c5..3b32e03b5cdd4 100644 --- a/src/EditorFeatures/CSharpTest/Workspaces/WorkspaceTests_EditorFeatures.cs +++ b/src/EditorFeatures/CSharpTest/Workspaces/WorkspaceTests_EditorFeatures.cs @@ -13,7 +13,6 @@ using System.Xml.Linq; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editor.Test; using Microsoft.CodeAnalysis.Editor.UnitTests; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host; @@ -479,7 +478,11 @@ internal async Task TestGetCompilationOnCrossLanguageDependentProjectChanged( var solutionX = workspace.CurrentSolution; var document1 = new EditorTestHostDocument(@"public class C { }"); - var project1 = new EditorTestHostProject(workspace, document1, name: "project1"); + var project1 = new EditorTestHostProject(workspace, document1, name: "project1", + compilationOptions: solutionX.Services + .GetRequiredLanguageService(LanguageNames.CSharp) + .GetDefaultCompilationOptions() + .WithOutputKind(OutputKind.DynamicallyLinkedLibrary)); var document2 = new EditorTestHostDocument(""" Public Class D @@ -533,7 +536,11 @@ public async Task TestDependentSemanticVersionChangesWhenNotOriginallyAccessed() var solutionX = workspace.CurrentSolution; var document1 = new EditorTestHostDocument(@"public class C { }"); - var project1 = new EditorTestHostProject(workspace, document1, name: "project1"); + var project1 = new EditorTestHostProject(workspace, document1, name: "project1", + compilationOptions: solutionX.Services + .GetRequiredLanguageService(LanguageNames.CSharp) + .GetDefaultCompilationOptions() + .WithOutputKind(OutputKind.DynamicallyLinkedLibrary)); var document2 = new EditorTestHostDocument(""" Public Class D @@ -601,7 +608,11 @@ internal async Task TestGetCompilationOnCrossLanguageDependentProjectChangedInPr var solutionX = workspace.CurrentSolution; var document1 = new EditorTestHostDocument(@"public class C { }"); - var project1 = new EditorTestHostProject(workspace, document1, name: "project1"); + var project1 = new EditorTestHostProject(workspace, document1, name: "project1", + compilationOptions: solutionX.Services + .GetRequiredLanguageService(LanguageNames.CSharp) + .GetDefaultCompilationOptions() + .WithOutputKind(OutputKind.DynamicallyLinkedLibrary)); var document2 = new EditorTestHostDocument(""" Public Class D diff --git a/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/Json/CSharpJsonParserTests_NstTests.cs b/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/Json/CSharpJsonParserTests_NstTests.cs index ff8ddadcd534f..d6af20208ea5e 100644 --- a/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/Json/CSharpJsonParserTests_NstTests.cs +++ b/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/Json/CSharpJsonParserTests_NstTests.cs @@ -16,7 +16,7 @@ private void TestNST( { var (_, tree, allChars) = JustParseTree(stringText, JsonOptions.Strict, conversionFailureOk: false); Assert.NotNull(tree); - Roslyn.Utilities.Contract.ThrowIfNull(tree); + Contract.ThrowIfNull(tree); var actualTree = TreeToText(tree!).Replace("\"", "\"\""); Assert.Equal(expected.Replace("\"", "\"\""), actualTree); diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/AbstractKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/AbstractKeywordRecommenderTests.cs index cf2736a2be179..a8ae804f62cfb 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/AbstractKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/AbstractKeywordRecommenderTests.cs @@ -484,5 +484,20 @@ class C { override $$ """); } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyAbsenceAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/AsyncKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/AsyncKeywordRecommenderTests.cs index 3637abd1754a3..c1536f02862e7 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/AsyncKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/AsyncKeywordRecommenderTests.cs @@ -401,5 +401,20 @@ public async Task TestLocalFunction7(bool topLevelStatement) await VerifyKeywordAsync(AddInsideMethod( @"static $$", topLevelStatement: topLevelStatement), options: CSharp9ParseOptions); } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/BoolKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/BoolKeywordRecommenderTests.cs index a78023a3bf842..a8bf7bf1b504a 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/BoolKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/BoolKeywordRecommenderTests.cs @@ -329,9 +329,9 @@ public async Task TestNotAfterPartial() => await VerifyAbsenceAsync(@"partial $$"); [Fact] - public async Task TestNotAfterNestedPartial() + public async Task TestAfterNestedPartial() { - await VerifyAbsenceAsync( + await VerifyKeywordAsync( """ class C { partial $$ @@ -1106,5 +1106,20 @@ IEnumerable M() => [string.Empty, .. ($$ } #endregion + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/ByteKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/ByteKeywordRecommenderTests.cs index 76d43d6604003..654eaee844801 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/ByteKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/ByteKeywordRecommenderTests.cs @@ -350,9 +350,9 @@ public async Task TestNotAfterPartial() => await VerifyAbsenceAsync(@"partial $$"); [Fact] - public async Task TestNotAfterNestedPartial() + public async Task TestAfterNestedPartial() { - await VerifyAbsenceAsync( + await VerifyKeywordAsync( """ class C { partial $$ @@ -1106,5 +1106,20 @@ IEnumerable M() => [string.Empty, .. ($$ } #endregion + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/CharKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/CharKeywordRecommenderTests.cs index 828bcdaa9fd06..c88dd40be804f 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/CharKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/CharKeywordRecommenderTests.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations { - public class CharKeywordRecommenderTests : KeywordRecommenderTests + public sealed class CharKeywordRecommenderTests : KeywordRecommenderTests { [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] public async Task TestAtRoot_Interactive() @@ -349,9 +349,9 @@ public async Task TestNotAfterPartial() => await VerifyAbsenceAsync(@"partial $$"); [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public async Task TestNotAfterNestedPartial() + public async Task TestAfterNestedPartial() { - await VerifyAbsenceAsync( + await VerifyKeywordAsync( """ class C { partial $$ @@ -1171,5 +1171,20 @@ IEnumerable M() => [string.Empty, .. ($$ } #endregion + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/ClassKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/ClassKeywordRecommenderTests.cs index f58aa3947595c..43ceea5a54489 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/ClassKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/ClassKeywordRecommenderTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations { [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public class ClassKeywordRecommenderTests : KeywordRecommenderTests + public sealed class ClassKeywordRecommenderTests : KeywordRecommenderTests { [Fact] public async Task TestAtRoot_Interactive() @@ -543,5 +543,22 @@ public async Task TestAfterAttributeFileScopedNamespace() await VerifyKeywordAsync( @"namespace NS; [Attr] $$"); } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, + CSharpNextParseOptions, + CSharpNextScriptParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/ConstKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/ConstKeywordRecommenderTests.cs index e596353323c25..af4e9d57f3121 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/ConstKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/ConstKeywordRecommenderTests.cs @@ -448,5 +448,22 @@ int Goo { $$ """); } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyAbsenceAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, + CSharpNextParseOptions, + CSharpNextScriptParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/DecimalKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/DecimalKeywordRecommenderTests.cs index fc4ed190203ec..460788997a7f9 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/DecimalKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/DecimalKeywordRecommenderTests.cs @@ -350,9 +350,9 @@ public async Task TestNotAfterPartial() => await VerifyAbsenceAsync(@"partial $$"); [Fact] - public async Task TestNotAfterNestedPartial() + public async Task TestAfterNestedPartial() { - await VerifyAbsenceAsync( + await VerifyKeywordAsync( """ class C { partial $$ @@ -1123,5 +1123,20 @@ IEnumerable M() => [string.Empty, .. ($$ } #endregion + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/DelegateKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/DelegateKeywordRecommenderTests.cs index c5dd8fa1b50d0..3664642f6ee3b 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/DelegateKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/DelegateKeywordRecommenderTests.cs @@ -641,4 +641,19 @@ IEnumerable M() => [string.Empty, .. ($$ } #endregion + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/DoubleKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/DoubleKeywordRecommenderTests.cs index 2283d0e9fc4ce..0d2b9307d8f92 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/DoubleKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/DoubleKeywordRecommenderTests.cs @@ -350,9 +350,9 @@ public async Task TestNotAfterPartial() => await VerifyAbsenceAsync(@"partial $$"); [Fact] - public async Task TestNotAfterNestedPartial() + public async Task TestAfterNestedPartial() { - await VerifyAbsenceAsync( + await VerifyKeywordAsync( """ class C { partial $$ @@ -1109,5 +1109,20 @@ IEnumerable M() => [string.Empty, .. ($$ } #endregion + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/DynamicKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/DynamicKeywordRecommenderTests.cs index 585d0ab2710fc..6398091cc46fc 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/DynamicKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/DynamicKeywordRecommenderTests.cs @@ -347,9 +347,9 @@ public async Task TestNotAfterPartial() => await VerifyAbsenceAsync(@"partial $$"); [Fact] - public async Task TestNotAfterNestedPartial() + public async Task TestAfterNestedPartial() { - await VerifyAbsenceAsync( + await VerifyKeywordAsync( """ class C { partial $$ @@ -771,5 +771,20 @@ class C delegate*$$ """); } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/EnumKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/EnumKeywordRecommenderTests.cs index 7b325f7c6d165..9dad53fbcf0d5 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/EnumKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/EnumKeywordRecommenderTests.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations { [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public class EnumKeywordRecommenderTests : KeywordRecommenderTests + public sealed class EnumKeywordRecommenderTests : KeywordRecommenderTests { [Fact] public async Task TestAtRoot_Interactive() @@ -329,5 +329,22 @@ public async Task TestNotAfterAbstractPublic() [Fact] public async Task TestNotAfterEnum() => await VerifyAbsenceAsync(@"enum $$"); + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, + CSharpNextParseOptions, + CSharpNextScriptParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/EventKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/EventKeywordRecommenderTests.cs index 501f19e0b3f66..9c1cd1d91adb4 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/EventKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/EventKeywordRecommenderTests.cs @@ -318,6 +318,17 @@ record C(int i, int j) { """, absent: false, options: TestOptions.RegularPreview); } + [Theory, CombinatorialData] + public async Task TestPartialMember( + [CombinatorialValues("class", "record", "struct", "interface")] string kind) + { + await VerifyKeywordAsync( + $$""" + {{kind}} C { + partial $$ + """); + } + [Fact] public async Task TestNotAfterPartial() => await VerifyAbsenceAsync(@"partial $$"); @@ -644,4 +655,21 @@ await VerifyAbsenceAsync( record R([$$] int i) { } """); } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, + CSharpNextParseOptions, + CSharpNextScriptParseOptions); + } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/ExtensionKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/ExtensionKeywordRecommenderTests.cs new file mode 100644 index 0000000000000..c8fe8ee566b3e --- /dev/null +++ b/src/EditorFeatures/CSharpTest2/Recommendations/ExtensionKeywordRecommenderTests.cs @@ -0,0 +1,153 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations; + +[Trait(Traits.Feature, Traits.Features.KeywordRecommending)] +public sealed class ExtensionKeywordRecommenderTests : KeywordRecommenderTests +{ + private static readonly CSharpParseOptions s_options = CSharpNextParseOptions; + + [Fact] + public async Task NotInRoot() + { + await VerifyAbsenceAsync(@"$$", s_options); + } + + [Fact] + public async Task NotInNormalClass() + { + await VerifyAbsenceAsync(""" + class C + { + $$ + } + """, s_options); + } + + [Fact] + public async Task InStaticClass() + { + await VerifyKeywordAsync(""" + static class C + { + $$ + } + """, s_options); + } + + [Fact] + public async Task NotAfterAccessibilityInStaticClass() + { + await VerifyAbsenceAsync(""" + static class C + { + public $$ + } + """, s_options); + } + + [Fact] + public async Task NotAfterModifierInStaticClass() + { + await VerifyAbsenceAsync(""" + static class C + { + unsafe $$ + } + """, s_options); + } + + [Fact] + public async Task NotAfterPartialInStaticClass() + { + await VerifyAbsenceAsync(""" + static class C + { + partial $$ + } + """, s_options); + } + + [Fact] + public async Task NotInStaticStructClass() + { + await VerifyAbsenceAsync(""" + static struct C + { + $$ + } + """, s_options); + } + + [Fact] + public async Task AfterMethodInStaticClass() + { + await VerifyKeywordAsync(""" + static class C + { + void M() { } + $$ + } + """, s_options); + } + + [Fact] + public async Task AfterClassInStaticClass() + { + await VerifyKeywordAsync(""" + static class C + { + class M { } + $$ + } + """, s_options); + } + + [Fact] + public async Task AfterExtensionInStaticClass() + { + await VerifyKeywordAsync(""" + static class C + { + extension E() { } + $$ + } + """, s_options); + } + + [Fact] + public async Task NotInClassInStaticClass() + { + await VerifyAbsenceAsync(""" + static class C + { + class C + { + $$ + } + } + """, s_options); + } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyAbsenceAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } +} diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/ExternKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/ExternKeywordRecommenderTests.cs index 926fdf0a23e98..ef398572684aa 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/ExternKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/ExternKeywordRecommenderTests.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations { [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public class ExternKeywordRecommenderTests : KeywordRecommenderTests + public sealed class ExternKeywordRecommenderTests : KeywordRecommenderTests { [Fact] public async Task TestAtRoot() @@ -346,5 +346,20 @@ class C { public $$ """); } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/FloatKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/FloatKeywordRecommenderTests.cs index 958a92bfc8de6..14e2f4cbe4ae7 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/FloatKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/FloatKeywordRecommenderTests.cs @@ -350,9 +350,9 @@ public async Task TestNotAfterPartial() => await VerifyAbsenceAsync(@"partial $$"); [Fact] - public async Task TestNotAfterNestedPartial() + public async Task TestAfterNestedPartial() { - await VerifyAbsenceAsync( + await VerifyKeywordAsync( """ class C { partial $$ @@ -966,5 +966,20 @@ await VerifyKeywordAsync( ref readonly $$ }}"); } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/GlobalKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/GlobalKeywordRecommenderTests.cs index e7d0eb3bff1e5..d1e09081c850e 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/GlobalKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/GlobalKeywordRecommenderTests.cs @@ -528,5 +528,20 @@ IEnumerable M() => [string.Empty, .. ($$ } #endregion + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/IntKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/IntKeywordRecommenderTests.cs index b4ae9655b78bc..be447e34064ac 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/IntKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/IntKeywordRecommenderTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations { [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public class IntKeywordRecommenderTests : KeywordRecommenderTests + public sealed class IntKeywordRecommenderTests : KeywordRecommenderTests { [Fact] public async Task TestAtRoot_Interactive() @@ -305,9 +305,9 @@ public async Task TestNotAfterPartial() => await VerifyAbsenceAsync(@"partial $$"); [Fact] - public async Task TestNotAfterNestedPartial() + public async Task TestAfterNestedPartial() { - await VerifyAbsenceAsync( + await VerifyKeywordAsync( """ class C { partial $$ @@ -1215,5 +1215,20 @@ IEnumerable M() => [string.Empty, .. ($$ } #endregion + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/InterfaceKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/InterfaceKeywordRecommenderTests.cs index 18dfcc00466d7..84300fcddf54b 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/InterfaceKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/InterfaceKeywordRecommenderTests.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations { [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public class InterfaceKeywordRecommenderTests : KeywordRecommenderTests + public sealed class InterfaceKeywordRecommenderTests : KeywordRecommenderTests { [Fact] public async Task TestAtRoot_Interactive() @@ -333,5 +333,22 @@ public async Task TestNotAfterStatic() [Fact] public async Task TestNotAfterInterface() => await VerifyAbsenceAsync(@"interface $$"); + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, + CSharpNextParseOptions, + CSharpNextScriptParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/InternalKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/InternalKeywordRecommenderTests.cs index dadf68e402dbc..36dc05656eb51 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/InternalKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/InternalKeywordRecommenderTests.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations { [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public class InternalKeywordRecommenderTests : KeywordRecommenderTests + public sealed class InternalKeywordRecommenderTests : KeywordRecommenderTests { [Fact] public async Task TestAtRoot_Interactive() @@ -476,5 +476,22 @@ class C { int this[int i] { get { } protected $$ """); } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, + CSharpNextParseOptions, + CSharpNextScriptParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/LongKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/LongKeywordRecommenderTests.cs index 4aef97388870c..8d7c5195ca445 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/LongKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/LongKeywordRecommenderTests.cs @@ -350,9 +350,9 @@ public async Task TestNotAfterPartial() => await VerifyAbsenceAsync(@"partial $$"); [Fact] - public async Task TestNotAfterNestedPartial() + public async Task TestAfterNestedPartial() { - await VerifyAbsenceAsync( + await VerifyKeywordAsync( """ class C { partial $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/MethodKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/MethodKeywordRecommenderTests.cs index c8886baabb8fe..2ba731923eab3 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/MethodKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/MethodKeywordRecommenderTests.cs @@ -270,4 +270,36 @@ void F() } """); } + + [Fact] + public async Task TestWithinExtension1() + { + await VerifyAbsenceAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } + + [Fact] + public async Task TestWithinExtension2() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + [$$ + } + } + """, + CSharpNextParseOptions, + CSharpNextScriptParseOptions); + } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/NamespaceKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/NamespaceKeywordRecommenderTests.cs index 0b13d621b62d1..9967f116778f3 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/NamespaceKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/NamespaceKeywordRecommenderTests.cs @@ -543,5 +543,20 @@ await VerifyAbsenceAsync(SourceCodeKind.Script, $$ """); } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyAbsenceAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/NativeIntegerKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/NativeIntegerKeywordRecommenderTests.cs index 322ddd4898186..c13f4bee4cbfd 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/NativeIntegerKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/NativeIntegerKeywordRecommenderTests.cs @@ -28,6 +28,17 @@ await VerifyKeywordAsync(AddInsideMethod( @"$$")); } + [Fact] + public async Task TestInClass() + { + await VerifyKeywordAsync( + """ + class C + { + $$ + """); + } + [Fact] public async Task TestInParameterList() { @@ -591,4 +602,21 @@ IEnumerable M() => [string.Empty, .. ($$ } #endregion + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, + CSharpNextParseOptions, + CSharpNextScriptParseOptions); + } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/NewKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/NewKeywordRecommenderTests.cs index 2c18df41418af..3380cd5062b95 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/NewKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/NewKeywordRecommenderTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations { [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public class NewKeywordRecommenderTests : KeywordRecommenderTests + public sealed class NewKeywordRecommenderTests : KeywordRecommenderTests { [Fact] public async Task TestAtRoot() @@ -1325,5 +1325,22 @@ IEnumerable M() => [string.Empty, .. ($$ } #endregion + + [Fact] + public async Task TestWithinExtension() + { + await VerifyAbsenceAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, + CSharpNextParseOptions, + CSharpNextScriptParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/ObjectKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/ObjectKeywordRecommenderTests.cs index 0fc8d684ea2e1..d43f3324ccf10 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/ObjectKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/ObjectKeywordRecommenderTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations { [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public class ObjectKeywordRecommenderTests : KeywordRecommenderTests + public sealed class ObjectKeywordRecommenderTests : KeywordRecommenderTests { [Fact] public async Task TestAtRoot_Interactive() @@ -329,9 +329,9 @@ public async Task TestNotAfterPartial() => await VerifyAbsenceAsync(@"partial $$"); [Fact] - public async Task TestNotAfterNestedPartial() + public async Task TestAfterNestedPartial() { - await VerifyAbsenceAsync( + await VerifyKeywordAsync( """ class C { partial $$ @@ -1130,5 +1130,20 @@ IEnumerable M() => [string.Empty, .. ($$ } #endregion + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/OperatorKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/OperatorKeywordRecommenderTests.cs index 2977a3301a4e1..be78fa202787a 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/OperatorKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/OperatorKeywordRecommenderTests.cs @@ -139,5 +139,37 @@ interface Goo { public static int $$ """); } + + [Fact] + public async Task TestWithinExtension1() + { + await VerifyAbsenceAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } + + [Fact] + public async Task TestWithinExtension2() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + public static explicit $$ + } + } + """, + CSharpNextParseOptions, + CSharpNextScriptParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/OverrideKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/OverrideKeywordRecommenderTests.cs index b01caac19e286..d5eb94c35542c 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/OverrideKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/OverrideKeywordRecommenderTests.cs @@ -443,5 +443,20 @@ class C { private protected $$ """); } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyAbsenceAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/PartialKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/PartialKeywordRecommenderTests.cs index 5acbf825d5178..b424245897e71 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/PartialKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/PartialKeywordRecommenderTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations { [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public class PartialKeywordRecommenderTests : KeywordRecommenderTests + public sealed class PartialKeywordRecommenderTests : KeywordRecommenderTests { [Fact] public async Task TestAtRoot_Interactive() @@ -495,5 +495,20 @@ partial class C { virtual $$ """); } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyAbsenceAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/PrivateKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/PrivateKeywordRecommenderTests.cs index 9dc016e76e65e..49fdcc03b966e 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/PrivateKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/PrivateKeywordRecommenderTests.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations { [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public class PrivateKeywordRecommenderTests : KeywordRecommenderTests + public sealed class PrivateKeywordRecommenderTests : KeywordRecommenderTests { [Fact] public async Task TestAtRoot_Interactive() @@ -518,5 +518,22 @@ class C { int this[int i] { get { } internal $$ """); } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, + CSharpNextParseOptions, + CSharpNextScriptParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/PropertyKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/PropertyKeywordRecommenderTests.cs index 2413e43406f28..c62126d4c6541 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/PropertyKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/PropertyKeywordRecommenderTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations; [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] -public class PropertyKeywordRecommenderTests : KeywordRecommenderTests +public sealed class PropertyKeywordRecommenderTests : KeywordRecommenderTests { [Fact] public async Task TestNotAtRoot_Interactive() @@ -264,4 +264,36 @@ await VerifyKeywordAsync( record R([$$] int i) { } """); } + + [Fact] + public async Task TestWithinExtension1() + { + await VerifyAbsenceAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } + + [Fact] + public async Task TestWithinExtension2() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + [$$ + } + } + """, + CSharpNextParseOptions, + CSharpNextScriptParseOptions); + } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/PublicKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/PublicKeywordRecommenderTests.cs index 56ffbb2a5df3b..9c563b54df161 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/PublicKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/PublicKeywordRecommenderTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations { [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public class PublicKeywordRecommenderTests : KeywordRecommenderTests + public sealed class PublicKeywordRecommenderTests : KeywordRecommenderTests { [Fact] public async Task TestAtRoot_Interactive() @@ -552,5 +552,22 @@ await VerifyKeywordAsync( $$ """); } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, + CSharpNextParseOptions, + CSharpNextScriptParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/ReadOnlyKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/ReadOnlyKeywordRecommenderTests.cs index 801d5f9f721c8..fdc499a06ce03 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/ReadOnlyKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/ReadOnlyKeywordRecommenderTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations { [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public class ReadOnlyKeywordRecommenderTests : KeywordRecommenderTests + public sealed class ReadOnlyKeywordRecommenderTests : KeywordRecommenderTests { [Fact] public async Task TestAtRoot() @@ -716,10 +716,26 @@ class C [InlineData("ref readonly")] public async Task TestNotInFunctionPointerTypeAfterOtherRefModifier(string modifier) { - await VerifyAbsenceAsync($@" -class C -{{ - delegate*<{modifier} $$"); + await VerifyAbsenceAsync($$""" + class C + { + delegate*<{{modifier}} $$ + """); + } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyAbsenceAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/RecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/RecommenderTests.cs index c27ef93bb9f76..b4ab7bb7e532e 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/RecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/RecommenderTests.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; +using Microsoft.CodeAnalysis.CSharp.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; @@ -23,6 +24,8 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations public abstract class RecommenderTests : TestBase { protected static readonly CSharpParseOptions CSharp9ParseOptions = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp9); + protected static readonly CSharpParseOptions CSharpNextParseOptions = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersionExtensions.CSharpNext); + protected static readonly CSharpParseOptions CSharpNextScriptParseOptions = Options.Script.WithLanguageVersion(LanguageVersionExtensions.CSharpNext); protected abstract string KeywordText { get; } internal Func>>? RecommendKeywordsAsync; diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/RecordKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/RecordKeywordRecommenderTests.cs index 02ac3ea83a9dc..bf0ac559f0bba 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/RecordKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/RecordKeywordRecommenderTests.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations { [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public class RecordKeywordRecommenderTests : KeywordRecommenderTests + public sealed class RecordKeywordRecommenderTests : KeywordRecommenderTests { [Fact] public async Task TestAtRoot_Interactive() @@ -540,5 +540,22 @@ public async Task TestAfterReadonly() // readonly record struct is allowed. await VerifyKeywordAsync("readonly $$"); } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, + CSharpNextParseOptions, + CSharpNextScriptParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/RefKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/RefKeywordRecommenderTests.cs index 360e0bddbd32f..cf2d2f04215cb 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/RefKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/RefKeywordRecommenderTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations { [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public class RefKeywordRecommenderTests : KeywordRecommenderTests + public sealed class RefKeywordRecommenderTests : KeywordRecommenderTests { [Fact] public async Task TestAtRoot() @@ -1384,5 +1384,20 @@ await VerifyAbsenceAsync( class C where T : new(), allows ref $$ """); } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/ReturnKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/ReturnKeywordRecommenderTests.cs index e766277fc0abd..ab22e8f34a362 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/ReturnKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/ReturnKeywordRecommenderTests.cs @@ -455,4 +455,38 @@ await VerifyAbsenceAsync( record R([$$] int i) { } """); } + + [Fact] + public async Task TestWithinExtension1() + { + await VerifyAbsenceAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, + CSharpNextParseOptions, + CSharpNextScriptParseOptions); + } + + [Fact] + public async Task TestWithinExtension2() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + [$$ + } + } + """, + CSharpNextParseOptions, + CSharpNextScriptParseOptions); + } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/SByteKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/SByteKeywordRecommenderTests.cs index f47b1315ef06b..3d6c7c9f60c2e 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/SByteKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/SByteKeywordRecommenderTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations { [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public class SByteKeywordRecommenderTests : KeywordRecommenderTests + public sealed class SByteKeywordRecommenderTests : KeywordRecommenderTests { [Fact] public async Task TestAtRoot_Interactive() @@ -350,9 +350,9 @@ public async Task TestNotAfterPartial() => await VerifyAbsenceAsync(@"partial $$"); [Fact] - public async Task TestNotAfterNestedPartial() + public async Task TestAfterNestedPartial() { - await VerifyAbsenceAsync( + await VerifyKeywordAsync( """ class C { partial $$ @@ -1109,5 +1109,20 @@ IEnumerable M() => [string.Empty, .. ($$ } #endregion + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/SealedKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/SealedKeywordRecommenderTests.cs index 6011e8077e3ea..738f20128cc21 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/SealedKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/SealedKeywordRecommenderTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations { [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public class SealedKeywordRecommenderTests : KeywordRecommenderTests + public sealed class SealedKeywordRecommenderTests : KeywordRecommenderTests { [Fact] public async Task TestAtRoot_Interactive() @@ -471,5 +471,20 @@ class C { int Goo { get; internal $$ """); } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyAbsenceAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/ShortKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/ShortKeywordRecommenderTests.cs index 2e261c1aa6aa9..cb20061a084c5 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/ShortKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/ShortKeywordRecommenderTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations { [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public class ShortKeywordRecommenderTests : KeywordRecommenderTests + public sealed class ShortKeywordRecommenderTests : KeywordRecommenderTests { [Fact] public async Task TestAtRoot_Interactive() @@ -350,9 +350,9 @@ public async Task TestNotAfterPartial() => await VerifyAbsenceAsync(@"partial $$"); [Fact] - public async Task TestNotAfterNestedPartial() + public async Task TestAfterNestedPartial() { - await VerifyAbsenceAsync( + await VerifyKeywordAsync( """ class C { partial $$ @@ -958,10 +958,12 @@ ref readonly $$ public async Task TestAfterRefInClassInterfaceStructRecord(string type) { await VerifyKeywordAsync( -$@"{type} N -{{ - ref $$ -}}"); + $$""" + {{type}} N + { + ref $$ + } + """); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/67061")] @@ -972,10 +974,12 @@ await VerifyKeywordAsync( public async Task TestAfterReadonlyInClassInterfaceStructRecord(string type) { await VerifyKeywordAsync( -$@"{type} N -{{ - readonly $$ -}}"); + $$""" + {{type}} N + { + readonly $$ + } + """); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/67061")] @@ -986,10 +990,27 @@ await VerifyKeywordAsync( public async Task TestAfterRefReadonlyInClassInterfaceStructRecord(string type) { await VerifyKeywordAsync( -$@"{type} N -{{ - ref readonly $$ -}}"); + $$""" + {{type}} N + { + ref readonly $$ + } + """); + } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/StaticKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/StaticKeywordRecommenderTests.cs index e46bbf87812e6..719977e6e4ffb 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/StaticKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/StaticKeywordRecommenderTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations { [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public class StaticKeywordRecommenderTests : KeywordRecommenderTests + public sealed class StaticKeywordRecommenderTests : KeywordRecommenderTests { [Fact] public async Task TestAtRoot_Interactive() @@ -700,9 +700,24 @@ public async Task TestInFor() public async Task TestAfterUsingKeywordBeforeTopLevelStatement() { await VerifyKeywordAsync(""" -using $$ -var i = 1; -"""); + using $$ + var i = 1; + """); + } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/StringKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/StringKeywordRecommenderTests.cs index 1b6fa709c8dd9..1cc970d1a8799 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/StringKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/StringKeywordRecommenderTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations { [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public class StringKeywordRecommenderTests : KeywordRecommenderTests + public sealed class StringKeywordRecommenderTests : KeywordRecommenderTests { [Fact] public async Task TestAtRoot_Interactive() @@ -406,9 +406,9 @@ public async Task TestNotAfterPartial() => await VerifyAbsenceAsync(@"partial $$"); [Fact] - public async Task TestNotAfterNestedPartial() + public async Task TestAfterNestedPartial() { - await VerifyAbsenceAsync( + await VerifyKeywordAsync( """ class C { partial $$ @@ -1147,5 +1147,20 @@ IEnumerable M() => [string.Empty, .. ($$ } #endregion + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/StructKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/StructKeywordRecommenderTests.cs index 01f496fac662d..36e725a942f62 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/StructKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/StructKeywordRecommenderTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations { [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public class StructKeywordRecommenderTests : KeywordRecommenderTests + public sealed class StructKeywordRecommenderTests : KeywordRecommenderTests { [Fact] public async Task TestAtRoot_Interactive() @@ -708,5 +708,22 @@ await VerifyAbsenceAsync( class C where T : class, allows $$ """); } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, + CSharpNextParseOptions, + CSharpNextScriptParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/UIntKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/UIntKeywordRecommenderTests.cs index 382b988c5dfcc..74de0383fb7b3 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/UIntKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/UIntKeywordRecommenderTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations { [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public class UIntKeywordRecommenderTests : KeywordRecommenderTests + public sealed class UIntKeywordRecommenderTests : KeywordRecommenderTests { [Fact] public async Task TestAtRoot_Interactive() @@ -350,9 +350,9 @@ public async Task TestNotAfterPartial() => await VerifyAbsenceAsync(@"partial $$"); [Fact] - public async Task TestNotAfterNestedPartial() + public async Task TestAfterNestedPartial() { - await VerifyAbsenceAsync( + await VerifyKeywordAsync( """ class C { partial $$ @@ -1109,5 +1109,20 @@ IEnumerable M() => [string.Empty, .. ($$ } #endregion + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/ULongKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/ULongKeywordRecommenderTests.cs index 78a7092812e0c..ed4ef81119789 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/ULongKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/ULongKeywordRecommenderTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations { [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public class ULongKeywordRecommenderTests : KeywordRecommenderTests + public sealed class ULongKeywordRecommenderTests : KeywordRecommenderTests { [Fact] public async Task TestAtRoot_Interactive() @@ -350,9 +350,9 @@ public async Task TestNotAfterPartial() => await VerifyAbsenceAsync(@"partial $$"); [Fact] - public async Task TestNotAfterNestedPartial() + public async Task TestAfterNestedPartial() { - await VerifyAbsenceAsync( + await VerifyKeywordAsync( """ class C { partial $$ @@ -1109,5 +1109,20 @@ IEnumerable M() => [string.Empty, .. ($$ } #endregion + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/UShortKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/UShortKeywordRecommenderTests.cs index c93001d03ff98..c0edee7623d40 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/UShortKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/UShortKeywordRecommenderTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations { [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public class UShortKeywordRecommenderTests : KeywordRecommenderTests + public sealed class UShortKeywordRecommenderTests : KeywordRecommenderTests { [Fact] public async Task TestAtRoot_Interactive() @@ -350,9 +350,9 @@ public async Task TestNotAfterPartial() => await VerifyAbsenceAsync(@"partial $$"); [Fact] - public async Task TestNotAfterNestedPartial() + public async Task TestAfterNestedPartial() { - await VerifyAbsenceAsync( + await VerifyKeywordAsync( """ class C { partial $$ @@ -1109,5 +1109,20 @@ IEnumerable M() => [string.Empty, .. ($$ } #endregion + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/UncheckedKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/UncheckedKeywordRecommenderTests.cs index 83b624cda5953..c1475c1aaee98 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/UncheckedKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/UncheckedKeywordRecommenderTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations { [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public class UncheckedKeywordRecommenderTests : KeywordRecommenderTests + public sealed class UncheckedKeywordRecommenderTests : KeywordRecommenderTests { [Fact] public async Task TestAtRoot_Interactive() @@ -115,7 +115,24 @@ void M() public async Task TestAfterRefExpression() { await VerifyKeywordAsync(AddInsideMethod( -@"ref int x = ref $$")); + @"ref int x = ref $$")); + } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyAbsenceAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, + CSharpNextParseOptions, + CSharpNextScriptParseOptions); } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/UnsafeKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/UnsafeKeywordRecommenderTests.cs index a3e485c72a616..92680f0a62255 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/UnsafeKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/UnsafeKeywordRecommenderTests.cs @@ -497,5 +497,20 @@ public async Task TestAfterStaticKeywordInGlobalUsingDirective() { await VerifyKeywordAsync("global using static $$"); } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/UsingKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/UsingKeywordRecommenderTests.cs index c0ef8cd6b2186..976213efd46d7 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/UsingKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/UsingKeywordRecommenderTests.cs @@ -587,5 +587,22 @@ await VerifyKeywordAsync( [assembly: Call()] """); } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyAbsenceAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, + CSharpNextParseOptions, + CSharpNextScriptParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/VarKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/VarKeywordRecommenderTests.cs index 253f5fe3e52ab..f498b06f44377 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/VarKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/VarKeywordRecommenderTests.cs @@ -483,5 +483,22 @@ public async Task TestAfterScoped() await VerifyKeywordAsync(AddInsideMethod("scoped $$")); await VerifyKeywordAsync("scoped $$"); } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyAbsenceAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, + CSharpNextParseOptions, + CSharpNextScriptParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/VirtualKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/VirtualKeywordRecommenderTests.cs index c7e5cb44a1e2d..774157d5190f7 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/VirtualKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/VirtualKeywordRecommenderTests.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations { [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public class VirtualKeywordRecommenderTests : KeywordRecommenderTests + public sealed class VirtualKeywordRecommenderTests : KeywordRecommenderTests { [Fact] public async Task TestNotAtRoot_Interactive() @@ -407,5 +407,20 @@ class C { private protected $$ """); } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyAbsenceAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/VoidKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/VoidKeywordRecommenderTests.cs index 7f79f1cfd613d..d9e2114ab6da4 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/VoidKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/VoidKeywordRecommenderTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations { [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public class VoidKeywordRecommenderTests : KeywordRecommenderTests + public sealed class VoidKeywordRecommenderTests : KeywordRecommenderTests { [Fact] public async Task TestAtRoot() @@ -938,5 +938,20 @@ public async Task TestNotInRegularUsingDirective() { await VerifyAbsenceAsync("using T = $$"); } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyKeywordAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/VolatileKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/VolatileKeywordRecommenderTests.cs index 1c5b8dca3195b..692b8e8d1178e 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/VolatileKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/VolatileKeywordRecommenderTests.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations { [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public class VolatileKeywordRecommenderTests : KeywordRecommenderTests + public sealed class VolatileKeywordRecommenderTests : KeywordRecommenderTests { [Fact] public async Task TestAtRoot_Interactive() @@ -508,5 +508,20 @@ void Goo() { $$ """); } + + [Fact] + public async Task TestWithinExtension() + { + await VerifyAbsenceAsync( + """ + static class C + { + extension(string s) + { + $$ + } + } + """, CSharpNextParseOptions); + } } } diff --git a/src/EditorFeatures/Core.Wpf/Adornments/AbstractAdornmentManager.cs b/src/EditorFeatures/Core.Wpf/Adornments/AbstractAdornmentManager.cs index b7c9e6277bd73..1949869f19175 100644 --- a/src/EditorFeatures/Core.Wpf/Adornments/AbstractAdornmentManager.cs +++ b/src/EditorFeatures/Core.Wpf/Adornments/AbstractAdornmentManager.cs @@ -17,7 +17,6 @@ using Microsoft.VisualStudio.Text.Formatting; using Microsoft.VisualStudio.Text.Tagging; using Microsoft.VisualStudio.Threading; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.Adornments { diff --git a/src/EditorFeatures/Core.Wpf/BackgroundWorkIndicator/BackgroundWorkIndicatorContext.cs b/src/EditorFeatures/Core.Wpf/BackgroundWorkIndicator/BackgroundWorkIndicatorContext.cs index 037808e696ec0..54e4f7f9b7c32 100644 --- a/src/EditorFeatures/Core.Wpf/BackgroundWorkIndicator/BackgroundWorkIndicatorContext.cs +++ b/src/EditorFeatures/Core.Wpf/BackgroundWorkIndicator/BackgroundWorkIndicatorContext.cs @@ -10,11 +10,11 @@ using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Threading; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Adornments; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.BackgroundWorkIndicator; diff --git a/src/EditorFeatures/Core.Wpf/BackgroundWorkIndicator/BackgroundWorkIndicatorScope.cs b/src/EditorFeatures/Core.Wpf/BackgroundWorkIndicator/BackgroundWorkIndicatorScope.cs index 21436bb7dfeb1..d65e9fcdd3ae3 100644 --- a/src/EditorFeatures/Core.Wpf/BackgroundWorkIndicator/BackgroundWorkIndicatorScope.cs +++ b/src/EditorFeatures/Core.Wpf/BackgroundWorkIndicator/BackgroundWorkIndicatorScope.cs @@ -5,7 +5,6 @@ using System; using System.Threading; using Microsoft.VisualStudio.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.BackgroundWorkIndicator; diff --git a/src/EditorFeatures/Core.Wpf/IWpfDifferenceViewerExtensions.cs b/src/EditorFeatures/Core.Wpf/IWpfDifferenceViewerExtensions.cs index d00224da10320..4e702d2f01ab7 100644 --- a/src/EditorFeatures/Core.Wpf/IWpfDifferenceViewerExtensions.cs +++ b/src/EditorFeatures/Core.Wpf/IWpfDifferenceViewerExtensions.cs @@ -13,7 +13,6 @@ using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Projection; using Microsoft.VisualStudio.Threading; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Shared.Extensions { diff --git a/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsTag.cs b/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsTag.cs index fc6415f180205..85476119ad962 100644 --- a/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsTag.cs +++ b/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsTag.cs @@ -18,7 +18,6 @@ using Microsoft.VisualStudio.Text.Classification; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Formatting; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.InlineDiagnostics { diff --git a/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTagger.cs b/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTagger.cs index c7fad83f466a5..d62014cbd01a0 100644 --- a/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTagger.cs +++ b/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTagger.cs @@ -17,7 +17,6 @@ using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Formatting; using Microsoft.VisualStudio.Text.Tagging; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.InlineHints; diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyout.xaml b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyout.xaml index be642b6dfac18..36632cbe37f86 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyout.xaml +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyout.xaml @@ -12,7 +12,6 @@ xmlns:vsui="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.15.0" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800" - MinWidth="200" KeyDown="Adornment_KeyDown" MouseDown="Adornment_ConsumeMouseEvent" MouseUp="Adornment_ConsumeMouseEvent" @@ -97,13 +96,14 @@ - + @@ -125,6 +125,7 @@ Text="{Binding ElementName=control, Path=SubmitText}" Margin="5, 5, 0, 0" FontStyle="Italic" + TextWrapping="Wrap" /> diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyout.xaml.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyout.xaml.cs index 4b35e3e3832f6..ad8b1fbd8e1f3 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyout.xaml.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyout.xaml.cs @@ -23,6 +23,8 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename /// internal partial class RenameFlyout : InlineRenameAdornment { + private const int DefaultMinWidth = 200; + private readonly RenameFlyoutViewModel _viewModel; private readonly IEditorFormatMap _editorFormatMap; private readonly IWpfTextView _textView; @@ -147,8 +149,11 @@ private void PositionAdornment() ? _textView.ViewportRight - width : desiredLeft; - Canvas.SetTop(this, top); - Canvas.SetLeft(this, left); + MaxWidth = _textView.ViewportRight; + MinWidth = Math.Min(DefaultMinWidth, _textView.ViewportWidth); + + Canvas.SetTop(this, Math.Max(0, top)); + Canvas.SetLeft(this, Math.Max(0, left)); } public override void Dispose() diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/SmartRename/SmartRenameUserInputComboBox.xaml b/src/EditorFeatures/Core.Wpf/InlineRename/UI/SmartRename/SmartRenameUserInputComboBox.xaml index 5c0518f50525d..69a06a7bcacf0 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/SmartRename/SmartRenameUserInputComboBox.xaml +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/SmartRename/SmartRenameUserInputComboBox.xaml @@ -15,6 +15,7 @@ ItemsSource="{Binding SuggestedNames}" StaysOpenOnEdit="True" IsEditable="True" + IsTextSearchEnabled="False" Style="{StaticResource {x:Static vsfx:VsResourceKeys.ComboBoxStyleKey}}" GotKeyboardFocus="ComboBox_GotKeyboardFocus" VirtualizingStackPanel.IsVirtualizing="True" diff --git a/src/EditorFeatures/Core.Wpf/Interactive/InteractiveEvaluator.cs b/src/EditorFeatures/Core.Wpf/Interactive/InteractiveEvaluator.cs index bf3b243d0be11..414ee3dd3cef2 100644 --- a/src/EditorFeatures/Core.Wpf/Interactive/InteractiveEvaluator.cs +++ b/src/EditorFeatures/Core.Wpf/Interactive/InteractiveEvaluator.cs @@ -20,7 +20,6 @@ using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Classification; using Microsoft.VisualStudio.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Interactive { diff --git a/src/EditorFeatures/Core.Wpf/Interactive/InteractiveGlobalUndoServiceFactory.cs b/src/EditorFeatures/Core.Wpf/Interactive/InteractiveGlobalUndoServiceFactory.cs index f3cdb820b317c..ed6703990cb54 100644 --- a/src/EditorFeatures/Core.Wpf/Interactive/InteractiveGlobalUndoServiceFactory.cs +++ b/src/EditorFeatures/Core.Wpf/Interactive/InteractiveGlobalUndoServiceFactory.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.VisualStudio.Text.Operations; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Interactive { diff --git a/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorAdornmentManager.cs b/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorAdornmentManager.cs index 659e7faf5f05a..42154a5755cee 100644 --- a/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorAdornmentManager.cs +++ b/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorAdornmentManager.cs @@ -9,7 +9,6 @@ using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Tagging; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.LineSeparators { diff --git a/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemProvider.Callback.cs b/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemProvider.Callback.cs index cb42cc3076b4f..cd2996666f6e2 100644 --- a/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemProvider.Callback.cs +++ b/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemProvider.Callback.cs @@ -12,7 +12,6 @@ using Microsoft.CodeAnalysis.Text.Shared.Extensions; using Microsoft.VisualStudio.Language.NavigateTo.Interfaces; using Microsoft.VisualStudio.Text.PatternMatching; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.NavigateTo { diff --git a/src/EditorFeatures/Core.Wpf/Peek/PeekableItemFactory.cs b/src/EditorFeatures/Core.Wpf/Peek/PeekableItemFactory.cs index d3b86ff56a40a..f78c5d70cd9ac 100644 --- a/src/EditorFeatures/Core.Wpf/Peek/PeekableItemFactory.cs +++ b/src/EditorFeatures/Core.Wpf/Peek/PeekableItemFactory.cs @@ -6,7 +6,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.ComponentModel.Composition; using System.Linq; using System.Threading; diff --git a/src/EditorFeatures/Core.Wpf/Preview/DifferenceViewerPreview.cs b/src/EditorFeatures/Core.Wpf/Preview/DifferenceViewerPreview.cs index ae8a5ebb885b6..c7c93b2787992 100644 --- a/src/EditorFeatures/Core.Wpf/Preview/DifferenceViewerPreview.cs +++ b/src/EditorFeatures/Core.Wpf/Preview/DifferenceViewerPreview.cs @@ -12,7 +12,6 @@ using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Text.Differencing; using Microsoft.VisualStudio.Text.Operations; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.Preview { diff --git a/src/EditorFeatures/Core.Wpf/Preview/PreviewFactoryService.cs b/src/EditorFeatures/Core.Wpf/Preview/PreviewFactoryService.cs index de16129008ca8..f34e2dbd6353a 100644 --- a/src/EditorFeatures/Core.Wpf/Preview/PreviewFactoryService.cs +++ b/src/EditorFeatures/Core.Wpf/Preview/PreviewFactoryService.cs @@ -18,7 +18,6 @@ using Microsoft.VisualStudio.Text.Operations; using Microsoft.VisualStudio.Text.Projection; using Microsoft.VisualStudio.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.Preview { diff --git a/src/EditorFeatures/Core.Wpf/QuickInfo/Extensions.cs b/src/EditorFeatures/Core.Wpf/QuickInfo/Extensions.cs index eaea8ad593cf6..f3b23e78f1956 100644 --- a/src/EditorFeatures/Core.Wpf/QuickInfo/Extensions.cs +++ b/src/EditorFeatures/Core.Wpf/QuickInfo/Extensions.cs @@ -8,7 +8,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.QuickInfo { diff --git a/src/EditorFeatures/Core.Wpf/QuickInfo/OnTheFlyDocsView.xaml.cs b/src/EditorFeatures/Core.Wpf/QuickInfo/OnTheFlyDocsView.xaml.cs index 424d1c8c775d2..b9908ef2dbf80 100644 --- a/src/EditorFeatures/Core.Wpf/QuickInfo/OnTheFlyDocsView.xaml.cs +++ b/src/EditorFeatures/Core.Wpf/QuickInfo/OnTheFlyDocsView.xaml.cs @@ -179,7 +179,8 @@ private async Task SetResultTextAsync(ICopilotCodeAnalysisService copilotService try { - var (responseString, isQuotaExceeded) = await copilotService.GetOnTheFlyDocsAsync(_onTheFlyDocsInfo.SymbolSignature, _onTheFlyDocsInfo.DeclarationCode, _onTheFlyDocsInfo.Language, cancellationToken).ConfigureAwait(false); + var prompt = await copilotService.GetOnTheFlyDocsPromptAsync(_onTheFlyDocsInfo, cancellationToken).ConfigureAwait(false); + var (responseString, isQuotaExceeded) = await copilotService.GetOnTheFlyDocsResponseAsync(prompt, cancellationToken).ConfigureAwait(false); var copilotRequestTime = stopwatch.Elapsed; await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session.cs index 2536450973e52..9de3c4ff61bf6 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session.cs @@ -4,9 +4,7 @@ #nullable disable -using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp { diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs index 2b913940c08ef..1174c20a726ea 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs @@ -16,7 +16,6 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SignatureHelp; using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_SetModelSelectedItem.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_SetModelSelectedItem.cs index 026e40169bcb8..9d39545a5aef2 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_SetModelSelectedItem.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_SetModelSelectedItem.cs @@ -6,8 +6,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.SignatureHelp; -using Microsoft.VisualStudio.Threading; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp { diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/Model.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/Model.cs index 00d210ad0890c..de9bc206ecfba 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/Model.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/Model.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text.Shared.Extensions; using Microsoft.VisualStudio.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp { diff --git a/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationAdornmentManager.cs b/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationAdornmentManager.cs index 0e0e7d4edb5b3..5b54fe64dff28 100644 --- a/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationAdornmentManager.cs +++ b/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationAdornmentManager.cs @@ -13,7 +13,6 @@ using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Tagging; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.StringIndentation { diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionWithNestedFlavors.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionWithNestedFlavors.cs index cb486d50fcc43..e356b48f8dbf4 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionWithNestedFlavors.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionWithNestedFlavors.cs @@ -18,7 +18,6 @@ using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions { diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/AbstractFixAllSuggestedAction.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/AbstractFixAllSuggestedAction.cs index e227356ca87df..537fea880b42d 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/AbstractFixAllSuggestedAction.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/AbstractFixAllSuggestedAction.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.VisualStudio.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions { diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/SuggestedAction.CaretPositionRestorer.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/SuggestedAction.CaretPositionRestorer.cs index 4e52102add66b..e4294a41f0e77 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/SuggestedAction.CaretPositionRestorer.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/SuggestedAction.CaretPositionRestorer.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions { diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs index 549acf728a56a..70ba8fbf31827 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -9,11 +9,9 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Options; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSourceProvider.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSourceProvider.cs index 49b3fe24307b5..1c0176004abff 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSourceProvider.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSourceProvider.cs @@ -20,7 +20,6 @@ using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions { diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource_Async.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource_Async.cs index 206c7f08f8f81..4fe80c0b9563a 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource_Async.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource_Async.cs @@ -12,7 +12,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.Shared; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Options; diff --git a/src/EditorFeatures/Core/AddImports/AbstractAddImportsPasteCommandHandler.cs b/src/EditorFeatures/Core/AddImports/AbstractAddImportsPasteCommandHandler.cs index 4f89fe2ee33e7..af45baddacc1a 100644 --- a/src/EditorFeatures/Core/AddImports/AbstractAddImportsPasteCommandHandler.cs +++ b/src/EditorFeatures/Core/AddImports/AbstractAddImportsPasteCommandHandler.cs @@ -6,7 +6,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.AddImportOnPaste; using Microsoft.CodeAnalysis.AddMissingImports; -using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Editor.BackgroundWorkIndicator; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; diff --git a/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.BraceCompletionSession.cs b/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.BraceCompletionSession.cs index 0a7150c29cc60..76b24069f2701 100644 --- a/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.BraceCompletionSession.cs +++ b/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.BraceCompletionSession.cs @@ -20,7 +20,6 @@ using Microsoft.VisualStudio.Text.BraceCompletion; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Operations; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.AutomaticCompletion; diff --git a/src/EditorFeatures/Core/AutomaticCompletion/Extensions.cs b/src/EditorFeatures/Core/AutomaticCompletion/Extensions.cs index 26ffb71470ca7..cdda4dd93f8bc 100644 --- a/src/EditorFeatures/Core/AutomaticCompletion/Extensions.cs +++ b/src/EditorFeatures/Core/AutomaticCompletion/Extensions.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.BraceCompletion; diff --git a/src/EditorFeatures/Core/BraceMatching/BraceHighlightingViewTaggerProvider.cs b/src/EditorFeatures/Core/BraceMatching/BraceHighlightingViewTaggerProvider.cs index 412030cb17cb7..4c1e0d851ada9 100644 --- a/src/EditorFeatures/Core/BraceMatching/BraceHighlightingViewTaggerProvider.cs +++ b/src/EditorFeatures/Core/BraceMatching/BraceHighlightingViewTaggerProvider.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.ComponentModel.Composition; using System.Diagnostics.CodeAnalysis; diff --git a/src/EditorFeatures/Core/ChangeSignature/AbstractChangeSignatureCommandHandler.cs b/src/EditorFeatures/Core/ChangeSignature/AbstractChangeSignatureCommandHandler.cs index 8c81a0fe321df..653b84794cce2 100644 --- a/src/EditorFeatures/Core/ChangeSignature/AbstractChangeSignatureCommandHandler.cs +++ b/src/EditorFeatures/Core/ChangeSignature/AbstractChangeSignatureCommandHandler.cs @@ -125,7 +125,7 @@ private static void HandleResult(ChangeSignatureResult result, Solution oldSolut string.Format(EditorFeaturesResources.Preview_Changes_0, EditorFeaturesResources.Change_Signature), "vs.csharp.refactoring.preview", EditorFeaturesResources.Change_Signature_colon, - result.Name, + result.Name!, result.Glyph.GetValueOrDefault(), result.UpdatedSolution, oldSolution); diff --git a/src/EditorFeatures/Core/Classification/ClassificationTags.cs b/src/EditorFeatures/Core/Classification/ClassificationTags.cs index 4fb4aadf7e4ab..95803c17e6442 100644 --- a/src/EditorFeatures/Core/Classification/ClassificationTags.cs +++ b/src/EditorFeatures/Core/Classification/ClassificationTags.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; namespace Microsoft.CodeAnalysis.Classification; diff --git a/src/EditorFeatures/Core/Classification/CopyPasteAndPrintingClassificationBufferTaggerProvider.Tagger.cs b/src/EditorFeatures/Core/Classification/CopyPasteAndPrintingClassificationBufferTaggerProvider.Tagger.cs index 26e47c2026d5c..7fa4b6d4cc0de 100644 --- a/src/EditorFeatures/Core/Classification/CopyPasteAndPrintingClassificationBufferTaggerProvider.Tagger.cs +++ b/src/EditorFeatures/Core/Classification/CopyPasteAndPrintingClassificationBufferTaggerProvider.Tagger.cs @@ -15,6 +15,7 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Threading; using Microsoft.CodeAnalysis.Utilities; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Tagging; diff --git a/src/EditorFeatures/Core/Classification/Semantic/AbstractSemanticOrEmbeddedClassificationViewTaggerProvider.cs b/src/EditorFeatures/Core/Classification/Semantic/AbstractSemanticOrEmbeddedClassificationViewTaggerProvider.cs index b26cd16e6f34a..9c5c9091fd842 100644 --- a/src/EditorFeatures/Core/Classification/Semantic/AbstractSemanticOrEmbeddedClassificationViewTaggerProvider.cs +++ b/src/EditorFeatures/Core/Classification/Semantic/AbstractSemanticOrEmbeddedClassificationViewTaggerProvider.cs @@ -23,7 +23,6 @@ using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Tagging; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Classification; diff --git a/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.ClassifiedLineCache.cs b/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.ClassifiedLineCache.cs index 7b53e6139c6fc..c1dc9cb55ade9 100644 --- a/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.ClassifiedLineCache.cs +++ b/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.ClassifiedLineCache.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.VisualStudio.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Classification; diff --git a/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.TagComputer.cs b/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.TagComputer.cs index 75f3ca53e80f3..64e62295d6774 100644 --- a/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.TagComputer.cs +++ b/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.TagComputer.cs @@ -15,10 +15,10 @@ using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text.Shared.Extensions; +using Microsoft.CodeAnalysis.Threading; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Tagging; using Microsoft.VisualStudio.Utilities; -using Roslyn.LanguageServer.Protocol; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Classification; diff --git a/src/EditorFeatures/Core/CodeDefinitionWindow/DefinitionContextTracker.cs b/src/EditorFeatures/Core/CodeDefinitionWindow/DefinitionContextTracker.cs index dac6664277e6d..e8b27fb5d1a4d 100644 --- a/src/EditorFeatures/Core/CodeDefinitionWindow/DefinitionContextTracker.cs +++ b/src/EditorFeatures/Core/CodeDefinitionWindow/DefinitionContextTracker.cs @@ -22,6 +22,7 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Threading; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Utilities; @@ -185,7 +186,7 @@ internal async Task> GetContextFrom var declarationFile = await _metadataAsSourceFileService.GetGeneratedFileAsync(workspace, document.Project, symbol, signaturesOnly: false, options: options, cancellationToken: cancellationToken).ConfigureAwait(false); var identifierSpan = declarationFile.IdentifierLocation.GetLineSpan().Span; locations.Add(new CodeDefinitionWindowLocation( - symbol.ToDisplayString(), declarationFile.FilePath, identifierSpan.Start)); + symbol.ToDisplayString(), declarationFile.FilePath!, identifierSpan.Start)); } } } diff --git a/src/EditorFeatures/Core/CodeRefactorings/EditorLayerCodeActionHelpersService.cs b/src/EditorFeatures/Core/CodeRefactorings/EditorLayerCodeActionHelpersService.cs index 8377489ee15b9..18e2e2402b326 100644 --- a/src/EditorFeatures/Core/CodeRefactorings/EditorLayerCodeActionHelpersService.cs +++ b/src/EditorFeatures/Core/CodeRefactorings/EditorLayerCodeActionHelpersService.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.Composition; using Microsoft.CodeAnalysis.Editor; diff --git a/src/EditorFeatures/Core/Commanding/LegacyCommandHandlerServiceFactory.cs b/src/EditorFeatures/Core/Commanding/LegacyCommandHandlerServiceFactory.cs index c8344eed699a6..d057d4f2bec5e 100644 --- a/src/EditorFeatures/Core/Commanding/LegacyCommandHandlerServiceFactory.cs +++ b/src/EditorFeatures/Core/Commanding/LegacyCommandHandlerServiceFactory.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.ComponentModel.Composition; using Microsoft.CodeAnalysis.Host.Mef; diff --git a/src/EditorFeatures/Core/CommentSelection/AbstractToggleBlockCommentBase.cs b/src/EditorFeatures/Core/CommentSelection/AbstractToggleBlockCommentBase.cs index 0fcc947eae5b8..9ef36b27f0f74 100644 --- a/src/EditorFeatures/Core/CommentSelection/AbstractToggleBlockCommentBase.cs +++ b/src/EditorFeatures/Core/CommentSelection/AbstractToggleBlockCommentBase.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.Immutable; diff --git a/src/EditorFeatures/Core/CommentSelection/CommentSelectionResult.cs b/src/EditorFeatures/Core/CommentSelection/CommentSelectionResult.cs index db211738e78f5..669ab8e37f146 100644 --- a/src/EditorFeatures/Core/CommentSelection/CommentSelectionResult.cs +++ b/src/EditorFeatures/Core/CommentSelection/CommentSelectionResult.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 Microsoft.CodeAnalysis.Text; diff --git a/src/EditorFeatures/Core/CommentSelection/CommentTrackingSpan.cs b/src/EditorFeatures/Core/CommentSelection/CommentTrackingSpan.cs index e97807eab7194..9c0944f0af267 100644 --- a/src/EditorFeatures/Core/CommentSelection/CommentTrackingSpan.cs +++ b/src/EditorFeatures/Core/CommentSelection/CommentTrackingSpan.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.CommentSelection; diff --git a/src/EditorFeatures/Core/CommentSelection/ToggleBlockCommentCommandHandler.cs b/src/EditorFeatures/Core/CommentSelection/ToggleBlockCommentCommandHandler.cs index 2d7e9dc241f63..cffb24053e6fd 100644 --- a/src/EditorFeatures/Core/CommentSelection/ToggleBlockCommentCommandHandler.cs +++ b/src/EditorFeatures/Core/CommentSelection/ToggleBlockCommentCommandHandler.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Immutable; using System.ComponentModel.Composition; diff --git a/src/EditorFeatures/Core/Copilot/CopilotTaggerProvider.cs b/src/EditorFeatures/Core/Copilot/CopilotTaggerProvider.cs index 5c3157ba29539..a1105e718c04c 100644 --- a/src/EditorFeatures/Core/Copilot/CopilotTaggerProvider.cs +++ b/src/EditorFeatures/Core/Copilot/CopilotTaggerProvider.cs @@ -17,7 +17,6 @@ using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Tagging; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Copilot; diff --git a/src/EditorFeatures/Core/DocumentationComments/AbstractDocumentationCommentCommandHandler.cs b/src/EditorFeatures/Core/DocumentationComments/AbstractDocumentationCommentCommandHandler.cs index f5e72cd324736..d18db02ea2f08 100644 --- a/src/EditorFeatures/Core/DocumentationComments/AbstractDocumentationCommentCommandHandler.cs +++ b/src/EditorFeatures/Core/DocumentationComments/AbstractDocumentationCommentCommandHandler.cs @@ -5,6 +5,7 @@ using System; using System.Linq; using System.Threading; +using Microsoft.CodeAnalysis.DocumentationComments; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -31,12 +32,14 @@ internal abstract class AbstractDocumentationCommentCommandHandler : private readonly ITextUndoHistoryRegistry _undoHistoryRegistry; private readonly IEditorOperationsFactoryService _editorOperationsFactoryService; private readonly EditorOptionsService _editorOptionsService; + private readonly CopilotGenerateDocumentationCommentManager _generateDocumentationCommentManager; protected AbstractDocumentationCommentCommandHandler( IUIThreadOperationExecutor uiThreadOperationExecutor, ITextUndoHistoryRegistry undoHistoryRegistry, IEditorOperationsFactoryService editorOperationsFactoryService, - EditorOptionsService editorOptionsService) + EditorOptionsService editorOptionsService, + CopilotGenerateDocumentationCommentManager generateDocumentationCommentManager) { Contract.ThrowIfNull(uiThreadOperationExecutor); Contract.ThrowIfNull(undoHistoryRegistry); @@ -46,6 +49,7 @@ protected AbstractDocumentationCommentCommandHandler( _undoHistoryRegistry = undoHistoryRegistry; _editorOperationsFactoryService = editorOperationsFactoryService; _editorOptionsService = editorOptionsService; + _generateDocumentationCommentManager = generateDocumentationCommentManager; } protected abstract string ExteriorTriviaText { get; } @@ -97,13 +101,17 @@ private bool CompleteComment( if (snippet != null) { ApplySnippet(snippet, subjectBuffer, textView); + var oldSnapshot = subjectBuffer.CurrentSnapshot; + var oldCaret = textView.Caret.Position.VirtualBufferPosition; + returnValue = true; + + _generateDocumentationCommentManager.TriggerDocumentationCommentProposalGeneration(document, snippet, oldSnapshot, oldCaret, textView, cancellationToken); } } return returnValue; } - public CommandState GetCommandState(TypeCharCommandArgs args, Func nextHandler) => nextHandler(); diff --git a/src/EditorFeatures/Core/DocumentationComments/CopilotGenerateDocumentationCommentManager.cs b/src/EditorFeatures/Core/DocumentationComments/CopilotGenerateDocumentationCommentManager.cs new file mode 100644 index 0000000000000..43b47dee86976 --- /dev/null +++ b/src/EditorFeatures/Core/DocumentationComments/CopilotGenerateDocumentationCommentManager.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; +using System.ComponentModel.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Copilot; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.VisualStudio.Language.Suggestions; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; + +namespace Microsoft.CodeAnalysis.DocumentationComments +{ + [Export(typeof(CopilotGenerateDocumentationCommentManager))] + internal class CopilotGenerateDocumentationCommentManager + { + private readonly SuggestionServiceBase? _suggestionServiceBase; + private readonly IThreadingContext _threadingContext; + private readonly IAsynchronousOperationListener _asyncListener; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CopilotGenerateDocumentationCommentManager([Import(AllowDefault = true)] SuggestionServiceBase? suggestionServiceBase, IThreadingContext threadingContext, + IAsynchronousOperationListenerProvider listenerProvider) + { + _suggestionServiceBase = suggestionServiceBase; + _threadingContext = threadingContext; + _asyncListener = listenerProvider.GetListener(FeatureAttribute.GenerateDocumentation); + } + + public void TriggerDocumentationCommentProposalGeneration(Document document, + DocumentationCommentSnippet snippet, ITextSnapshot snapshot, VirtualSnapshotPoint caret, ITextView textView, CancellationToken cancellationToken) + { + if (_suggestionServiceBase is null) + { + return; + } + + var token = _asyncListener.BeginAsyncOperation(nameof(GenerateDocumentationCommentProposalsAsync)); + _ = GenerateDocumentationCommentProposalsAsync(document, snippet, snapshot, caret, textView, cancellationToken).CompletesAsyncOperation(token); + } + + private async Task GenerateDocumentationCommentProposalsAsync(Document document, DocumentationCommentSnippet snippet, ITextSnapshot snapshot, VirtualSnapshotPoint caret, ITextView textView, CancellationToken cancellationToken) + { + var generateDocumentationCommentProvider = await CreateProviderAsync(document, textView, snippet.MemberNode, cancellationToken).ConfigureAwait(false); + if (generateDocumentationCommentProvider is not null) + { + await generateDocumentationCommentProvider.GenerateDocumentationProposalAsync(snippet, snapshot, caret, cancellationToken).ConfigureAwait(false); + } + } + + private async Task CreateProviderAsync(Document document, ITextView textView, SyntaxNode? memberNode, CancellationToken cancellationToken) + { + var copilotService = await IsGenerateDocumentationAvailableAsync(document, memberNode, cancellationToken).ConfigureAwait(false); + + if (copilotService is null) + { + return null; + } + + var provider = textView.Properties.GetOrCreateSingletonProperty(typeof(CopilotGenerateDocumentationCommentProvider), + () => new CopilotGenerateDocumentationCommentProvider(_threadingContext, copilotService)); + + await provider!.InitializeAsync(textView, _suggestionServiceBase!, cancellationToken).ConfigureAwait(false); + + return provider; + } + + private static async Task IsGenerateDocumentationAvailableAsync(Document document, SyntaxNode? memberNode, CancellationToken cancellationToken) + { + // Bailing out if copilot is not available or the option is not enabled. + if (document.GetLanguageService() is not { } copilotOptionService || + !await copilotOptionService.IsGenerateDocumentationCommentOptionEnabledAsync().ConfigureAwait(false)) + { + return null; + } + + if (document.GetLanguageService() is not { } copilotService || + await copilotService.IsAvailableAsync(cancellationToken).ConfigureAwait(false) is false) + { + return null; + } + + if (memberNode is null) + { + return null; + } + + // Check to see if the file containing the member being documented has been excluded. + if (await copilotService.IsFileExcludedAsync(memberNode.SyntaxTree.FilePath, cancellationToken).ConfigureAwait(false)) + { + return null; + } + + return copilotService; + } + } +} diff --git a/src/EditorFeatures/Core/DocumentationComments/CopilotGenerateDocumentationCommentProvider.cs b/src/EditorFeatures/Core/DocumentationComments/CopilotGenerateDocumentationCommentProvider.cs new file mode 100644 index 0000000000000..ffae074634a6b --- /dev/null +++ b/src/EditorFeatures/Core/DocumentationComments/CopilotGenerateDocumentationCommentProvider.cs @@ -0,0 +1,323 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Copilot; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Threading; +using Microsoft.VisualStudio.Language.Proposals; +using Microsoft.VisualStudio.Language.Suggestions; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.DocumentationComments +{ + internal class CopilotGenerateDocumentationCommentProvider : SuggestionProviderBase + { + private SuggestionManagerBase? _suggestionManager; + private readonly ICopilotCodeAnalysisService _copilotService; + + public readonly IThreadingContext ThreadingContext; + + public bool Enabled => _enabled && (_suggestionManager != null); + private bool _enabled = true; + + public CopilotGenerateDocumentationCommentProvider(IThreadingContext threadingContext, ICopilotCodeAnalysisService copilotService) + { + _copilotService = copilotService; + ThreadingContext = threadingContext; + } + + public async Task InitializeAsync(ITextView textView, SuggestionServiceBase suggestionServiceBase, CancellationToken cancellationToken) + { + _suggestionManager ??= await suggestionServiceBase.TryRegisterProviderAsync(this, textView, "AmbientAIDocumentationComments", cancellationToken).ConfigureAwait(false); + } + + public async Task GenerateDocumentationProposalAsync(DocumentationCommentSnippet snippet, + ITextSnapshot oldSnapshot, VirtualSnapshotPoint oldCaret, CancellationToken cancellationToken) + { + await Task.Yield().ConfigureAwait(false); + + if (!Enabled) + { + return; + } + + // MemberNode is not null at this point, checked when determining if the file is exluded. + var snippetProposal = GetSnippetProposal(snippet.SnippetText, snippet.MemberNode!, snippet.Position, snippet.CaretOffset); + + if (snippetProposal is null) + { + return; + } + + // Do not do IntelliCode line completions if we're about to generate a documentation comment + // so that won't have interfering grey text. + var intellicodeLineCompletionsDisposable = await _suggestionManager!.DisableProviderAsync(SuggestionServiceNames.IntelliCodeLineCompletions, cancellationToken).ConfigureAwait(false); + + var proposalEdits = await GetProposedEditsAsync(snippetProposal, _copilotService, oldSnapshot, snippet.IndentText, cancellationToken).ConfigureAwait(false); + + var proposal = Proposal.TryCreateProposal(null, proposalEdits, oldCaret, flags: ProposalFlags.SingleTabToAccept); + + if (proposal is null) + { + await intellicodeLineCompletionsDisposable.DisposeAsync().ConfigureAwait(false); + return; + } + + var suggestion = new DocumentationCommentSuggestion(this, proposal, _suggestionManager, intellicodeLineCompletionsDisposable); + await suggestion.TryDisplaySuggestionAsync(cancellationToken).ConfigureAwait(false); + } + + /// + /// Traverses the documentation comment shell and retrieves the pieces that are needed to generate the documentation comment. + /// + private static DocumentationCommentProposal? GetSnippetProposal(string comments, SyntaxNode memberNode, int? position, int caret) + { + if (position is null) + { + return null; + } + + var startIndex = position.Value; + var proposedEdits = ArrayBuilder.GetInstance(); + var index = 0; + + var summaryStartTag = comments.IndexOf("", index, StringComparison.Ordinal); + var summaryEndTag = comments.IndexOf("", index, StringComparison.Ordinal); + if (summaryEndTag != -1 && summaryStartTag != -1) + { + proposedEdits.Add(new DocumentationCommentProposedEdit(new TextSpan(caret + startIndex, 0), symbolName: null, DocumentationCommentTagType.Summary)); + } + + // We may receive remarks from the model. In that case, we want to insert the remark tags and remark directly after the summary. + proposedEdits.Add(new DocumentationCommentProposedEdit(new TextSpan(summaryEndTag + "".Length + startIndex, 0), symbolName: null, DocumentationCommentTagType.Remarks)); + + while (true) + { + var typeParamEndTag = comments.IndexOf("", index, StringComparison.Ordinal); + var typeParamStartTag = comments.IndexOf("", typeParamNameStart, StringComparison.Ordinal); + if (typeParamNameEnd != -1) + { + var parameterName = comments.Substring(typeParamNameStart, typeParamNameEnd - typeParamNameStart); + proposedEdits.Add(new DocumentationCommentProposedEdit(new TextSpan(typeParamEndTag + startIndex, 0), parameterName, DocumentationCommentTagType.TypeParam)); + } + + index = typeParamEndTag + "".Length; + } + + while (true) + { + var paramEndTag = comments.IndexOf("", index, StringComparison.Ordinal); + var paramStartTag = comments.IndexOf("", paramNameStart, StringComparison.Ordinal); + if (paramNameEnd != -1) + { + var parameterName = comments.Substring(paramNameStart, paramNameEnd - paramNameStart); + proposedEdits.Add(new DocumentationCommentProposedEdit(new TextSpan(paramEndTag + startIndex, 0), parameterName, DocumentationCommentTagType.Param)); + } + + index = paramEndTag + "".Length; + } + + var returnsEndTag = comments.IndexOf("", index, StringComparison.Ordinal); + if (returnsEndTag != -1) + { + proposedEdits.Add(new DocumentationCommentProposedEdit(new TextSpan(returnsEndTag + startIndex, 0), symbolName: null, DocumentationCommentTagType.Returns)); + } + + while (true) + { + var exceptionEndTag = comments.IndexOf("", index, StringComparison.Ordinal); + var exceptionStartTag = comments.IndexOf("", exceptionNameStart, StringComparison.Ordinal); + if (exceptionNameEnd != -1) + { + var exceptionName = comments.Substring(exceptionNameStart, exceptionNameEnd - exceptionNameStart); + proposedEdits.Add(new DocumentationCommentProposedEdit(new TextSpan(exceptionEndTag + startIndex, 0), exceptionName, DocumentationCommentTagType.Exception)); + } + + index = exceptionEndTag + "".Length; + } + + return new DocumentationCommentProposal(memberNode.ToFullString(), proposedEdits.ToImmutableArray()); + } + + /// + /// Calls into the copilot service to get the pieces for the documentation comment. + /// + private static async Task> GetProposedEditsAsync( + DocumentationCommentProposal proposal, ICopilotCodeAnalysisService copilotService, + ITextSnapshot oldSnapshot, string? indentText, CancellationToken cancellationToken) + { + var list = new List(); + var (documentationCommentDictionary, isQuotaExceeded) = await copilotService.GetDocumentationCommentAsync(proposal, cancellationToken).ConfigureAwait(false); + + // Quietly fail if the quota has been exceeded. + if (isQuotaExceeded) + { + return list; + } + + if (documentationCommentDictionary is null) + { + return list; + } + + if (documentationCommentDictionary.Count == 0) + { + return list; + } + + foreach (var edit in proposal.ProposedEdits) + { + var textSpan = edit.SpanToReplace; + + string? symbolKey = null; + + if (edit.SymbolName is not null) + { + symbolKey = edit.TagType.ToString() + "-" + edit.SymbolName; + } + + var copilotStatement = GetCopilotStatement(documentationCommentDictionary, edit, symbolKey); + + // Just skip this piece of the documentation comment if, for some reason, it is not found. + if (copilotStatement is null) + { + continue; + } + + var proposedEdit = new ProposedEdit(new SnapshotSpan(oldSnapshot, textSpan.Start, textSpan.Length), + AddNewLinesToCopilotText(copilotStatement, indentText, edit.TagType, characterLimit: 120)); + list.Add(proposedEdit); + } + + return list; + + static string? GetCopilotStatement(Dictionary documentationCommentDictionary, DocumentationCommentProposedEdit edit, string? symbolKey) + { + if (edit.TagType == DocumentationCommentTagType.Summary && documentationCommentDictionary.TryGetValue(DocumentationCommentTagType.Summary.ToString(), out var summary) && !string.IsNullOrEmpty(summary)) + { + return summary; + } + else if (edit.TagType == DocumentationCommentTagType.Remarks && documentationCommentDictionary.TryGetValue(DocumentationCommentTagType.Remarks.ToString(), out var remarks) && !string.IsNullOrEmpty(remarks)) + { + return remarks; + } + else if (edit.TagType == DocumentationCommentTagType.TypeParam && documentationCommentDictionary.TryGetValue(symbolKey!, out var typeParam) && !string.IsNullOrEmpty(typeParam)) + { + return typeParam; + } + else if (edit.TagType == DocumentationCommentTagType.Param && documentationCommentDictionary.TryGetValue(symbolKey!, out var param) && !string.IsNullOrEmpty(param)) + { + return param; + } + else if (edit.TagType == DocumentationCommentTagType.Returns && documentationCommentDictionary.TryGetValue(DocumentationCommentTagType.Returns.ToString(), out var returns) && !string.IsNullOrEmpty(returns)) + { + return returns; + } + else if (edit.TagType == DocumentationCommentTagType.Exception && documentationCommentDictionary.TryGetValue(symbolKey!, out var exception) && !string.IsNullOrEmpty(exception)) + { + return exception; + } + + return null; + } + + static string AddNewLinesToCopilotText(string copilotText, string? indentText, DocumentationCommentTagType tagType, int characterLimit) + { + // Double check that the resultant from Copilot does not produce any strings containing new line characters. + copilotText = Regex.Replace(copilotText, @"\r?\n", " "); + var builder = new StringBuilder(); + copilotText = BuildCopilotTextForRemarks(copilotText, indentText, tagType, builder); + + var words = copilotText.Split(' '); + var currentLineLength = 0; + characterLimit -= (indentText!.Length + "/// ".Length); + foreach (var word in words) + { + if (currentLineLength + word.Length >= characterLimit) + { + builder.AppendLine(); + builder.Append(indentText); + builder.Append("/// "); + currentLineLength = 0; + } + + if (currentLineLength > 0) + { + builder.Append(' '); + currentLineLength++; + } + + builder.Append(word); + currentLineLength += word.Length; + } + + return builder.ToString(); + + static string BuildCopilotTextForRemarks(string copilotText, string? indentText, DocumentationCommentTagType tagType, StringBuilder builder) + { + if (tagType is DocumentationCommentTagType.Remarks) + { + builder.AppendLine(); + builder.Append(indentText); + builder.Append("/// "); + builder.Append(copilotText); + builder.Append(""); + copilotText = builder.ToString(); + builder.Clear(); + } + + return copilotText; + } + } + } + + public override Task EnabledAsync(CancellationToken cancel) + { + _enabled = true; + return Task.CompletedTask; + } + + public override Task DisabledAsync(CancellationToken cancel) + { + _enabled = false; + return Task.CompletedTask; + } + } +} diff --git a/src/EditorFeatures/Core/DocumentationComments/DocumentationCommentSuggestion.cs b/src/EditorFeatures/Core/DocumentationComments/DocumentationCommentSuggestion.cs new file mode 100644 index 0000000000000..0d9cad652e085 --- /dev/null +++ b/src/EditorFeatures/Core/DocumentationComments/DocumentationCommentSuggestion.cs @@ -0,0 +1,118 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation 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; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Internal.Log; +using Microsoft.VisualStudio.Language.Proposals; +using Microsoft.VisualStudio.Language.Suggestions; +using Microsoft.VisualStudio.Text; + +namespace Microsoft.CodeAnalysis.DocumentationComments +{ + internal class DocumentationCommentSuggestion(CopilotGenerateDocumentationCommentProvider providerInstance, ProposalBase proposal, + SuggestionManagerBase suggestionManager, VisualStudio.Threading.IAsyncDisposable? intellicodeLineCompletionsDisposable) : SuggestionBase + { + public ProposalBase Proposal { get; } = proposal; + + public SuggestionManagerBase SuggestionManager { get; } = suggestionManager; + + public VisualStudio.Threading.IAsyncDisposable? IntellicodeLineCompletionsDisposable { get; set; } = intellicodeLineCompletionsDisposable; + + public override TipStyle TipStyle => TipStyle.AlwaysShowTip; + + public override EditDisplayStyle EditStyle => EditDisplayStyle.GrayText; + + public override bool HasMultipleSuggestions => false; + + public override event PropertyChangedEventHandler PropertyChanged { add { } remove { } } + + private SuggestionSessionBase? _suggestionSession; + + public override async Task OnAcceptedAsync(SuggestionSessionBase session, ProposalBase originalProposal, ProposalBase currentProposal, ReasonForAccept reason, CancellationToken cancel) + { + var threadingContext = providerInstance.ThreadingContext; + + await threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancel); + await DisposeAsync().ConfigureAwait(false); + Logger.Log(FunctionId.Copilot_Generate_Documentation_Accepted, logLevel: LogLevel.Information); + } + + public override Task OnChangeProposalAsync(SuggestionSessionBase session, ProposalBase originalProposal, ProposalBase currentProposal, bool forward, CancellationToken cancel) + { + return Task.CompletedTask; + } + + public override async Task OnDismissedAsync(SuggestionSessionBase session, ProposalBase? originalProposal, ProposalBase? currentProposal, ReasonForDismiss reason, CancellationToken cancel) + { + var threadingContext = providerInstance.ThreadingContext; + await threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancel); + await ClearSuggestionAsync(reason, cancel).ConfigureAwait(false); + Logger.Log(FunctionId.Copilot_Generate_Documentation_Dismissed, logLevel: LogLevel.Information); + } + + public override Task OnProposalUpdatedAsync(SuggestionSessionBase session, ProposalBase? originalProposal, ProposalBase? currentProposal, ReasonForUpdate reason, VirtualSnapshotPoint caret, CompletionState? completionState, CancellationToken cancel) + { + if (reason.HasFlag(ReasonForUpdate.Diverged)) + { + Logger.Log(FunctionId.Copilot_Generate_Documentation_Diverged, logLevel: LogLevel.Information); + return session.DismissAsync(ReasonForDismiss.DismissedAfterBufferChange, cancel); + } + + return Task.CompletedTask; + } + + public async Task TryDisplaySuggestionAsync(CancellationToken cancellationToken) + { + _suggestionSession = await SuggestionManager.TryDisplaySuggestionAsync(this, cancellationToken).ConfigureAwait(false); + + if (_suggestionSession != null) + { + var success = await TryDisplayProposalAsync(_suggestionSession, cancellationToken).ConfigureAwait(false); + if (success) + { + Logger.Log(FunctionId.Copilot_Generate_Documentation_Displayed, logLevel: LogLevel.Information); + } + } + } + + private async Task TryDisplayProposalAsync(SuggestionSessionBase session, CancellationToken cancellationToken) + { + try + { + await providerInstance.ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + await session.DisplayProposalAsync(Proposal, cancellationToken).ConfigureAwait(false); + return true; + } + catch (OperationCanceledException) + { + Logger.Log(FunctionId.Copilot_Generate_Documentation_Canceled, logLevel: LogLevel.Information); + } + + return false; + } + + private async Task ClearSuggestionAsync(ReasonForDismiss reason, CancellationToken cancellationToken) + { + if (_suggestionSession != null) + { + await _suggestionSession.DismissAsync(reason, cancellationToken).ConfigureAwait(false); + } + + _suggestionSession = null; + await DisposeAsync().ConfigureAwait(false); + } + + private async Task DisposeAsync() + { + if (IntellicodeLineCompletionsDisposable != null) + { + await IntellicodeLineCompletionsDisposable.DisposeAsync().ConfigureAwait(false); + IntellicodeLineCompletionsDisposable = null; + } + } + } +} diff --git a/src/EditorFeatures/Core/EditAndContinue/ActiveStatementTaggerProvider.cs b/src/EditorFeatures/Core/EditAndContinue/ActiveStatementTaggerProvider.cs index 533dabd5e54e8..dfab5f77e1cc3 100644 --- a/src/EditorFeatures/Core/EditAndContinue/ActiveStatementTaggerProvider.cs +++ b/src/EditorFeatures/Core/EditAndContinue/ActiveStatementTaggerProvider.cs @@ -4,8 +4,6 @@ using System; using System.ComponentModel.Composition; -using System.Diagnostics; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor; @@ -18,7 +16,6 @@ using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Tagging; using Microsoft.VisualStudio.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.EditAndContinue; diff --git a/src/EditorFeatures/Core/EditAndContinue/EditAndContinueLanguageService.cs b/src/EditorFeatures/Core/EditAndContinue/EditAndContinueLanguageService.cs index 74948a69c5ad0..34add1bee8489 100644 --- a/src/EditorFeatures/Core/EditAndContinue/EditAndContinueLanguageService.cs +++ b/src/EditorFeatures/Core/EditAndContinue/EditAndContinueLanguageService.cs @@ -378,10 +378,19 @@ public async ValueTask GetUpdatesAsync(ImmutableArray p.FilePath != null && runningProjectPaths.Contains(p.FilePath)).Select(static p => p.Id).ToImmutableHashSet(); var result = await GetDebuggingSession().EmitSolutionUpdateAsync(solution, runningProjectIds, activeStatementSpanProvider, cancellationToken).ConfigureAwait(false); - // Only store the solution if we have any changes to apply, otherwise CommitUpdatesAsync/DiscardUpdatesAsync won't be called. - if (result.ModuleUpdates.Status == ModuleUpdateStatus.Ready) + switch (result.ModuleUpdates.Status) { - _pendingUpdatedDesignTimeSolution = designTimeSolution; + case ModuleUpdateStatus.Ready: + // We have updates to be applied. The debugger will call Commit/Discard on the solution + // based on whether the updates will be applied successfully or not. + _pendingUpdatedDesignTimeSolution = designTimeSolution; + break; + + case ModuleUpdateStatus.None: + // No significant changes have been made. + // Commit the solution to apply any changes in comments that do not generate updates. + _committedDesignTimeSolution = designTimeSolution; + break; } UpdateApplyChangesDiagnostics(result.Diagnostics); diff --git a/src/EditorFeatures/Core/EditAndContinue/PdbMatchingSourceTextProvider.cs b/src/EditorFeatures/Core/EditAndContinue/PdbMatchingSourceTextProvider.cs index 0fc00c9f1f77d..d67a5cfdf7dea 100644 --- a/src/EditorFeatures/Core/EditAndContinue/PdbMatchingSourceTextProvider.cs +++ b/src/EditorFeatures/Core/EditAndContinue/PdbMatchingSourceTextProvider.cs @@ -21,7 +21,9 @@ namespace Microsoft.CodeAnalysis.EditAndContinue; /// [ExportEventListener(WellKnownEventListeners.Workspace, WorkspaceKind.Host), Shared] [Export(typeof(PdbMatchingSourceTextProvider))] -internal sealed class PdbMatchingSourceTextProvider : IEventListener, IEventListenerStoppable, IPdbMatchingSourceTextProvider +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class PdbMatchingSourceTextProvider() : IEventListener, IPdbMatchingSourceTextProvider { private readonly object _guard = new(); @@ -29,21 +31,11 @@ internal sealed class PdbMatchingSourceTextProvider : IEventListener, IE private int _baselineSolutionVersion; private readonly Dictionary _documentsWithChangedLoaderByPath = []; - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public PdbMatchingSourceTextProvider() - { - } - - public void StartListening(Workspace workspace, object serviceOpt) - { - workspace.WorkspaceChanged += WorkspaceChanged; - } + public void StartListening(Workspace workspace) + => workspace.WorkspaceChanged += WorkspaceChanged; public void StopListening(Workspace workspace) - { - workspace.WorkspaceChanged -= WorkspaceChanged; - } + => workspace.WorkspaceChanged -= WorkspaceChanged; private void WorkspaceChanged(object? sender, WorkspaceChangeEventArgs e) { diff --git a/src/EditorFeatures/Core/Editor/GoToAdjacentMemberCommandHandler.cs b/src/EditorFeatures/Core/Editor/GoToAdjacentMemberCommandHandler.cs index 923049a4c1d8b..a4409bace7975 100644 --- a/src/EditorFeatures/Core/Editor/GoToAdjacentMemberCommandHandler.cs +++ b/src/EditorFeatures/Core/Editor/GoToAdjacentMemberCommandHandler.cs @@ -5,12 +5,12 @@ #nullable disable using System; -using System.Collections.Generic; using System.ComponentModel.Composition; using System.Linq; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageService; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Commanding; @@ -103,12 +103,11 @@ private bool ExecuteCommandImpl(EditorCommandArgs args, bool gotoNextMember, Com /// internal static int? GetTargetPosition(ISyntaxFactsService service, SyntaxNode root, int caretPosition, bool next) { - using var pooledMembers = service.GetMethodLevelMembers(root); - var members = pooledMembers.Object; + // Specifies false for discardLargeInstances as these objects commonly exceed the default ArrayBuilder capacity threshold. + using var _ = ArrayBuilder.GetInstance(discardLargeInstances: false, out var members); + service.AddMethodLevelMembers(root, members); if (members.Count == 0) - { return null; - } var starts = members.Select(m => MemberStart(m)).ToArray(); var index = Array.BinarySearch(starts, caretPosition); diff --git a/src/EditorFeatures/Core/Editor/ITextBufferAssociatedViewService.cs b/src/EditorFeatures/Core/Editor/ITextBufferAssociatedViewService.cs index c9c32606f1e80..bdc96aa5d35c3 100644 --- a/src/EditorFeatures/Core/Editor/ITextBufferAssociatedViewService.cs +++ b/src/EditorFeatures/Core/Editor/ITextBufferAssociatedViewService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.ObjectModel; diff --git a/src/EditorFeatures/Core/Editor/ITextUndoHistoryWorkspaceService.cs b/src/EditorFeatures/Core/Editor/ITextUndoHistoryWorkspaceService.cs index 6dbfc7d6bb813..360d2f5c1cbb3 100644 --- a/src/EditorFeatures/Core/Editor/ITextUndoHistoryWorkspaceService.cs +++ b/src/EditorFeatures/Core/Editor/ITextUndoHistoryWorkspaceService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Host; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Operations; diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Aggregator/SettingsAggregator.cs b/src/EditorFeatures/Core/EditorConfigSettings/Aggregator/SettingsAggregator.cs index 2260badd1ab46..72c59049b7fd8 100644 --- a/src/EditorFeatures/Core/EditorConfigSettings/Aggregator/SettingsAggregator.cs +++ b/src/EditorFeatures/Core/EditorConfigSettings/Aggregator/SettingsAggregator.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings; diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProvider.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProvider.cs index f5604f7827400..5939394e80816 100644 --- a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProvider.cs +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProvider.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; using Microsoft.CodeAnalysis.EditorConfig; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using RoslynEnumerableExtensions = Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Extensions.EnumerableExtensions; @@ -19,8 +20,13 @@ internal sealed class AnalyzerSettingsProvider : SettingsProviderBase +internal sealed class AnalyzerSettingsProviderFactory( + Workspace workspace, + IDiagnosticAnalyzerService analyzerService, + IGlobalOptionService globalOptionService) : IWorkspaceSettingsProviderFactory { - private readonly Workspace _workspace = workspace; - private readonly IDiagnosticAnalyzerService _analyzerService = analyzerService; - public ISettingsProvider GetForFile(string filePath) { - var updater = new AnalyzerSettingsUpdater(_workspace, filePath); - return new AnalyzerSettingsProvider(filePath, updater, _workspace, _analyzerService); + var updater = new AnalyzerSettingsUpdater(workspace, filePath); + return new AnalyzerSettingsProvider(filePath, updater, workspace, analyzerService, globalOptionService); } } diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsWorkspaceServiceFactory.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsWorkspaceServiceFactory.cs index b098b95760e16..7945e987215b1 100644 --- a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsWorkspaceServiceFactory.cs +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsWorkspaceServiceFactory.cs @@ -8,16 +8,17 @@ using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.Analyzer; [ExportWorkspaceServiceFactory(typeof(IWorkspaceSettingsProviderFactory)), Shared] [method: ImportingConstructor] [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] -internal class AnalyzerSettingsWorkspaceServiceFactory(IDiagnosticAnalyzerService analyzerService) : IWorkspaceServiceFactory +internal sealed class AnalyzerSettingsWorkspaceServiceFactory( + IDiagnosticAnalyzerService analyzerService, + IGlobalOptionService globalOptionService) : IWorkspaceServiceFactory { - private readonly IDiagnosticAnalyzerService _analyzerService = analyzerService; - public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) - => new AnalyzerSettingsProviderFactory(workspaceServices.Workspace, _analyzerService); + => new AnalyzerSettingsProviderFactory(workspaceServices.Workspace, analyzerService, globalOptionService); } diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Updater/NamingStyles/SourceTextExtensions.cs b/src/EditorFeatures/Core/EditorConfigSettings/Updater/NamingStyles/SourceTextExtensions.cs index bcfccb834d896..9bb6b98bfb8dc 100644 --- a/src/EditorFeatures/Core/EditorConfigSettings/Updater/NamingStyles/SourceTextExtensions.cs +++ b/src/EditorFeatures/Core/EditorConfigSettings/Updater/NamingStyles/SourceTextExtensions.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; using System.Text; using Microsoft.CodeAnalysis.CodeStyle; diff --git a/src/EditorFeatures/Core/EncapsulateField/AbstractEncapsulateFieldCommandHandler.cs b/src/EditorFeatures/Core/EncapsulateField/AbstractEncapsulateFieldCommandHandler.cs index 71916add99162..63fac5bc1056b 100644 --- a/src/EditorFeatures/Core/EncapsulateField/AbstractEncapsulateFieldCommandHandler.cs +++ b/src/EditorFeatures/Core/EncapsulateField/AbstractEncapsulateFieldCommandHandler.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Notification; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Text; @@ -18,7 +17,6 @@ using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; using Microsoft.VisualStudio.Text.Operations; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.EncapsulateField; diff --git a/src/EditorFeatures/Core/Extensibility/Commands/ExportInteractiveCommandAttribute.cs b/src/EditorFeatures/Core/Extensibility/Commands/ExportInteractiveCommandAttribute.cs index 1d49a1309b221..0cc7cbe0e53e5 100644 --- a/src/EditorFeatures/Core/Extensibility/Commands/ExportInteractiveCommandAttribute.cs +++ b/src/EditorFeatures/Core/Extensibility/Commands/ExportInteractiveCommandAttribute.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.ComponentModel.Composition; diff --git a/src/EditorFeatures/Core/Extensibility/Commands/PredefinedCommandHandlerNames.cs b/src/EditorFeatures/Core/Extensibility/Commands/PredefinedCommandHandlerNames.cs index 43a3d4f969a00..ae0e0f428e240 100644 --- a/src/EditorFeatures/Core/Extensibility/Commands/PredefinedCommandHandlerNames.cs +++ b/src/EditorFeatures/Core/Extensibility/Commands/PredefinedCommandHandlerNames.cs @@ -2,9 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - -using Microsoft.CodeAnalysis.Host; using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion; namespace Microsoft.CodeAnalysis.Editor; diff --git a/src/EditorFeatures/Core/Extensibility/Completion/ExportCompletionProviderAttribute.cs b/src/EditorFeatures/Core/Extensibility/Completion/ExportCompletionProviderAttribute.cs index 48be90a3f2da5..22dfaf100cbf3 100644 --- a/src/EditorFeatures/Core/Extensibility/Completion/ExportCompletionProviderAttribute.cs +++ b/src/EditorFeatures/Core/Extensibility/Completion/ExportCompletionProviderAttribute.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.ComponentModel.Composition; using Microsoft.CodeAnalysis.Completion; diff --git a/src/EditorFeatures/Core/Extensibility/Completion/PredefinedCompletionProviderNames.cs b/src/EditorFeatures/Core/Extensibility/Completion/PredefinedCompletionProviderNames.cs index cdd08a294d4f4..8b5c73cc8c480 100644 --- a/src/EditorFeatures/Core/Extensibility/Completion/PredefinedCompletionProviderNames.cs +++ b/src/EditorFeatures/Core/Extensibility/Completion/PredefinedCompletionProviderNames.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.Editor; internal static class PredefinedCompletionProviderNames diff --git a/src/EditorFeatures/Core/Extensibility/Composition/IContentTypeMetadata.cs b/src/EditorFeatures/Core/Extensibility/Composition/IContentTypeMetadata.cs index fa25e7c01c22d..f1830023b5795 100644 --- a/src/EditorFeatures/Core/Extensibility/Composition/IContentTypeMetadata.cs +++ b/src/EditorFeatures/Core/Extensibility/Composition/IContentTypeMetadata.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; namespace Microsoft.CodeAnalysis.Editor; diff --git a/src/EditorFeatures/Core/Extensibility/NavigationBar/AbstractEditorNavigationBarItemService.cs b/src/EditorFeatures/Core/Extensibility/NavigationBar/AbstractEditorNavigationBarItemService.cs index 67a2922a8d923..cb4b407e8de55 100644 --- a/src/EditorFeatures/Core/Extensibility/NavigationBar/AbstractEditorNavigationBarItemService.cs +++ b/src/EditorFeatures/Core/Extensibility/NavigationBar/AbstractEditorNavigationBarItemService.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; -using Roslyn.Utilities; using static Microsoft.CodeAnalysis.NavigationBar.RoslynNavigationBarItem; namespace Microsoft.CodeAnalysis.Editor.Extensibility.NavigationBar; diff --git a/src/EditorFeatures/Core/Extensibility/NavigationBar/INavigationBarControllerFactoryService.cs b/src/EditorFeatures/Core/Extensibility/NavigationBar/INavigationBarControllerFactoryService.cs index f88d4818bf1ac..3067a0557e4cd 100644 --- a/src/EditorFeatures/Core/Extensibility/NavigationBar/INavigationBarControllerFactoryService.cs +++ b/src/EditorFeatures/Core/Extensibility/NavigationBar/INavigationBarControllerFactoryService.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.VisualStudio.Text; diff --git a/src/EditorFeatures/Core/Extensibility/NavigationBar/NavigationBarAutomationStrings.cs b/src/EditorFeatures/Core/Extensibility/NavigationBar/NavigationBarAutomationStrings.cs index 7aa89660ee9a0..6ec4f248283ff 100644 --- a/src/EditorFeatures/Core/Extensibility/NavigationBar/NavigationBarAutomationStrings.cs +++ b/src/EditorFeatures/Core/Extensibility/NavigationBar/NavigationBarAutomationStrings.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.Editor; internal static class NavigationBarAutomationStrings diff --git a/src/EditorFeatures/Core/Extensibility/NavigationBar/NavigationBarProjectItem.cs b/src/EditorFeatures/Core/Extensibility/NavigationBar/NavigationBarProjectItem.cs index 83659cf4529d9..7f61e907bc911 100644 --- a/src/EditorFeatures/Core/Extensibility/NavigationBar/NavigationBarProjectItem.cs +++ b/src/EditorFeatures/Core/Extensibility/NavigationBar/NavigationBarProjectItem.cs @@ -3,8 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Immutable; -using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Editor; diff --git a/src/EditorFeatures/Core/Extensibility/SignatureHelp/ISignatureHelpPresenterSession.cs b/src/EditorFeatures/Core/Extensibility/SignatureHelp/ISignatureHelpPresenterSession.cs index b5fcb1a79acd2..a3f1c82d76382 100644 --- a/src/EditorFeatures/Core/Extensibility/SignatureHelp/ISignatureHelpPresenterSession.cs +++ b/src/EditorFeatures/Core/Extensibility/SignatureHelp/ISignatureHelpPresenterSession.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using Microsoft.CodeAnalysis.SignatureHelp; diff --git a/src/EditorFeatures/Core/Extensibility/SignatureHelp/PredefinedSignatureHelpPresenterNames.cs b/src/EditorFeatures/Core/Extensibility/SignatureHelp/PredefinedSignatureHelpPresenterNames.cs index 169faddbb2498..2f2c7d3456c63 100644 --- a/src/EditorFeatures/Core/Extensibility/SignatureHelp/PredefinedSignatureHelpPresenterNames.cs +++ b/src/EditorFeatures/Core/Extensibility/SignatureHelp/PredefinedSignatureHelpPresenterNames.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.Editor; internal static class PredefinedSignatureHelpPresenterNames diff --git a/src/EditorFeatures/Core/Extensibility/SignatureHelp/SignatureHelpItemEventArgs.cs b/src/EditorFeatures/Core/Extensibility/SignatureHelp/SignatureHelpItemEventArgs.cs index a57372b3b5a38..757482db4c928 100644 --- a/src/EditorFeatures/Core/Extensibility/SignatureHelp/SignatureHelpItemEventArgs.cs +++ b/src/EditorFeatures/Core/Extensibility/SignatureHelp/SignatureHelpItemEventArgs.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.SignatureHelp; diff --git a/src/EditorFeatures/Core/Extensions/GlyphExtensions.cs b/src/EditorFeatures/Core/Extensions/GlyphExtensions.cs index 372ebdbecb8ab..313fd19a8b05e 100644 --- a/src/EditorFeatures/Core/Extensions/GlyphExtensions.cs +++ b/src/EditorFeatures/Core/Extensions/GlyphExtensions.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.VisualStudio.Imaging.Interop; diff --git a/src/EditorFeatures/Core/Extensions/LSPExtensions.cs b/src/EditorFeatures/Core/Extensions/LSPExtensions.cs index 8a8ee7573819f..f202dfeb6a51d 100644 --- a/src/EditorFeatures/Core/Extensions/LSPExtensions.cs +++ b/src/EditorFeatures/Core/Extensions/LSPExtensions.cs @@ -23,7 +23,7 @@ public static Roslyn.Text.Adornments.ClassifiedTextElement ToLSPElement(this Vis public static Roslyn.Text.Adornments.ContainerElement ToLSPElement(this VisualStudio.Text.Adornments.ContainerElement element) => new((Roslyn.Text.Adornments.ContainerElementStyle)element.Style, element.Elements.Select(ToLSPElement)); - private static object? ToLSPElement(object? value) + private static object ToLSPElement(object value) => value switch { VisualStudio.Core.Imaging.ImageId imageId => imageId.ToLSPImageId(), @@ -31,7 +31,6 @@ public static Roslyn.Text.Adornments.ContainerElement ToLSPElement(this VisualSt VisualStudio.Text.Adornments.ContainerElement element => element.ToLSPElement(), VisualStudio.Text.Adornments.ClassifiedTextElement element => element.ToLSPElement(), VisualStudio.Text.Adornments.ClassifiedTextRun run => run.ToLSPRun(), - _ => value, }; } diff --git a/src/EditorFeatures/Core/ExternalAccess/IntelliCode/IntentProcessor.cs b/src/EditorFeatures/Core/ExternalAccess/IntelliCode/IntentProcessor.cs index 13af115a66219..61960e93289b1 100644 --- a/src/EditorFeatures/Core/ExternalAccess/IntelliCode/IntentProcessor.cs +++ b/src/EditorFeatures/Core/ExternalAccess/IntelliCode/IntentProcessor.cs @@ -12,7 +12,6 @@ using Microsoft.CodeAnalysis.Features.Intents; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/EditorFeatures/Core/ExternalAccess/UnitTestGenerator/Api/UnitTestGeneratorOrganizeImportsAccessor.cs b/src/EditorFeatures/Core/ExternalAccess/UnitTestGenerator/Api/UnitTestGeneratorOrganizeImportsAccessor.cs index 0dc02e545b49c..05e7e81ca84c3 100644 --- a/src/EditorFeatures/Core/ExternalAccess/UnitTestGenerator/Api/UnitTestGeneratorOrganizeImportsAccessor.cs +++ b/src/EditorFeatures/Core/ExternalAccess/UnitTestGenerator/Api/UnitTestGeneratorOrganizeImportsAccessor.cs @@ -7,7 +7,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.OrganizeImports; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/EditorFeatures/Core/ExternalAccess/UnitTestGenerator/Api/WrappedAddImportFixData.cs b/src/EditorFeatures/Core/ExternalAccess/UnitTestGenerator/Api/WrappedAddImportFixData.cs index 327fc9d38048a..209c4bc86d2f2 100644 --- a/src/EditorFeatures/Core/ExternalAccess/UnitTestGenerator/Api/WrappedAddImportFixData.cs +++ b/src/EditorFeatures/Core/ExternalAccess/UnitTestGenerator/Api/WrappedAddImportFixData.cs @@ -5,7 +5,6 @@ using System.Collections.Immutable; using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTestGenerator.Api; diff --git a/src/EditorFeatures/Core/ExternalAccess/UnitTesting/UnitTestingReferencesService.cs b/src/EditorFeatures/Core/ExternalAccess/UnitTesting/UnitTestingReferencesService.cs index 48a5af7b6ef01..90cf99a24d3fd 100644 --- a/src/EditorFeatures/Core/ExternalAccess/UnitTesting/UnitTestingReferencesService.cs +++ b/src/EditorFeatures/Core/ExternalAccess/UnitTesting/UnitTestingReferencesService.cs @@ -2,11 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Generic; using System.Collections.Immutable; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeLens; diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptEditorInlineRenameService.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptEditorInlineRenameService.cs index 4d5c099549a6f..38bdbecd6ffce 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptEditorInlineRenameService.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptEditorInlineRenameService.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; diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptInlineRenameReplacementInfo.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptInlineRenameReplacementInfo.cs index 8bae295f55bed..f3aecfe5ec102 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptInlineRenameReplacementInfo.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptInlineRenameReplacementInfo.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.Linq; using Microsoft.CodeAnalysis.Editor; diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptAsynchronousTaggerProvider.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptAsynchronousTaggerProvider.cs index 103a05ea0bc92..c1ae35460bc68 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptAsynchronousTaggerProvider.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptAsynchronousTaggerProvider.cs @@ -3,10 +3,8 @@ // See the LICENSE file in the project root for more information. using System; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Editor.Tagging; using Microsoft.CodeAnalysis.Shared.TestHooks; -using Microsoft.CodeAnalysis.Workspaces; using Microsoft.VisualStudio.Text.Tagging; namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api; @@ -14,31 +12,14 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api; internal abstract class VSTypeScriptAsynchronousTaggerProvider : AsynchronousViewTaggerProvider where TTag : ITag { - [Obsolete("Use constructor that takes ITextBufferVisibilityTracker. Use `[Import(AllowDefault = true)] ITextBufferVisibilityTracker? visibilityTracker`")] - protected VSTypeScriptAsynchronousTaggerProvider( - IThreadingContext threadingContext, - IAsynchronousOperationListenerProvider asyncListenerProvider, - VSTypeScriptGlobalOptions globalOptions) - : this( - threadingContext, - globalOptions, - visibilityTracker: null, - asyncListenerProvider) - { - } - - [Obsolete("Use constructor that takes a single TaggerHost")] - protected VSTypeScriptAsynchronousTaggerProvider( - IThreadingContext threadingContext, - VSTypeScriptGlobalOptions globalOptions, - ITextBufferVisibilityTracker? visibilityTracker, - IAsynchronousOperationListenerProvider asyncListenerProvider) - : base(new TaggerHost(threadingContext, globalOptions.Service, visibilityTracker, asyncListenerProvider), FeatureAttribute.Classification) + [Obsolete("Use constructor that takes VSTypeScriptTaggerHost")] + protected VSTypeScriptAsynchronousTaggerProvider(TaggerHost taggerHost) + : base(taggerHost, FeatureAttribute.Classification) { } - protected VSTypeScriptAsynchronousTaggerProvider(TaggerHost taggerHost) - : base(taggerHost, FeatureAttribute.Classification) + protected VSTypeScriptAsynchronousTaggerProvider(VSTypeScriptTaggerHost taggerHost) + : base(taggerHost.UnderlyingObject, FeatureAttribute.Classification) { } } diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptDocumentSpan.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptDocumentSpan.cs index bb66de14574dc..bce95d6da5fca 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptDocumentSpan.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptDocumentSpan.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api; diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameInfo.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameInfo.cs index 5e859b093ee6f..ea263c1cd0251 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameInfo.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameInfo.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; diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameLocationWrapper.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameLocationWrapper.cs index 73be95096df28..88855108f7938 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameLocationWrapper.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameLocationWrapper.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Text; diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameReplacementWrapper.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameReplacementWrapper.cs index 345fb9de25f20..2d2f88c4fd3ce 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameReplacementWrapper.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameReplacementWrapper.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Text; diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptTaggerHost.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptTaggerHost.cs new file mode 100644 index 0000000000000..a5d1e79337dbd --- /dev/null +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptTaggerHost.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; +using System.Composition; +using Microsoft.CodeAnalysis.Editor.Tagging; +using Microsoft.CodeAnalysis.Host.Mef; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api; + +[Export(typeof(VSTypeScriptTaggerHost)), Shared] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class VSTypeScriptTaggerHost(TaggerHost underlyingObject) +{ + internal TaggerHost UnderlyingObject { get; } = underlyingObject; +} diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptEditorInlineRenameService.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptEditorInlineRenameService.cs index aa32797addd49..06748d0f67d8d 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptEditorInlineRenameService.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptEditorInlineRenameService.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.Editor.Implementation.InlineRename; using Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript; diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptInProcLanguageClient.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptInProcLanguageClient.cs index 59cf758bf0fc7..db9e62e01055b 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptInProcLanguageClient.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptInProcLanguageClient.cs @@ -18,7 +18,6 @@ using Microsoft.VisualStudio.Utilities; using Newtonsoft.Json; using Roslyn.LanguageServer.Protocol; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript; diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptInlineRenameReplacementKindHelpers.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptInlineRenameReplacementKindHelpers.cs index 41931120f1da6..93e18faa3c03e 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptInlineRenameReplacementKindHelpers.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptInlineRenameReplacementKindHelpers.cs @@ -2,11 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript; diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptRequestExecutionQueueProvider.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptRequestExecutionQueueProvider.cs index d4c90787529e1..498df4c794f6a 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptRequestExecutionQueueProvider.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptRequestExecutionQueueProvider.cs @@ -7,7 +7,6 @@ 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; diff --git a/src/EditorFeatures/Core/FindReferences/FindReferencesCommandHandler.cs b/src/EditorFeatures/Core/FindReferences/FindReferencesCommandHandler.cs index 439de5926d51c..7b81483e9d54a 100644 --- a/src/EditorFeatures/Core/FindReferences/FindReferencesCommandHandler.cs +++ b/src/EditorFeatures/Core/FindReferences/FindReferencesCommandHandler.cs @@ -23,7 +23,6 @@ using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; using Microsoft.VisualStudio.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.FindReferences; diff --git a/src/EditorFeatures/Core/Formatting/FormatCommandHandler.cs b/src/EditorFeatures/Core/Formatting/FormatCommandHandler.cs index 77b4e7623910c..89658c823fcaa 100644 --- a/src/EditorFeatures/Core/Formatting/FormatCommandHandler.cs +++ b/src/EditorFeatures/Core/Formatting/FormatCommandHandler.cs @@ -4,14 +4,12 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.ComponentModel.Composition; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Formatting.Rules; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; @@ -26,7 +24,6 @@ using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; using Microsoft.VisualStudio.Text.Operations; using Microsoft.VisualStudio.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Formatting; diff --git a/src/EditorFeatures/Core/GoToDefinition/AbstractGoToCommandHandler`2.cs b/src/EditorFeatures/Core/GoToDefinition/AbstractGoToCommandHandler`2.cs index a93e35b1372d2..b8ce01e14c998 100644 --- a/src/EditorFeatures/Core/GoToDefinition/AbstractGoToCommandHandler`2.cs +++ b/src/EditorFeatures/Core/GoToDefinition/AbstractGoToCommandHandler`2.cs @@ -103,7 +103,7 @@ public bool ExecuteCommand(TCommandArgs args, CommandExecutionContext context) if (service == null) return false; - Roslyn.Utilities.Contract.ThrowIfNull(document); + Contract.ThrowIfNull(document); // cancel any prior find-refs that might be in progress. _cancellationTokenSource.Cancel(); diff --git a/src/EditorFeatures/Core/GoToDefinition/GoToDefinitionCommandHandler.cs b/src/EditorFeatures/Core/GoToDefinition/GoToDefinitionCommandHandler.cs index 9635cf19695ee..427531e14a9f6 100644 --- a/src/EditorFeatures/Core/GoToDefinition/GoToDefinitionCommandHandler.cs +++ b/src/EditorFeatures/Core/GoToDefinition/GoToDefinitionCommandHandler.cs @@ -12,7 +12,6 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Navigation; using Microsoft.CodeAnalysis.Notification; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Text; @@ -31,15 +30,11 @@ namespace Microsoft.CodeAnalysis.GoToDefinition; [method: ImportingConstructor] [method: SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] internal class GoToDefinitionCommandHandler( - IGlobalOptionService globalOptionService, IThreadingContext threadingContext, - IUIThreadOperationExecutor executor, IAsynchronousOperationListenerProvider listenerProvider) : ICommandHandler { - private readonly IGlobalOptionService _globalOptionService = globalOptionService; private readonly IThreadingContext _threadingContext = threadingContext; - private readonly IUIThreadOperationExecutor _executor = executor; private readonly IAsynchronousOperationListener _listener = listenerProvider.GetListener(FeatureAttribute.GoToDefinition); public string DisplayName => EditorFeaturesResources.Go_to_Definition; diff --git a/src/EditorFeatures/Core/Host/IPreviewDialogService.cs b/src/EditorFeatures/Core/Host/IPreviewDialogService.cs index 66e05ac12eae9..d8c999ecbacf1 100644 --- a/src/EditorFeatures/Core/Host/IPreviewDialogService.cs +++ b/src/EditorFeatures/Core/Host/IPreviewDialogService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.Editor.Host; diff --git a/src/EditorFeatures/Core/Host/IPreviewPaneService.cs b/src/EditorFeatures/Core/Host/IPreviewPaneService.cs index 33ec7c74d8bb1..817006e99a8c8 100644 --- a/src/EditorFeatures/Core/Host/IPreviewPaneService.cs +++ b/src/EditorFeatures/Core/Host/IPreviewPaneService.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 Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Host; diff --git a/src/EditorFeatures/Core/ICommandHandlerServiceFactory.cs b/src/EditorFeatures/Core/ICommandHandlerServiceFactory.cs index 6913532ac170f..c58fcb773b46b 100644 --- a/src/EditorFeatures/Core/ICommandHandlerServiceFactory.cs +++ b/src/EditorFeatures/Core/ICommandHandlerServiceFactory.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; namespace Microsoft.CodeAnalysis.Editor; diff --git a/src/EditorFeatures/Core/IContentTypeLanguageService.cs b/src/EditorFeatures/Core/IContentTypeLanguageService.cs index c2b38ba6c8574..6b386953e392e 100644 --- a/src/EditorFeatures/Core/IContentTypeLanguageService.cs +++ b/src/EditorFeatures/Core/IContentTypeLanguageService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Host; using Microsoft.VisualStudio.Utilities; diff --git a/src/EditorFeatures/Core/IInlineRenameSession.cs b/src/EditorFeatures/Core/IInlineRenameSession.cs index f758c652b4f75..a7e52195f24dd 100644 --- a/src/EditorFeatures/Core/IInlineRenameSession.cs +++ b/src/EditorFeatures/Core/IInlineRenameSession.cs @@ -4,7 +4,6 @@ #nullable disable -using System.Threading; using System.Threading.Tasks; using Microsoft.VisualStudio.Utilities; diff --git a/src/EditorFeatures/Core/IIntellisensePresenterSession.cs b/src/EditorFeatures/Core/IIntellisensePresenterSession.cs index 23470bb1f5756..37e532cb63c51 100644 --- a/src/EditorFeatures/Core/IIntellisensePresenterSession.cs +++ b/src/EditorFeatures/Core/IIntellisensePresenterSession.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.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; diff --git a/src/EditorFeatures/Core/IRefactorNotifyService.cs b/src/EditorFeatures/Core/IRefactorNotifyService.cs index 4c420434982ad..d14381d06bf20 100644 --- a/src/EditorFeatures/Core/IRefactorNotifyService.cs +++ b/src/EditorFeatures/Core/IRefactorNotifyService.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; namespace Microsoft.CodeAnalysis.Editor; diff --git a/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.InlineRenameLocationSet.cs b/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.InlineRenameLocationSet.cs index edf97e98f5c60..25078c2b74754 100644 --- a/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.InlineRenameLocationSet.cs +++ b/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.InlineRenameLocationSet.cs @@ -7,8 +7,8 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Rename; +using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename; @@ -35,7 +35,7 @@ public InlineRenameLocationSet( private InlineRenameLocation ConvertLocation(RenameLocation location) { return new InlineRenameLocation( - _renameLocationSet.Solution.GetDocument(location.DocumentId), location.Location.SourceSpan); + _renameLocationSet.Solution.GetRequiredDocument(location.DocumentId), location.Location.SourceSpan); } public async Task GetReplacementsAsync( diff --git a/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.SymbolRenameInfo.cs b/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.SymbolRenameInfo.cs index 84ce9c84ad181..8808c07537a33 100644 --- a/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.SymbolRenameInfo.cs +++ b/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.SymbolRenameInfo.cs @@ -9,7 +9,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Rename; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RefactoringWithCommandHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RefactoringWithCommandHandler.cs index 7420b423c5e84..c578b382308c2 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RefactoringWithCommandHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RefactoringWithCommandHandler.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 Microsoft.CodeAnalysis.InlineRename; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text.Editor.Commanding; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs index 0a8cd1fe5cb12..fbadb6588e48f 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs @@ -8,7 +8,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.BackgroundWorkIndicator; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; -using Microsoft.CodeAnalysis.InlineRename; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; diff --git a/src/EditorFeatures/Core/InlineRename/IEditorInlineRenameService.cs b/src/EditorFeatures/Core/InlineRename/IEditorInlineRenameService.cs index be4c7530fcfda..377b5f34722a4 100644 --- a/src/EditorFeatures/Core/InlineRename/IEditorInlineRenameService.cs +++ b/src/EditorFeatures/Core/InlineRename/IEditorInlineRenameService.cs @@ -2,19 +2,15 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.Implementation.InlineRename; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Rename; using Microsoft.CodeAnalysis.Rename.ConflictEngine; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor; @@ -164,7 +160,7 @@ internal interface IInlineRenameInfo /// Provides the reason that can be displayed to the user if the entity at the selected /// location cannot be renamed. /// - string LocalizedErrorMessage { get; } + string? LocalizedErrorMessage { get; } /// /// The span of the entity that is being renamed. diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameService.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameService.cs index 7697a502b5e02..c34351edb50be 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameService.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameService.cs @@ -20,7 +20,6 @@ using Microsoft.CodeAnalysis.Text.Shared.Extensions; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename; diff --git a/src/EditorFeatures/Core/InlineRename/Taggers/RenameTagger.cs b/src/EditorFeatures/Core/InlineRename/Taggers/RenameTagger.cs index e7c4f32d22cde..c03e5b3c5c080 100644 --- a/src/EditorFeatures/Core/InlineRename/Taggers/RenameTagger.cs +++ b/src/EditorFeatures/Core/InlineRename/Taggers/RenameTagger.cs @@ -5,7 +5,6 @@ using Microsoft.CodeAnalysis.Editor.Implementation.InlineRename.HighlightTags; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Tagging; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename; diff --git a/src/EditorFeatures/Core/IntelliSense/AbstractController.cs b/src/EditorFeatures/Core/IntelliSense/AbstractController.cs index b4265f3b01c70..5d67f48531cde 100644 --- a/src/EditorFeatures/Core/IntelliSense/AbstractController.cs +++ b/src/EditorFeatures/Core/IntelliSense/AbstractController.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; -using Roslyn.Utilities; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using System.Threading.Tasks; diff --git a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CommitManager.cs b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CommitManager.cs index 7d4b4c67a47bc..cd0abaf590d4b 100644 --- a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CommitManager.cs +++ b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CommitManager.cs @@ -278,11 +278,11 @@ private AsyncCompletionData.CommitResult Commit( updatedCurrentSnapshot = edit.Apply(); } - if (change.NewPosition.HasValue) + if (change.NewSelection.HasValue) { - // Roslyn knows how to position the caret in the snapshot we just created. - // If there were more edits made by extensions, TryMoveCaretToAndEnsureVisible maps the snapshot point to the most recent one. - view.TryMoveCaretToAndEnsureVisible(new SnapshotPoint(updatedCurrentSnapshot, change.NewPosition.Value)); + // Roslyn knows how to set the selection in the snapshot we just created. + // If there were more edits made by extensions, TrySetSelectionAndEnsureVisible maps the snapshot point to the most recent one. + view.TrySetSelectionAndEnsureVisible(new SnapshotSpan(updatedCurrentSnapshot, change.NewSelection.Value.ToSpan())); } else { diff --git a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CompletionSource.cs b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CompletionSource.cs index 2908b93d0f156..631cd5208e197 100644 --- a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CompletionSource.cs +++ b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CompletionSource.cs @@ -21,6 +21,7 @@ using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text.Shared.Extensions; +using Microsoft.CodeAnalysis.Threading; using Microsoft.VisualStudio.Core.Imaging; using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion; using Microsoft.VisualStudio.Text; diff --git a/src/EditorFeatures/Core/IntelliSense/ISession.cs b/src/EditorFeatures/Core/IntelliSense/ISession.cs index e1b777b77937c..fb224283e8f36 100644 --- a/src/EditorFeatures/Core/IntelliSense/ISession.cs +++ b/src/EditorFeatures/Core/IntelliSense/ISession.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Threading.Tasks; namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense; diff --git a/src/EditorFeatures/Core/IntelliSense/QuickInfo/Model.cs b/src/EditorFeatures/Core/IntelliSense/QuickInfo/Model.cs index bfc1378a802b6..8829f6c01f392 100644 --- a/src/EditorFeatures/Core/IntelliSense/QuickInfo/Model.cs +++ b/src/EditorFeatures/Core/IntelliSense/QuickInfo/Model.cs @@ -2,13 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.QuickInfo; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text.Shared.Extensions; using Microsoft.VisualStudio.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo; diff --git a/src/EditorFeatures/Core/IntelliSense/QuickInfo/QuickInfoSourceProvider.QuickInfoSource.cs b/src/EditorFeatures/Core/IntelliSense/QuickInfo/QuickInfoSourceProvider.QuickInfoSource.cs index f7e8b4c1764ee..57019ea4d2bac 100644 --- a/src/EditorFeatures/Core/IntelliSense/QuickInfo/QuickInfoSourceProvider.QuickInfoSource.cs +++ b/src/EditorFeatures/Core/IntelliSense/QuickInfo/QuickInfoSourceProvider.QuickInfoSource.cs @@ -22,7 +22,6 @@ using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Utilities; -using Roslyn.Utilities; using IntellisenseQuickInfoItem = Microsoft.VisualStudio.Language.Intellisense.QuickInfoItem; using Microsoft.CodeAnalysis.Editor.InlineRename; diff --git a/src/EditorFeatures/Core/IntelliSense/Session.cs b/src/EditorFeatures/Core/IntelliSense/Session.cs index e3c7a1bdb52df..17a8bf6f8f876 100644 --- a/src/EditorFeatures/Core/IntelliSense/Session.cs +++ b/src/EditorFeatures/Core/IntelliSense/Session.cs @@ -7,7 +7,6 @@ using System; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense; diff --git a/src/EditorFeatures/Core/Intents/DeleteParameterIntentProvider.cs b/src/EditorFeatures/Core/Intents/DeleteParameterIntentProvider.cs index 403c3981ef0d8..1b685db55cba0 100644 --- a/src/EditorFeatures/Core/Intents/DeleteParameterIntentProvider.cs +++ b/src/EditorFeatures/Core/Intents/DeleteParameterIntentProvider.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.ChangeSignature; using Microsoft.CodeAnalysis.Features.Intents; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; diff --git a/src/EditorFeatures/Core/Intents/RenameIntentProvider.cs b/src/EditorFeatures/Core/Intents/RenameIntentProvider.cs index 04c4895e01e1e..3e4a1972ad4d5 100644 --- a/src/EditorFeatures/Core/Intents/RenameIntentProvider.cs +++ b/src/EditorFeatures/Core/Intents/RenameIntentProvider.cs @@ -13,7 +13,6 @@ using Microsoft.CodeAnalysis.Rename; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.EditorFeatures.Intents; diff --git a/src/EditorFeatures/Core/Interactive/ISendToInteractiveSubmissionProvider.cs b/src/EditorFeatures/Core/Interactive/ISendToInteractiveSubmissionProvider.cs index 8a9dfa1cd9d42..f583c4ab6ef08 100644 --- a/src/EditorFeatures/Core/Interactive/ISendToInteractiveSubmissionProvider.cs +++ b/src/EditorFeatures/Core/Interactive/ISendToInteractiveSubmissionProvider.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Editor.Commanding; using System.Threading; diff --git a/src/EditorFeatures/Core/Interactive/InteractiveSession.cs b/src/EditorFeatures/Core/Interactive/InteractiveSession.cs index 8b4ee5b63197d..47aef36e9a97c 100644 --- a/src/EditorFeatures/Core/Interactive/InteractiveSession.cs +++ b/src/EditorFeatures/Core/Interactive/InteractiveSession.cs @@ -26,6 +26,7 @@ namespace Microsoft.CodeAnalysis.Interactive; using InteractiveHost::Microsoft.CodeAnalysis.Interactive; using Microsoft.CodeAnalysis.Collections; +using Microsoft.CodeAnalysis.Threading; using RelativePathResolver = Scripting::Microsoft.CodeAnalysis.RelativePathResolver; internal sealed class InteractiveSession : IDisposable diff --git a/src/EditorFeatures/Core/Interactive/InteractiveWorkspace.cs b/src/EditorFeatures/Core/Interactive/InteractiveWorkspace.cs index 4a00dd65a66f7..0814b5074e3f7 100644 --- a/src/EditorFeatures/Core/Interactive/InteractiveWorkspace.cs +++ b/src/EditorFeatures/Core/Interactive/InteractiveWorkspace.cs @@ -5,7 +5,6 @@ using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Interactive; diff --git a/src/EditorFeatures/Core/KeywordHighlighting/HighlighterViewTaggerProvider.cs b/src/EditorFeatures/Core/KeywordHighlighting/HighlighterViewTaggerProvider.cs index 96c2edeeaaa96..ce6ad983f656f 100644 --- a/src/EditorFeatures/Core/KeywordHighlighting/HighlighterViewTaggerProvider.cs +++ b/src/EditorFeatures/Core/KeywordHighlighting/HighlighterViewTaggerProvider.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.ComponentModel.Composition; @@ -16,6 +14,7 @@ using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.KeywordHighlighting; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text.Shared.Extensions; @@ -23,7 +22,6 @@ using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Tagging; using Microsoft.VisualStudio.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.Highlighting; @@ -101,7 +99,7 @@ protected override async Task ProduceTagsAsync( using (Logger.LogBlock(FunctionId.Tagger_Highlighter_TagProducer_ProduceTags, cancellationToken)) using (s_listPool.GetPooledObject(out var highlights)) { - var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); _highlightingService.AddHighlights(root, position, highlights, cancellationToken); diff --git a/src/EditorFeatures/Core/KeywordHighlighting/KeywordHighlightTag.cs b/src/EditorFeatures/Core/KeywordHighlighting/KeywordHighlightTag.cs index fa1900e27a55d..e4f3ec32d1a19 100644 --- a/src/EditorFeatures/Core/KeywordHighlighting/KeywordHighlightTag.cs +++ b/src/EditorFeatures/Core/KeywordHighlighting/KeywordHighlightTag.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Editor.Shared.Tagging; namespace Microsoft.CodeAnalysis.Editor.Implementation.Highlighting; diff --git a/src/EditorFeatures/Core/LanguageServer/AlwaysActiveLanguageClientEventListener.cs b/src/EditorFeatures/Core/LanguageServer/AlwaysActiveLanguageClientEventListener.cs index c94dee1607695..bd4dcbb58a21f 100644 --- a/src/EditorFeatures/Core/LanguageServer/AlwaysActiveLanguageClientEventListener.cs +++ b/src/EditorFeatures/Core/LanguageServer/AlwaysActiveLanguageClientEventListener.cs @@ -26,7 +26,7 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.LanguageClient; internal class AlwaysActiveLanguageClientEventListener( AlwaysActivateInProcLanguageClient languageClient, Lazy languageClientBroker, - IAsynchronousOperationListenerProvider listenerProvider) : IEventListener + IAsynchronousOperationListenerProvider listenerProvider) : IEventListener { private readonly AlwaysActivateInProcLanguageClient _languageClient = languageClient; private readonly Lazy _languageClientBroker = languageClientBroker; @@ -38,12 +38,17 @@ internal class AlwaysActiveLanguageClientEventListener( /// agnostic. We know we can provide as soon as the /// workspace is started, so tell the to start loading it. /// - public void StartListening(Workspace workspace, object serviceOpt) + public void StartListening(Workspace workspace) { // Trigger a fire and forget request to the VS LSP client to load our ILanguageClient. _ = LoadAsync(); } + public void StopListening(Workspace workspace) + { + // Nothing to do here. There's no concept of unloading an ILanguageClient. + } + private async Task LoadAsync() { try diff --git a/src/EditorFeatures/Core/Microsoft.CodeAnalysis.EditorFeatures.csproj b/src/EditorFeatures/Core/Microsoft.CodeAnalysis.EditorFeatures.csproj index 2ffdb061e7ab2..e92b4dd72771f 100644 --- a/src/EditorFeatures/Core/Microsoft.CodeAnalysis.EditorFeatures.csproj +++ b/src/EditorFeatures/Core/Microsoft.CodeAnalysis.EditorFeatures.csproj @@ -34,7 +34,6 @@ - @@ -79,6 +78,7 @@ + diff --git a/src/EditorFeatures/Core/ModernCommands/GoToImplementationCommandArgs.cs b/src/EditorFeatures/Core/ModernCommands/GoToImplementationCommandArgs.cs index cccb9c6789a30..29e9a99f6e308 100644 --- a/src/EditorFeatures/Core/ModernCommands/GoToImplementationCommandArgs.cs +++ b/src/EditorFeatures/Core/ModernCommands/GoToImplementationCommandArgs.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.Diagnostics.CodeAnalysis; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; diff --git a/src/EditorFeatures/Core/ModernCommands/OrganizeDocumentCommandArgs.cs b/src/EditorFeatures/Core/ModernCommands/OrganizeDocumentCommandArgs.cs index 0e2ccf238ef3f..18f7783fb6694 100644 --- a/src/EditorFeatures/Core/ModernCommands/OrganizeDocumentCommandArgs.cs +++ b/src/EditorFeatures/Core/ModernCommands/OrganizeDocumentCommandArgs.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.Diagnostics.CodeAnalysis; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; diff --git a/src/EditorFeatures/Core/ModernCommands/SortAndRemoveUnnecessaryImportsCommandArgs.cs b/src/EditorFeatures/Core/ModernCommands/SortAndRemoveUnnecessaryImportsCommandArgs.cs index f3faa1694223f..a989abc144edd 100644 --- a/src/EditorFeatures/Core/ModernCommands/SortAndRemoveUnnecessaryImportsCommandArgs.cs +++ b/src/EditorFeatures/Core/ModernCommands/SortAndRemoveUnnecessaryImportsCommandArgs.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.Diagnostics.CodeAnalysis; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; diff --git a/src/EditorFeatures/Core/ModernCommands/SortImportsCommandArgs.cs b/src/EditorFeatures/Core/ModernCommands/SortImportsCommandArgs.cs index c7ea673010532..52b05787993b6 100644 --- a/src/EditorFeatures/Core/ModernCommands/SortImportsCommandArgs.cs +++ b/src/EditorFeatures/Core/ModernCommands/SortImportsCommandArgs.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.Diagnostics.CodeAnalysis; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; diff --git a/src/EditorFeatures/Core/NavigateTo/DefaultNavigateToLinkService.cs b/src/EditorFeatures/Core/NavigateTo/DefaultNavigateToLinkService.cs index 266e45bfdafa3..477ecd75ad962 100644 --- a/src/EditorFeatures/Core/NavigateTo/DefaultNavigateToLinkService.cs +++ b/src/EditorFeatures/Core/NavigateTo/DefaultNavigateToLinkService.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.Composition; using System.Threading; diff --git a/src/EditorFeatures/Core/NavigateTo/INavigateToLinkService.cs b/src/EditorFeatures/Core/NavigateTo/INavigateToLinkService.cs index 1b6d388cdbbf3..51c0b6546ff1c 100644 --- a/src/EditorFeatures/Core/NavigateTo/INavigateToLinkService.cs +++ b/src/EditorFeatures/Core/NavigateTo/INavigateToLinkService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Threading; using System.Threading.Tasks; diff --git a/src/EditorFeatures/Core/Navigation/IDocumentNavigationServiceExtensions.cs b/src/EditorFeatures/Core/Navigation/IDocumentNavigationServiceExtensions.cs index fbaa8a20e8f98..d2bc7ec0c15da 100644 --- a/src/EditorFeatures/Core/Navigation/IDocumentNavigationServiceExtensions.cs +++ b/src/EditorFeatures/Core/Navigation/IDocumentNavigationServiceExtensions.cs @@ -75,7 +75,7 @@ public static async Task TryNavigateToLineAndOffsetAsync( // Navigation should not change the context of linked files and Shared Projects. documentId = workspace.GetDocumentIdInCurrentContext(documentId); - var document = workspace.CurrentSolution.GetDocument(documentId); + var document = workspace.CurrentSolution.GetTextDocument(documentId); if (document is null) return false; diff --git a/src/EditorFeatures/Core/NavigationBar/NavigationBarController.cs b/src/EditorFeatures/Core/NavigationBar/NavigationBarController.cs index f988ab4ffc1d4..4a8cf20cedada 100644 --- a/src/EditorFeatures/Core/NavigationBar/NavigationBarController.cs +++ b/src/EditorFeatures/Core/NavigationBar/NavigationBarController.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Data.Common; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -17,6 +16,7 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Threading; using Microsoft.CodeAnalysis.Workspaces; using Microsoft.VisualStudio.Text; using Roslyn.Utilities; diff --git a/src/EditorFeatures/Core/Organizing/OrganizeDocumentCommandHandler.cs b/src/EditorFeatures/Core/Organizing/OrganizeDocumentCommandHandler.cs index c7e05e1cbb2a6..cb23f2040e390 100644 --- a/src/EditorFeatures/Core/Organizing/OrganizeDocumentCommandHandler.cs +++ b/src/EditorFeatures/Core/Organizing/OrganizeDocumentCommandHandler.cs @@ -12,7 +12,6 @@ using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.OrganizeImports; using Microsoft.CodeAnalysis.Organizing; using Microsoft.CodeAnalysis.RemoveUnnecessaryImports; diff --git a/src/EditorFeatures/Core/Remote/SolutionChecksumUpdater.cs b/src/EditorFeatures/Core/Remote/SolutionChecksumUpdater.cs index 6f1b14d5dc446..70dabe4a7aa68 100644 --- a/src/EditorFeatures/Core/Remote/SolutionChecksumUpdater.cs +++ b/src/EditorFeatures/Core/Remote/SolutionChecksumUpdater.cs @@ -3,16 +3,15 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Immutable; using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Notification; -using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; -using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Telemetry; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Remote; @@ -33,13 +32,6 @@ internal sealed class SolutionChecksumUpdater private readonly IDocumentTrackingService _documentTrackingService; - /// - /// Queue to push out text changes in a batched fashion when we hear about them. Because these should be short - /// operations (only syncing text changes) we don't cancel this when we enter the paused state. We simply don't - /// start queuing more requests into this until we become unpaused. - /// - private readonly AsyncBatchingWorkQueue<(Document oldDocument, Document newDocument)> _textChangeQueue; - /// /// Queue for kicking off the work to synchronize the primary workspace's solution. /// @@ -53,6 +45,13 @@ internal sealed class SolutionChecksumUpdater private readonly object _gate = new(); private bool _isSynchronizeWorkspacePaused; + private readonly CancellationToken _shutdownToken; + + private const string SynchronizeTextChangesStatusSucceededMetricName = "SucceededCount"; + private const string SynchronizeTextChangesStatusFailedMetricName = "FailedCount"; + private const string SynchronizeTextChangesStatusSucceededKeyName = nameof(SolutionChecksumUpdater) + "." + SynchronizeTextChangesStatusSucceededMetricName; + private const string SynchronizeTextChangesStatusFailedKeyName = nameof(SolutionChecksumUpdater) + "." + SynchronizeTextChangesStatusFailedMetricName; + public SolutionChecksumUpdater( Workspace workspace, IAsynchronousOperationListenerProvider listenerProvider, @@ -65,20 +64,14 @@ public SolutionChecksumUpdater( _workspace = workspace; _documentTrackingService = workspace.Services.GetRequiredService(); + _shutdownToken = shutdownToken; + _synchronizeWorkspaceQueue = new AsyncBatchingWorkQueue( DelayTimeSpan.NearImmediate, SynchronizePrimaryWorkspaceAsync, listener, shutdownToken); - // Text changes and active doc info are tiny messages. So attempt to send them immediately. Just batching - // things up if we get a flurry of notifications. - _textChangeQueue = new AsyncBatchingWorkQueue<(Document oldDocument, Document newDocument)>( - TimeSpan.Zero, - SynchronizeTextChangesAsync, - listener, - shutdownToken); - _synchronizeActiveDocumentQueue = new AsyncBatchingWorkQueue( TimeSpan.Zero, SynchronizeActiveDocumentAsync, @@ -87,6 +80,7 @@ public SolutionChecksumUpdater( // start listening workspace change event _workspace.WorkspaceChanged += OnWorkspaceChanged; + _workspace.WorkspaceChangedImmediate += OnWorkspaceChangedImmediate; _documentTrackingService.ActiveDocumentChanged += OnActiveDocumentChanged; if (_globalOperationService != null) @@ -107,6 +101,7 @@ public void Shutdown() _documentTrackingService.ActiveDocumentChanged -= OnActiveDocumentChanged; _workspace.WorkspaceChanged -= OnWorkspaceChanged; + _workspace.WorkspaceChangedImmediate -= OnWorkspaceChangedImmediate; if (_globalOperationService != null) { @@ -143,14 +138,6 @@ private void ResumeSynchronizingPrimaryWorkspace() private void OnWorkspaceChanged(object? sender, WorkspaceChangeEventArgs e) { - if (e.Kind == WorkspaceChangeKind.DocumentChanged) - { - var oldDocument = e.OldSolution.GetDocument(e.DocumentId); - var newDocument = e.NewSolution.GetDocument(e.DocumentId); - if (oldDocument != null && newDocument != null) - _textChangeQueue.AddWork((oldDocument, newDocument)); - } - // Check if we're currently paused. If so ignore this notification. We don't want to any work in response // to whatever the workspace is doing. lock (_gate) @@ -160,6 +147,20 @@ private void OnWorkspaceChanged(object? sender, WorkspaceChangeEventArgs e) } } + private void OnWorkspaceChangedImmediate(object? sender, WorkspaceChangeEventArgs e) + { + if (e.Kind == WorkspaceChangeKind.DocumentChanged) + { + var documentId = e.DocumentId!; + var oldDocument = e.OldSolution.GetRequiredDocument(documentId); + var newDocument = e.NewSolution.GetRequiredDocument(documentId); + + // Fire-and-forget to dispatch notification of this document change event to the remote side + // and return to the caller as quickly as possible. + _ = DispatchSynchronizeTextChangesAsync(oldDocument, newDocument).ReportNonFatalErrorAsync(); + } + } + private void OnActiveDocumentChanged(object? sender, DocumentId? e) => _synchronizeActiveDocumentQueue.AddWork(); @@ -202,57 +203,81 @@ await client.TryInvokeAsync( cancellationToken).ConfigureAwait(false); } - private async ValueTask SynchronizeTextChangesAsync( - ImmutableSegmentedList<(Document oldDocument, Document newDocument)> values, - CancellationToken cancellationToken) + private async Task DispatchSynchronizeTextChangesAsync( + Document oldDocument, + Document newDocument) { - var client = await RemoteHostClient.TryGetClientAsync(_workspace, cancellationToken).ConfigureAwait(false); - if (client == null) + // Explicitly force a yield point here to ensure this method returns to the caller immediately and that + // all work is done off the calling thread. + await Task.Yield().ConfigureAwait(false); + + // Inform the remote asset synchronization service as quickly as possible + // about the text changes between oldDocument and newDocument. By doing this, we can + // reduce the likelihood of the remote side encountering an unknown checksum and + // requiring a synchronization of the full document contents. + var wasSynchronized = await DispatchSynchronizeTextChangesHelperAsync().ConfigureAwait(false); + if (wasSynchronized == null) return; - // this pushes text changes to the remote side if it can. this is purely perf optimization. whether this - // pushing text change worked or not doesn't affect feature's functionality. - // - // this basically see whether it can cheaply find out text changes between 2 snapshots, if it can, it will - // send out that text changes to remote side. - // - // the remote side, once got the text change, will again see whether it can use that text change information - // without any high cost and create new snapshot from it. - // - // otherwise, it will do the normal behavior of getting full text from VS side. this optimization saves - // times we need to do full text synchronization for typing scenario. - using var _ = ArrayBuilder<(DocumentId id, Checksum textChecksum, ImmutableArray changes, Checksum newTextChecksum)>.GetInstance(out var builder); - - foreach (var (oldDocument, newDocument) in values) + // Update aggregated telemetry with success status of sending the synchronization data. + var metricName = wasSynchronized.Value ? SynchronizeTextChangesStatusSucceededMetricName : SynchronizeTextChangesStatusFailedMetricName; + var keyName = wasSynchronized.Value ? SynchronizeTextChangesStatusSucceededKeyName : SynchronizeTextChangesStatusFailedKeyName; + TelemetryLogging.LogAggregatedCounter(FunctionId.ChecksumUpdater_SynchronizeTextChangesStatus, KeyValueLogMessage.Create(m => { + m[TelemetryLogging.KeyName] = keyName; + m[TelemetryLogging.KeyValue] = 1L; + m[TelemetryLogging.KeyMetricName] = metricName; + })); + + return; + + async Task DispatchSynchronizeTextChangesHelperAsync() + { + var client = await RemoteHostClient.TryGetClientAsync(_workspace, _shutdownToken).ConfigureAwait(false); + if (client == null) + { + // null return value indicates that we were unable to synchronize the text changes, but to not log + // telemetry against that inability as turning off OOP is not a failure. + return null; + } + + // this pushes text changes to the remote side if it can. this is purely perf optimization. whether this + // pushing text change worked or not doesn't affect feature's functionality. + // + // this basically see whether it can cheaply find out text changes between 2 snapshots, if it can, it will + // send out that text changes to remote side. + // + // the remote side, once got the text change, will again see whether it can use that text change information + // without any high cost and create new snapshot from it. + // + // otherwise, it will do the normal behavior of getting full text from VS side. this optimization saves + // times we need to do full text synchronization for typing scenario. if (!oldDocument.TryGetText(out var oldText) || !newDocument.TryGetText(out var newText)) { // we only support case where text already exist - continue; + return false; } // Avoid allocating text before seeing if we can bail out. var changeRanges = newText.GetChangeRanges(oldText).AsImmutable(); if (changeRanges.Length == 0) - continue; + return true; // no benefit here. pulling from remote host is more efficient if (changeRanges is [{ Span.Length: var singleChangeLength }] && singleChangeLength == oldText.Length) - continue; + return true; - var state = await oldDocument.State.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); - var newState = await newDocument.State.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); + var state = await oldDocument.State.GetStateChecksumsAsync(_shutdownToken).ConfigureAwait(false); + var newState = await newDocument.State.GetStateChecksumsAsync(_shutdownToken).ConfigureAwait(false); var textChanges = newText.GetTextChanges(oldText).AsImmutable(); - builder.Add((oldDocument.Id, state.Text, textChanges, newState.Text)); - } - if (builder.Count == 0) - return; + await client.TryInvokeAsync( + (service, cancellationToken) => service.SynchronizeTextChangesAsync(oldDocument.Id, state.Text, textChanges, newState.Text, cancellationToken), + _shutdownToken).ConfigureAwait(false); - await client.TryInvokeAsync( - (service, cancellationToken) => service.SynchronizeTextChangesAsync(builder.ToImmutableAndClear(), cancellationToken), - cancellationToken).ConfigureAwait(false); + return true; + } } } diff --git a/src/EditorFeatures/Core/RenameTracking/IRenameTrackingLanguageHeuristicsService.cs b/src/EditorFeatures/Core/RenameTracking/IRenameTrackingLanguageHeuristicsService.cs index 74ff0b2bebccb..af09bce87c616 100644 --- a/src/EditorFeatures/Core/RenameTracking/IRenameTrackingLanguageHeuristicsService.cs +++ b/src/EditorFeatures/Core/RenameTracking/IRenameTrackingLanguageHeuristicsService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.Editor.Implementation.RenameTracking; diff --git a/src/EditorFeatures/Core/RenameTracking/RenameTrackingCancellationCommandHandler.cs b/src/EditorFeatures/Core/RenameTracking/RenameTrackingCancellationCommandHandler.cs index 50d4ea654dfc0..992b44cec2288 100644 --- a/src/EditorFeatures/Core/RenameTracking/RenameTrackingCancellationCommandHandler.cs +++ b/src/EditorFeatures/Core/RenameTracking/RenameTrackingCancellationCommandHandler.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.ComponentModel.Composition; using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; diff --git a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTag.cs b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTag.cs index c2e3f57b04d60..0da73767d419e 100644 --- a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTag.cs +++ b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTag.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.VisualStudio.Text.Tagging; namespace Microsoft.CodeAnalysis.Editor.Implementation.RenameTracking; diff --git a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.RenameTrackingSolutionSet.cs b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.RenameTrackingSolutionSet.cs index 02d248980c121..50423344157aa 100644 --- a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.RenameTrackingSolutionSet.cs +++ b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.RenameTrackingSolutionSet.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.Editor.Implementation.RenameTracking; internal sealed partial class RenameTrackingTaggerProvider diff --git a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.Tagger.cs b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.Tagger.cs index deaef04b1024e..d1206c6c1bf71 100644 --- a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.Tagger.cs +++ b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.Tagger.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using Microsoft.VisualStudio.Text; diff --git a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.cs b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.cs index de3b3ce56c86e..8e4deef024bea 100644 --- a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.cs +++ b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.cs @@ -8,7 +8,6 @@ using System.Collections.Generic; using System.ComponentModel.Composition; using System.Diagnostics.CodeAnalysis; -using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Diagnostics; @@ -16,14 +15,12 @@ using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; -using Microsoft.CodeAnalysis.SQLite.Interop; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Operations; using Microsoft.VisualStudio.Text.Tagging; using Microsoft.VisualStudio.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.RenameTracking; diff --git a/src/EditorFeatures/Core/Shared/Extensions/ITextSelectionExtensions.cs b/src/EditorFeatures/Core/Shared/Extensions/ITextSelectionExtensions.cs index 9e73dc6aaea40..09425c84ddfc6 100644 --- a/src/EditorFeatures/Core/Shared/Extensions/ITextSelectionExtensions.cs +++ b/src/EditorFeatures/Core/Shared/Extensions/ITextSelectionExtensions.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Shared.Extensions; diff --git a/src/EditorFeatures/Core/Shared/Extensions/ITextViewExtensions.AutoClosingViewProperty.cs b/src/EditorFeatures/Core/Shared/Extensions/ITextViewExtensions.AutoClosingViewProperty.cs index 282aa1add2ab0..daa93c2bdd88f 100644 --- a/src/EditorFeatures/Core/Shared/Extensions/ITextViewExtensions.AutoClosingViewProperty.cs +++ b/src/EditorFeatures/Core/Shared/Extensions/ITextViewExtensions.AutoClosingViewProperty.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using Microsoft.VisualStudio.Text.Editor; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Shared.Extensions; diff --git a/src/EditorFeatures/Core/Shared/Extensions/ITextViewExtensions.cs b/src/EditorFeatures/Core/Shared/Extensions/ITextViewExtensions.cs index 8c5027115121d..b328be35f519c 100644 --- a/src/EditorFeatures/Core/Shared/Extensions/ITextViewExtensions.cs +++ b/src/EditorFeatures/Core/Shared/Extensions/ITextViewExtensions.cs @@ -108,6 +108,15 @@ public static void SetMultiSelection(this ITextView textView, IEnumerable textView.TryMoveCaretToAndEnsureVisible(new VirtualSnapshotPoint(point), outliningManagerService, ensureSpanVisibleOptions); diff --git a/src/EditorFeatures/Core/Shared/Extensions/IThreadingContextExtensions.cs b/src/EditorFeatures/Core/Shared/Extensions/IThreadingContextExtensions.cs index ece4af98e0f52..8db832bba0c30 100644 --- a/src/EditorFeatures/Core/Shared/Extensions/IThreadingContextExtensions.cs +++ b/src/EditorFeatures/Core/Shared/Extensions/IThreadingContextExtensions.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Shared.Extensions; diff --git a/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.CaretPositionChangedEventSource.cs b/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.CaretPositionChangedEventSource.cs index 52e1fb9ccf7ef..443d2b34f9c6c 100644 --- a/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.CaretPositionChangedEventSource.cs +++ b/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.CaretPositionChangedEventSource.cs @@ -4,7 +4,6 @@ using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Shared.Tagging; diff --git a/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.ReadOnlyRegionsChangedEventSource.cs b/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.ReadOnlyRegionsChangedEventSource.cs index a88b8892fb254..960cec990820d 100644 --- a/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.ReadOnlyRegionsChangedEventSource.cs +++ b/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.ReadOnlyRegionsChangedEventSource.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using Microsoft.VisualStudio.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Shared.Tagging; diff --git a/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.TextChangedEventSource.cs b/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.TextChangedEventSource.cs index 71feb49801ae2..8395901632e36 100644 --- a/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.TextChangedEventSource.cs +++ b/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.TextChangedEventSource.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using Microsoft.VisualStudio.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Shared.Tagging; diff --git a/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.WorkspaceChangedEventSource.cs b/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.WorkspaceChangedEventSource.cs index 2c627b9a63a9e..d7301c29e8156 100644 --- a/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.WorkspaceChangedEventSource.cs +++ b/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.WorkspaceChangedEventSource.cs @@ -4,6 +4,7 @@ using System.Threading; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Threading; using Microsoft.VisualStudio.Text; using Roslyn.Utilities; diff --git a/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.cs b/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.cs index 5b70580fabf45..6dc2d5eaa66c0 100644 --- a/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.cs +++ b/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; -using System.Linq; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Editor.Tagging; using Microsoft.CodeAnalysis.Options; diff --git a/src/EditorFeatures/Core/Shared/Utilities/ClassificationTypeMap.cs b/src/EditorFeatures/Core/Shared/Utilities/ClassificationTypeMap.cs index 62c3eea7c82f0..fdc2524f47df4 100644 --- a/src/EditorFeatures/Core/Shared/Utilities/ClassificationTypeMap.cs +++ b/src/EditorFeatures/Core/Shared/Utilities/ClassificationTypeMap.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.VisualStudio.Text.Classification; -using Roslyn.Utilities; using ReferenceEqualityComparer = Roslyn.Utilities.ReferenceEqualityComparer; namespace Microsoft.CodeAnalysis.Editor.Shared.Utilities; diff --git a/src/EditorFeatures/Core/Shared/Utilities/ResettableDelay.cs b/src/EditorFeatures/Core/Shared/Utilities/ResettableDelay.cs index b7cf6c32c4d03..1d0574a9436b8 100644 --- a/src/EditorFeatures/Core/Shared/Utilities/ResettableDelay.cs +++ b/src/EditorFeatures/Core/Shared/Utilities/ResettableDelay.cs @@ -6,7 +6,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Shared.TestHooks; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Shared.Utilities; diff --git a/src/EditorFeatures/Core/SolutionEvents/HostLegacySolutionEventsWorkspaceEventListener.cs b/src/EditorFeatures/Core/SolutionEvents/HostLegacySolutionEventsWorkspaceEventListener.cs index 12535d5b92067..5fe501dff9197 100644 --- a/src/EditorFeatures/Core/SolutionEvents/HostLegacySolutionEventsWorkspaceEventListener.cs +++ b/src/EditorFeatures/Core/SolutionEvents/HostLegacySolutionEventsWorkspaceEventListener.cs @@ -15,6 +15,7 @@ using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.SolutionCrawler; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LegacySolutionEvents; @@ -25,7 +26,7 @@ namespace Microsoft.CodeAnalysis.LegacySolutionEvents; /// to an entirely differently (ideally 'pull') model for test discovery. /// [ExportEventListener(WellKnownEventListeners.Workspace, WorkspaceKind.Host), Shared] -internal sealed partial class HostLegacySolutionEventsWorkspaceEventListener : IEventListener +internal sealed partial class HostLegacySolutionEventsWorkspaceEventListener : IEventListener { private readonly IGlobalOptionService _globalOptions; private readonly IThreadingContext _threadingContext; @@ -47,18 +48,18 @@ public HostLegacySolutionEventsWorkspaceEventListener( _threadingContext.DisposalToken); } - public void StartListening(Workspace workspace, object? serviceOpt) + public void StartListening(Workspace workspace) { // We only support this option to disable crawling in internal speedometer and ddrit perf runs to lower noise. // It is not exposed to the user. if (_globalOptions.GetOption(SolutionCrawlerRegistrationService.EnableSolutionCrawler)) - { workspace.WorkspaceChanged += OnWorkspaceChanged; - _threadingContext.DisposalToken.Register(() => - { - workspace.WorkspaceChanged -= OnWorkspaceChanged; - }); - } + } + + public void StopListening(Workspace workspace) + { + if (_globalOptions.GetOption(SolutionCrawlerRegistrationService.EnableSolutionCrawler)) + workspace.WorkspaceChanged -= OnWorkspaceChanged; } private void OnWorkspaceChanged(object? sender, WorkspaceChangeEventArgs e) diff --git a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource.cs b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource.cs index 18d853a4388a0..3a7ed489a5f72 100644 --- a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource.cs +++ b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource.cs @@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Threading; using Microsoft.CodeAnalysis.Workspaces; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; diff --git a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_IEqualityComparer.cs b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_IEqualityComparer.cs index 4e4abff3bcf06..e102d431b7ea3 100644 --- a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_IEqualityComparer.cs +++ b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_IEqualityComparer.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.VisualStudio.Text.Tagging; namespace Microsoft.CodeAnalysis.Editor.Tagging; diff --git a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_ProduceTags.cs b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_ProduceTags.cs index a071145057f31..c9eb12fb47e54 100644 --- a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_ProduceTags.cs +++ b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_ProduceTags.cs @@ -17,6 +17,7 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Threading; using Microsoft.CodeAnalysis.Utilities; using Microsoft.CodeAnalysis.Workspaces; using Microsoft.VisualStudio.Text; diff --git a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_ReferenceCounting.cs b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_ReferenceCounting.cs index 9a3503d556999..9c2095dd746ec 100644 --- a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_ReferenceCounting.cs +++ b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_ReferenceCounting.cs @@ -5,7 +5,6 @@ using System; using System.Diagnostics; using System.Threading; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Tagging; diff --git a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.cs b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.cs index d0a37a1634e12..6a09fbf6164d9 100644 --- a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.cs +++ b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.cs @@ -24,7 +24,6 @@ using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Tagging; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Tagging; diff --git a/src/EditorFeatures/Core/Tagging/AsynchronousViewportTaggerProvider.SingleViewportTaggerProvider.cs b/src/EditorFeatures/Core/Tagging/AsynchronousViewportTaggerProvider.SingleViewportTaggerProvider.cs index 4b2b118f431de..8d26290225dda 100644 --- a/src/EditorFeatures/Core/Tagging/AsynchronousViewportTaggerProvider.SingleViewportTaggerProvider.cs +++ b/src/EditorFeatures/Core/Tagging/AsynchronousViewportTaggerProvider.SingleViewportTaggerProvider.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading; diff --git a/src/EditorFeatures/Core/Tagging/ITaggerEventSource.cs b/src/EditorFeatures/Core/Tagging/ITaggerEventSource.cs index 43cc5947723c3..1a8e1f613febd 100644 --- a/src/EditorFeatures/Core/Tagging/ITaggerEventSource.cs +++ b/src/EditorFeatures/Core/Tagging/ITaggerEventSource.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; namespace Microsoft.CodeAnalysis.Editor.Tagging; diff --git a/src/EditorFeatures/Core/Tagging/TaggerCaretChangeBehavior.cs b/src/EditorFeatures/Core/Tagging/TaggerCaretChangeBehavior.cs index b419e476adae7..dea71e642e720 100644 --- a/src/EditorFeatures/Core/Tagging/TaggerCaretChangeBehavior.cs +++ b/src/EditorFeatures/Core/Tagging/TaggerCaretChangeBehavior.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; namespace Microsoft.CodeAnalysis.Editor.Tagging; diff --git a/src/EditorFeatures/Core/Tagging/TaggerDelay.cs b/src/EditorFeatures/Core/Tagging/TaggerDelay.cs index d6a1e2757f658..fd44366bfdc31 100644 --- a/src/EditorFeatures/Core/Tagging/TaggerDelay.cs +++ b/src/EditorFeatures/Core/Tagging/TaggerDelay.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.Editor.Tagging; /// diff --git a/src/EditorFeatures/Core/Tagging/TaggerMainThreadManager.cs b/src/EditorFeatures/Core/Tagging/TaggerMainThreadManager.cs index 5378232757c2d..b850082da78a1 100644 --- a/src/EditorFeatures/Core/Tagging/TaggerMainThreadManager.cs +++ b/src/EditorFeatures/Core/Tagging/TaggerMainThreadManager.cs @@ -8,7 +8,7 @@ using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Shared.TestHooks; -using Roslyn.Utilities; +using Microsoft.CodeAnalysis.Threading; using TaggerUIData = (bool isVisible, Microsoft.VisualStudio.Text.SnapshotPoint? caretPosition, Roslyn.Utilities.OneOrMany spansToTag); diff --git a/src/EditorFeatures/Core/Tagging/TaggerTextChangeBehavior.cs b/src/EditorFeatures/Core/Tagging/TaggerTextChangeBehavior.cs index 008425992693f..95871b9271c50 100644 --- a/src/EditorFeatures/Core/Tagging/TaggerTextChangeBehavior.cs +++ b/src/EditorFeatures/Core/Tagging/TaggerTextChangeBehavior.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Threading; namespace Microsoft.CodeAnalysis.Editor.Tagging; diff --git a/src/EditorFeatures/Core/Tags/IImageIdService.cs b/src/EditorFeatures/Core/Tags/IImageIdService.cs index a584807d5a355..260e384116869 100644 --- a/src/EditorFeatures/Core/Tags/IImageIdService.cs +++ b/src/EditorFeatures/Core/Tags/IImageIdService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using Microsoft.VisualStudio.Core.Imaging; diff --git a/src/EditorFeatures/Core/TextViewRoles.cs b/src/EditorFeatures/Core/TextViewRoles.cs index 8838f360c21ae..5b06a6d5e33a9 100644 --- a/src/EditorFeatures/Core/TextViewRoles.cs +++ b/src/EditorFeatures/Core/TextViewRoles.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.Editor; internal static class TextViewRoles diff --git a/src/EditorFeatures/Core/TypeForwarders.cs b/src/EditorFeatures/Core/TypeForwarders.cs index fbfdc58a439fd..c80f7e43f06e1 100644 --- a/src/EditorFeatures/Core/TypeForwarders.cs +++ b/src/EditorFeatures/Core/TypeForwarders.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.Runtime.CompilerServices; // Microsoft.CodeAnalysis.Editor.ContentTypeNames has been moved to Microsoft.CodeAnalysis.Editor.Text.dll diff --git a/src/EditorFeatures/Core/Undo/IGlobalUndoService.cs b/src/EditorFeatures/Core/Undo/IGlobalUndoService.cs index d9ac0af07f873..d618221c10a79 100644 --- a/src/EditorFeatures/Core/Undo/IGlobalUndoService.cs +++ b/src/EditorFeatures/Core/Undo/IGlobalUndoService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.Editor.Undo; diff --git a/src/EditorFeatures/Core/Undo/ISourceTextUndoService.cs b/src/EditorFeatures/Core/Undo/ISourceTextUndoService.cs index 9a399e8fdfb6d..bcddc17c81aa9 100644 --- a/src/EditorFeatures/Core/Undo/ISourceTextUndoService.cs +++ b/src/EditorFeatures/Core/Undo/ISourceTextUndoService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; diff --git a/src/EditorFeatures/Core/Undo/ISourceTextUndoTransaction.cs b/src/EditorFeatures/Core/Undo/ISourceTextUndoTransaction.cs index 2a853e5b4d3c5..4a716ff219ca1 100644 --- a/src/EditorFeatures/Core/Undo/ISourceTextUndoTransaction.cs +++ b/src/EditorFeatures/Core/Undo/ISourceTextUndoTransaction.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.Text; diff --git a/src/EditorFeatures/Core/Undo/IWorkspaceGlobalUndoTransaction.cs b/src/EditorFeatures/Core/Undo/IWorkspaceGlobalUndoTransaction.cs index 930ebc1283781..e501ca2d50e92 100644 --- a/src/EditorFeatures/Core/Undo/IWorkspaceGlobalUndoTransaction.cs +++ b/src/EditorFeatures/Core/Undo/IWorkspaceGlobalUndoTransaction.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; namespace Microsoft.CodeAnalysis.Editor.Undo; diff --git a/src/EditorFeatures/Core/Undo/NoOpGlobalUndoServiceFactory.cs b/src/EditorFeatures/Core/Undo/NoOpGlobalUndoServiceFactory.cs index 42007f1d6886c..a28a06c79f32d 100644 --- a/src/EditorFeatures/Core/Undo/NoOpGlobalUndoServiceFactory.cs +++ b/src/EditorFeatures/Core/Undo/NoOpGlobalUndoServiceFactory.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.Composition; using Microsoft.CodeAnalysis.Host; diff --git a/src/EditorFeatures/Core/Workspaces/TextUndoHistoryWorkspaceServiceFactoryService.cs b/src/EditorFeatures/Core/Workspaces/TextUndoHistoryWorkspaceServiceFactoryService.cs index 9a2487541b1d1..9fa6242f5f521 100644 --- a/src/EditorFeatures/Core/Workspaces/TextUndoHistoryWorkspaceServiceFactoryService.cs +++ b/src/EditorFeatures/Core/Workspaces/TextUndoHistoryWorkspaceServiceFactoryService.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.Composition; using Microsoft.CodeAnalysis.Host; diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.cs.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.cs.xlf index cda4910f11c0d..02ee0c7190b58 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.cs.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.cs.xlf @@ -19,7 +19,7 @@ Chat limit reached, [upgrade now] or wait for the limit to reset. - Chat limit reached, [upgrade now] or wait for the limit to reset. + Bylo dosaženo limitu chatu. [Upgradujte nyní] nebo počkejte na resetování limitu. The text surrounded by "[" and "]" characters will be hyperlinked. Please ensure the localized text still has "[" and "]" characters. diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.de.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.de.xlf index 223527ee2ae83..251a1a6ba30ba 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.de.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.de.xlf @@ -19,7 +19,7 @@ Chat limit reached, [upgrade now] or wait for the limit to reset. - Chat limit reached, [upgrade now] or wait for the limit to reset. + Das Chatlimit wurde erreicht, [upgrade now] oder warten Sie, bis das Limit zurückgesetzt wurde. The text surrounded by "[" and "]" characters will be hyperlinked. Please ensure the localized text still has "[" and "]" characters. diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.es.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.es.xlf index 8f96fcc9c21d7..c655afaa7ef4a 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.es.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.es.xlf @@ -19,7 +19,7 @@ Chat limit reached, [upgrade now] or wait for the limit to reset. - Chat limit reached, [upgrade now] or wait for the limit to reset. + Se alcanzó el límite de chats, [upgrade now] o esperar a que se restablezca el límite. The text surrounded by "[" and "]" characters will be hyperlinked. Please ensure the localized text still has "[" and "]" characters. diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.fr.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.fr.xlf index cd4dc9731af30..961b6268a1cba 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.fr.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.fr.xlf @@ -19,7 +19,7 @@ Chat limit reached, [upgrade now] or wait for the limit to reset. - Chat limit reached, [upgrade now] or wait for the limit to reset. + La limite de conversation a été atteinte, [upgrade now] ou attendez la réinitialisation de la limite. The text surrounded by "[" and "]" characters will be hyperlinked. Please ensure the localized text still has "[" and "]" characters. diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.it.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.it.xlf index 264651a81a1d2..b6a038b54c877 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.it.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.it.xlf @@ -19,7 +19,7 @@ Chat limit reached, [upgrade now] or wait for the limit to reset. - Chat limit reached, [upgrade now] or wait for the limit to reset. + È stato raggiunto il limite di chat, [upgrade now] o attendere la reimpostazione del limite. The text surrounded by "[" and "]" characters will be hyperlinked. Please ensure the localized text still has "[" and "]" characters. diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ja.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ja.xlf index 162b9ff3a5da9..acf184340e87a 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ja.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ja.xlf @@ -19,7 +19,7 @@ Chat limit reached, [upgrade now] or wait for the limit to reset. - Chat limit reached, [upgrade now] or wait for the limit to reset. + チャットの制限に達しました。[今すぐアップグレード] するか、制限がリセットされるまでお待ちください。 The text surrounded by "[" and "]" characters will be hyperlinked. Please ensure the localized text still has "[" and "]" characters. diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ko.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ko.xlf index 967a8c3d65f76..f55e5980a48bc 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ko.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ko.xlf @@ -19,7 +19,7 @@ Chat limit reached, [upgrade now] or wait for the limit to reset. - Chat limit reached, [upgrade now] or wait for the limit to reset. + 채팅 제한에 도달했습니다. [upgrade now] 또는 제한이 재설정될 때까지 기다리세요. The text surrounded by "[" and "]" characters will be hyperlinked. Please ensure the localized text still has "[" and "]" characters. diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pl.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pl.xlf index 13c31e460e558..0e512ff2be43d 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pl.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pl.xlf @@ -19,7 +19,7 @@ Chat limit reached, [upgrade now] or wait for the limit to reset. - Chat limit reached, [upgrade now] or wait for the limit to reset. + Osiągnięto limit czatu, [upgrade now] lub poczekaj na zresetowanie limitu. The text surrounded by "[" and "]" characters will be hyperlinked. Please ensure the localized text still has "[" and "]" characters. diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pt-BR.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pt-BR.xlf index f0b76297e818e..40b3167932d02 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pt-BR.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pt-BR.xlf @@ -19,7 +19,7 @@ Chat limit reached, [upgrade now] or wait for the limit to reset. - Chat limit reached, [upgrade now] or wait for the limit to reset. + Limite de chat atingido, [upgrade now] ou aguarde até que o limite seja redefinido. The text surrounded by "[" and "]" characters will be hyperlinked. Please ensure the localized text still has "[" and "]" characters. diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ru.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ru.xlf index 882882e284155..6d2105d4343be 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ru.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ru.xlf @@ -19,7 +19,7 @@ Chat limit reached, [upgrade now] or wait for the limit to reset. - Chat limit reached, [upgrade now] or wait for the limit to reset. + Достигнут предел использования чата. [Повысьте статус сейчас] или дождитесь сброса ограничения. The text surrounded by "[" and "]" characters will be hyperlinked. Please ensure the localized text still has "[" and "]" characters. diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.tr.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.tr.xlf index 6aff6dc59e379..be6fcde4ffa57 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.tr.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.tr.xlf @@ -19,7 +19,7 @@ Chat limit reached, [upgrade now] or wait for the limit to reset. - Chat limit reached, [upgrade now] or wait for the limit to reset. + Sohbet sınırına ulaşıldı, [upgrade now] veya sınırın sıfırlanması için bekleyin. The text surrounded by "[" and "]" characters will be hyperlinked. Please ensure the localized text still has "[" and "]" characters. diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hans.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hans.xlf index 0bed7187047f0..a985dc67447b9 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hans.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hans.xlf @@ -19,7 +19,7 @@ Chat limit reached, [upgrade now] or wait for the limit to reset. - Chat limit reached, [upgrade now] or wait for the limit to reset. + 已达到聊天限制,[upgrade now] 或等待重置限制。 The text surrounded by "[" and "]" characters will be hyperlinked. Please ensure the localized text still has "[" and "]" characters. diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hant.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hant.xlf index 7daf637ef2194..9ebef803db3be 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hant.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hant.xlf @@ -19,7 +19,7 @@ Chat limit reached, [upgrade now] or wait for the limit to reset. - Chat limit reached, [upgrade now] or wait for the limit to reset. + 已達到聊天限制,[upgrade now] 或等候重設限制。 The text surrounded by "[" and "]" characters will be hyperlinked. Please ensure the localized text still has "[" and "]" characters. diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/ChangeSignature/AbstractChangeSignatureTests.cs b/src/EditorFeatures/DiagnosticsTestUtilities/ChangeSignature/AbstractChangeSignatureTests.cs index d80d8fdd84195..c9890767674d3 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/ChangeSignature/AbstractChangeSignatureTests.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/ChangeSignature/AbstractChangeSignatureTests.cs @@ -13,7 +13,6 @@ using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities.ChangeSignature; -using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; using Xunit; diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/ChangeSignature/ChangeSignatureTestState.cs b/src/EditorFeatures/DiagnosticsTestUtilities/ChangeSignature/ChangeSignatureTestState.cs index 827de1a7e388e..622c97d33cea8 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/ChangeSignature/ChangeSignatureTestState.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/ChangeSignature/ChangeSignatureTestState.cs @@ -12,7 +12,6 @@ using Microsoft.CodeAnalysis.ChangeSignature; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.VisualBasic; @@ -85,7 +84,7 @@ public async Task GetParameterConfigurationAsync() return changeSignatureAnalyzedSucceedContext.ParameterConfiguration; } - throw Roslyn.Utilities.ExceptionUtilities.UnexpectedValue(((CannotChangeSignatureAnalyzedContext)context).CannotChangeSignatureReason.ToString()); + throw ExceptionUtilities.UnexpectedValue(((CannotChangeSignatureAnalyzedContext)context).CannotChangeSignatureReason.ToString()); } public void Dispose() diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest_GenerateTypeDialog.cs b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest_GenerateTypeDialog.cs index cd5193deb76f5..f8d2996d8dcb6 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest_GenerateTypeDialog.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest_GenerateTypeDialog.cs @@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics.GenerateType; using Microsoft.CodeAnalysis.GenerateType; using Microsoft.CodeAnalysis.Test.Utilities; -using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.UnitTests; using Roslyn.Utilities; using Xunit; diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/MoveToNamespace/AbstractMoveToNamespaceTests.cs b/src/EditorFeatures/DiagnosticsTestUtilities/MoveToNamespace/AbstractMoveToNamespaceTests.cs index e221ea06844ec..d835b86f22b55 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/MoveToNamespace/AbstractMoveToNamespaceTests.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/MoveToNamespace/AbstractMoveToNamespaceTests.cs @@ -9,7 +9,6 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/MoveType/AbstractMoveTypeTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/MoveType/AbstractMoveTypeTest.cs index 7d8739acaece3..4ef6536f45d98 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/MoveType/AbstractMoveTypeTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/MoveType/AbstractMoveTypeTest.cs @@ -15,7 +15,6 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Test.Utilities; -using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.UnitTests; using Roslyn.Test.Utilities; using Xunit; diff --git a/src/EditorFeatures/ExternalAccess/Copilot/Internal/Analyzer/CSharp/CSharpCopilotCodeAnalysisService.ReflectionWrapper.cs b/src/EditorFeatures/ExternalAccess/Copilot/Internal/Analyzer/CSharp/CSharpCopilotCodeAnalysisService.ReflectionWrapper.cs deleted file mode 100644 index 6f33ec3b27cf8..0000000000000 --- a/src/EditorFeatures/ExternalAccess/Copilot/Internal/Analyzer/CSharp/CSharpCopilotCodeAnalysisService.ReflectionWrapper.cs +++ /dev/null @@ -1,178 +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.Reflection; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell.ServiceBroker; -using IServiceProvider = System.IServiceProvider; - -namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot.Internal.Analyzer.CSharp; - -using AnalyzeDocumentAsyncDelegateType = Func>>; -using GetAvailablePromptTitlesAsyncDelegateType = Func>>; -using GetCachedDiagnosticsAsyncDelegateType = Func>>; -using IsAvailableAsyncDelegateType = Func>; -using StartRefinementSessionAsyncDelegateType = Func; -using GetOnTheFlyDocsAsyncDelegateType = Func, string, CancellationToken, Task<(string responseString, bool isQuotaExceeded)>>; -using IsAnyExclusionAsyncDelegateType = Func>; -using IsFileExcludedAsyncDelegateType = Func>; - -internal sealed partial class CSharpCopilotCodeAnalysisService -{ - // A temporary helper to get access to the implementation of IExternalCSharpCopilotCodeAnalysisService, until it can be MEF exported. - private sealed class ReflectionWrapper : IExternalCSharpCopilotCodeAnalysisService - { - private const string CopilotRoslynDllName = "Microsoft.VisualStudio.Copilot.Roslyn, Version=0.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; - private const string InternalCSharpCopilotAnalyzerTypeFullName = "Microsoft.VisualStudio.Copilot.Roslyn.Analyzer.InternalCSharpCopilotAnalyzer"; - - private const string IsAvailableAsyncMethodName = "IsAvailableAsync"; - private const string GetAvailablePromptTitlesAsyncMethodName = "GetAvailablePromptTitlesAsync"; - private const string AnalyzeDocumentAsyncMethodName = "AnalyzeDocumentAsync"; - private const string GetCachedDiagnosticsAsyncMethodName = "GetCachedDiagnosticsAsync"; - private const string StartRefinementSessionAsyncMethodName = "StartRefinementSessionAsync"; - private const string GetOnTheFlyDocsAsyncMethodName = "GetOnTheFlyDocsAsync"; - private const string IsFileExcludedAsyncMethodName = "IsFileExcludedAsync"; - - // Create and cache closed delegate to ensure we use a singleton object and with better performance. - private readonly Type? _analyzerType; - private readonly object? _analyzerInstance; - private readonly Lazy _lazyIsAvailableAsyncDelegate; - private readonly Lazy _lazyGetAvailablePromptTitlesAsyncDelegate; - private readonly Lazy _lazyAnalyzeDocumentAsyncDelegate; - private readonly Lazy _lazyGetCachedDiagnosticsAsyncDelegate; - private readonly Lazy _lazyStartRefinementSessionAsyncDelegate; - private readonly Lazy _lazyGetOnTheFlyDocsAsyncDelegate; - private readonly Lazy _lazyIsFileExcludedAsyncDelegate; - - public ReflectionWrapper(IServiceProvider serviceProvider, IVsService brokeredServiceContainer) - { - try - { - var assembly = Assembly.Load(CopilotRoslynDllName); - var analyzerType = assembly.GetType(InternalCSharpCopilotAnalyzerTypeFullName); - if (analyzerType is not null) - { - var analyzerInstance = Activator.CreateInstance(analyzerType, serviceProvider, brokeredServiceContainer); - if (analyzerInstance is not null) - { - _analyzerType = analyzerType; - _analyzerInstance = analyzerInstance; - } - } - } - catch - { - // Catch all here since failure is expected if user has no copilot chat or an older version of it installed. - } - - _lazyIsAvailableAsyncDelegate = new(CreateIsAvailableAsyncDelegate, LazyThreadSafetyMode.PublicationOnly); - _lazyGetAvailablePromptTitlesAsyncDelegate = new(CreateGetAvailablePromptTitlesAsyncDelegate, LazyThreadSafetyMode.PublicationOnly); - _lazyAnalyzeDocumentAsyncDelegate = new(CreateAnalyzeDocumentAsyncDelegate, LazyThreadSafetyMode.PublicationOnly); - _lazyGetCachedDiagnosticsAsyncDelegate = new(CreateGetCachedDiagnosticsAsyncDelegate, LazyThreadSafetyMode.PublicationOnly); - _lazyStartRefinementSessionAsyncDelegate = new(CreateStartRefinementSessionAsyncDelegate, LazyThreadSafetyMode.PublicationOnly); - _lazyGetOnTheFlyDocsAsyncDelegate = new(CreateGetOnTheFlyDocsAsyncDelegate, LazyThreadSafetyMode.PublicationOnly); - _lazyIsFileExcludedAsyncDelegate = new(CreateIsFileExcludedAsyncDelegate, LazyThreadSafetyMode.PublicationOnly); - } - - private T? CreateDelegate(string methodName, Type[] types) where T : Delegate - { - try - { - if (_analyzerInstance is null || _analyzerType is null) - return null; - - if (_analyzerType.GetMethod(methodName, types) is MethodInfo methodInfo) - return (T)Delegate.CreateDelegate(typeof(T), _analyzerInstance, methodInfo); - } - catch - { - // Catch all here since failure is expected if user has no copilot chat or an older version of it installed - } - - return null; - } - - private IsAvailableAsyncDelegateType? CreateIsAvailableAsyncDelegate() - => CreateDelegate(IsAvailableAsyncMethodName, [typeof(CancellationToken)]); - - private GetAvailablePromptTitlesAsyncDelegateType? CreateGetAvailablePromptTitlesAsyncDelegate() - => CreateDelegate(GetAvailablePromptTitlesAsyncMethodName, [typeof(Document), typeof(CancellationToken)]); - - private AnalyzeDocumentAsyncDelegateType? CreateAnalyzeDocumentAsyncDelegate() - => CreateDelegate(AnalyzeDocumentAsyncMethodName, [typeof(Document), typeof(TextSpan?), typeof(string), typeof(CancellationToken)]); - - private GetCachedDiagnosticsAsyncDelegateType? CreateGetCachedDiagnosticsAsyncDelegate() - => CreateDelegate(GetCachedDiagnosticsAsyncMethodName, [typeof(Document), typeof(string), typeof(CancellationToken)]); - - private StartRefinementSessionAsyncDelegateType? CreateStartRefinementSessionAsyncDelegate() - => CreateDelegate(StartRefinementSessionAsyncMethodName, [typeof(Document), typeof(Document), typeof(Diagnostic), typeof(CancellationToken)]); - - private GetOnTheFlyDocsAsyncDelegateType? CreateGetOnTheFlyDocsAsyncDelegate() - => CreateDelegate(GetOnTheFlyDocsAsyncMethodName, [typeof(string), typeof(ImmutableArray), typeof(string), typeof(CancellationToken)]); - - private IsFileExcludedAsyncDelegateType? CreateIsFileExcludedAsyncDelegate() - => CreateDelegate(IsFileExcludedAsyncMethodName, [typeof(string), typeof(CancellationToken)]); - - public async Task IsAvailableAsync(CancellationToken cancellationToken) - { - if (_lazyIsAvailableAsyncDelegate.Value is null) - return false; - - return await _lazyIsAvailableAsyncDelegate.Value(cancellationToken).ConfigureAwait(false); - } - - public async Task> GetAvailablePromptTitlesAsync(Document document, CancellationToken cancellationToken) - { - if (_lazyGetAvailablePromptTitlesAsyncDelegate.Value is null) - return []; - - return await _lazyGetAvailablePromptTitlesAsyncDelegate.Value(document, cancellationToken).ConfigureAwait(false); - } - - public async Task> AnalyzeDocumentAsync(Document document, TextSpan? span, string promptTitle, CancellationToken cancellationToken) - { - if (_lazyAnalyzeDocumentAsyncDelegate.Value is null) - return []; - - return await _lazyAnalyzeDocumentAsyncDelegate.Value(document, span, promptTitle, cancellationToken).ConfigureAwait(false); - } - - public async Task> GetCachedDiagnosticsAsync(Document document, string promptTitle, CancellationToken cancellationToken) - { - if (_lazyGetCachedDiagnosticsAsyncDelegate.Value is null) - return []; - - return await _lazyGetCachedDiagnosticsAsyncDelegate.Value(document, promptTitle, cancellationToken).ConfigureAwait(false); - } - - public Task StartRefinementSessionAsync(Document oldDocument, Document newDocument, Diagnostic? primaryDiagnostic, CancellationToken cancellationToken) - { - if (_lazyStartRefinementSessionAsyncDelegate.Value is null) - return Task.CompletedTask; - - return _lazyStartRefinementSessionAsyncDelegate.Value(oldDocument, newDocument, primaryDiagnostic, cancellationToken); - } - - public async Task<(string responseString, bool isQuotaExceeded)> GetOnTheFlyDocsAsync(string symbolSignature, ImmutableArray declarationCode, string language, CancellationToken cancellationToken) - { - if (_lazyGetOnTheFlyDocsAsyncDelegate.Value is null) - return (string.Empty, false); - - return await _lazyGetOnTheFlyDocsAsyncDelegate.Value(symbolSignature, declarationCode, language, cancellationToken).ConfigureAwait(false); - } - - public async Task IsFileExcludedAsync(string filePath, CancellationToken cancellationToken) - { - if (_lazyIsFileExcludedAsyncDelegate.Value is null) - return false; - - return await _lazyIsFileExcludedAsyncDelegate.Value(filePath, cancellationToken).ConfigureAwait(false); - } - } -} diff --git a/src/EditorFeatures/ExternalAccess/Copilot/Internal/Analyzer/CSharp/CSharpCopilotCodeAnalysisService.cs b/src/EditorFeatures/ExternalAccess/Copilot/Internal/Analyzer/CSharp/CSharpCopilotCodeAnalysisService.cs deleted file mode 100644 index 8d5a5a91088af..0000000000000 --- a/src/EditorFeatures/ExternalAccess/Copilot/Internal/Analyzer/CSharp/CSharpCopilotCodeAnalysisService.cs +++ /dev/null @@ -1,85 +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.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Copilot; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageService; -using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.ServiceBroker; - -namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot.Internal.Analyzer.CSharp; - -[ExportLanguageService(typeof(ICopilotCodeAnalysisService), LanguageNames.CSharp), Shared] -internal sealed partial class CSharpCopilotCodeAnalysisService : AbstractCopilotCodeAnalysisService -{ - private readonly Lazy _lazyExternalCopilotService; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpCopilotCodeAnalysisService( - [Import(AllowDefault = true)] IExternalCSharpCopilotCodeAnalysisService? externalCopilotService, - IDiagnosticsRefresher diagnosticsRefresher, - SVsServiceProvider serviceProvider, - IVsService brokeredServiceContainer - ) : base(diagnosticsRefresher) - { - _lazyExternalCopilotService = new Lazy(GetExternalService, LazyThreadSafetyMode.PublicationOnly); - - IExternalCSharpCopilotCodeAnalysisService GetExternalService() - => externalCopilotService ?? new ReflectionWrapper(serviceProvider, brokeredServiceContainer); - } - - protected override Task> AnalyzeDocumentCoreAsync(Document document, TextSpan? span, string promptTitle, CancellationToken cancellationToken) - => _lazyExternalCopilotService.Value.AnalyzeDocumentAsync(document, span, promptTitle, cancellationToken); - - protected override Task> GetAvailablePromptTitlesCoreAsync(Document document, CancellationToken cancellationToken) - => _lazyExternalCopilotService.Value.GetAvailablePromptTitlesAsync(document, cancellationToken); - - protected override Task> GetCachedDiagnosticsCoreAsync(Document document, string promptTitle, CancellationToken cancellationToken) - => _lazyExternalCopilotService.Value.GetCachedDiagnosticsAsync(document, promptTitle, cancellationToken); - - protected override Task IsAvailableCoreAsync(CancellationToken cancellationToken) - => _lazyExternalCopilotService.Value.IsAvailableAsync(cancellationToken); - - protected override Task StartRefinementSessionCoreAsync(Document oldDocument, Document newDocument, Diagnostic? primaryDiagnostic, CancellationToken cancellationToken) - => _lazyExternalCopilotService.Value.StartRefinementSessionAsync(oldDocument, newDocument, primaryDiagnostic, cancellationToken); - - protected override Task<(string responseString, bool isQuotaExceeded)> GetOnTheFlyDocsCoreAsync(string symbolSignature, ImmutableArray declarationCode, string language, CancellationToken cancellationToken) - => _lazyExternalCopilotService.Value.GetOnTheFlyDocsAsync(symbolSignature, declarationCode, language, cancellationToken); - - protected override async Task> GetDiagnosticsIntersectWithSpanAsync( - Document document, IReadOnlyList diagnostics, TextSpan span, CancellationToken cancellationToken) - { - using var _ = ArrayBuilder.GetInstance(out var filteredDiagnostics); - - // The location of Copilot diagnostics is on the method identifier, we'd like to expand the range to include them - // if any part of the method intersects with the given span. - var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var syntaxFacts = document.GetRequiredLanguageService(); - - foreach (var diagnostic in diagnostics) - { - var containingMethod = syntaxFacts.GetContainingMethodDeclaration(root, diagnostic.Location.SourceSpan.Start, useFullSpan: false); - if (containingMethod?.Span.IntersectsWith(span) is true) - filteredDiagnostics.Add(diagnostic); - } - - return filteredDiagnostics.ToImmutable(); - } - - protected override Task IsFileExcludedCoreAsync(string filePath, CancellationToken cancellationToken) - => _lazyExternalCopilotService.Value.IsFileExcludedAsync(filePath, cancellationToken); -} diff --git a/src/EditorFeatures/ExternalAccess/Copilot/InternalAPI.Unshipped.txt b/src/EditorFeatures/ExternalAccess/Copilot/InternalAPI.Unshipped.txt deleted file mode 100644 index 546acd188e8fa..0000000000000 --- a/src/EditorFeatures/ExternalAccess/Copilot/InternalAPI.Unshipped.txt +++ /dev/null @@ -1,23 +0,0 @@ -#nullable enable -Microsoft.CodeAnalysis.ExternalAccess.Copilot.CodeMapper.ICSharpCopilotMapCodeService -Microsoft.CodeAnalysis.ExternalAccess.Copilot.CodeMapper.ICSharpCopilotMapCodeService.MapCodeAsync(Microsoft.CodeAnalysis.Document! document, System.Collections.Immutable.ImmutableArray contents, System.Collections.Immutable.ImmutableArray<(Microsoft.CodeAnalysis.Document! document, Microsoft.CodeAnalysis.Text.TextSpan textSpan)> prioritizedFocusLocations, System.Collections.Generic.Dictionary! options, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task?>! -Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotChecksumWrapper -Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotChecksumWrapper.Equals(Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotChecksumWrapper? other) -> bool -Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotUtilities -Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotCodeAnalysisService -Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotCodeAnalysisService.AnalyzeDocumentAsync(Microsoft.CodeAnalysis.Document! document, Microsoft.CodeAnalysis.Text.TextSpan? span, string! promptTitle, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task>! -Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotCodeAnalysisService.GetAvailablePromptTitlesAsync(Microsoft.CodeAnalysis.Document! document, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task>! -Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotCodeAnalysisService.GetCachedDiagnosticsAsync(Microsoft.CodeAnalysis.Document! document, string! promptTitle, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task>! -Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotCodeAnalysisService.GetOnTheFlyDocsAsync(string! symbolSignature, System.Collections.Immutable.ImmutableArray declarationCode, string! language, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task<(string! responseString, bool isQuotaExceeded)>! -Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotCodeAnalysisService.IsAvailableAsync(System.Threading.CancellationToken cancellation) -> System.Threading.Tasks.Task! -Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotCodeAnalysisService.IsFileExcludedAsync(string! filePath, System.Threading.CancellationToken cancellationToken) -> 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! -static Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotUtilities.GetContainingMethodDeclarationAsync(Microsoft.CodeAnalysis.Document! document, int position, bool useFullSpan, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task! -static Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotUtilities.GetCopilotSuggestionDiagnosticTag() -> string! -static Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotUtilities.IsResultantVisibilityPublic(this Microsoft.CodeAnalysis.ISymbol! symbol) -> bool -static Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotUtilities.IsValidIdentifier(string? name) -> bool diff --git a/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs b/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs index 1b777a72a585c..149dd06940b05 100644 --- a/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs +++ b/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs @@ -12,13 +12,13 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Diagnostics.EngineV2; using Microsoft.CodeAnalysis.Editor.Implementation.Suggestions; using Microsoft.CodeAnalysis.ErrorLogger; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Extensions; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Serialization; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SolutionCrawler; using Microsoft.CodeAnalysis.Test.Utilities; @@ -43,7 +43,7 @@ public async Task TestGetFirstDiagnosticWithFixAsync() "; using var workspace = TestWorkspace.CreateCSharp(code, composition: s_compositionWithMockDiagnosticUpdateSourceRegistrationService, openDocuments: true); - var diagnosticService = Assert.IsType(workspace.GetService()); + var diagnosticService = workspace.GetService(); var analyzerReference = new TestAnalyzerReferenceByLanguage(DiagnosticExtensions.GetCompilerDiagnosticAnalyzersMap()); workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); @@ -78,7 +78,7 @@ public async Task TestGetFixesAsyncWithDuplicateDiagnostics() var tuple = ServiceSetup(codeFix); using var workspace = tuple.workspace; - GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, out var extensionManager, analyzerReference); + GetDocumentAndExtensionManager(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), CancellationToken.None); @@ -105,7 +105,7 @@ public async Task TestGetFixesAsyncHasNoDuplicateConfigurationActions() var tuple = ServiceSetup(codeFix, includeConfigurationFixProviders: true); using var workspace = tuple.workspace; - GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, out var extensionManager, analyzerReference); + GetDocumentAndExtensionManager(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), CancellationToken.None); @@ -136,7 +136,7 @@ public async Task TestGetFixesAsyncForFixableAndNonFixableAnalyzersAsync() var tuple = ServiceSetup(codeFix, includeConfigurationFixProviders: true); using var workspace = tuple.workspace; - GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, out var extensionManager, analyzerReference); + GetDocumentAndExtensionManager(workspace, out var document, out var extensionManager, analyzerReference); // Verify only analyzerWithFix is executed when GetFixesAsync is invoked with 'CodeActionRequestPriority.Normal'. _ = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), @@ -172,7 +172,7 @@ public async Task TestGetFixesAsyncForDocumentDiagnosticAnalyzerAsync() var tuple = ServiceSetup(codeFix, includeConfigurationFixProviders: false); using var workspace = tuple.workspace; - GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, out var extensionManager, analyzerReference); + GetDocumentAndExtensionManager(workspace, out var document, out var extensionManager, analyzerReference); // Verify both analyzers are executed when GetFixesAsync is invoked with 'CodeActionRequestPriority.Normal'. _ = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), @@ -202,7 +202,7 @@ public async Task TestGetFixesAsyncForGeneratorDiagnosticAsync() var tuple = ServiceSetup(codeFix, includeConfigurationFixProviders: false); using var workspace = tuple.workspace; - GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, out var extensionManager, analyzerReference); + GetDocumentAndExtensionManager(workspace, out var document, out var extensionManager, analyzerReference); Assert.False(codeFix.Called); var fixCollectionSet = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), @@ -288,7 +288,7 @@ private static async Task> GetAddedFixesAsync( var errorReported = false; errorReportingService.OnError = message => errorReported = true; - GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, out var extensionManager); + GetDocumentAndExtensionManager(workspace, out var document, out var extensionManager); var reference = new MockAnalyzerReference(codefix, [diagnosticAnalyzer]); var project = workspace.CurrentSolution.Projects.Single().AddAnalyzerReference(reference); document = project.Documents.Single(); @@ -315,7 +315,7 @@ private static async Task GetFirstDiagnosticWithFixWithExceptionValidationAsync( var errorReported = false; errorReportingService.OnError = message => errorReported = true; - GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, out var extensionManager); + GetDocumentAndExtensionManager(workspace, out var document, out var extensionManager); var unused = await tuple.codeFixService.GetMostSevereFixAsync( document, TextSpan.FromBounds(0, 0), new DefaultCodeActionRequestPriorityProvider(), CancellationToken.None); Assert.True(extensionManager.IsDisabled(codefix)); @@ -323,7 +323,7 @@ private static async Task GetFirstDiagnosticWithFixWithExceptionValidationAsync( Assert.True(errorReported); } - private static (EditorTestWorkspace workspace, DiagnosticAnalyzerService analyzerService, CodeFixService codeFixService, IErrorLoggerService errorLogger) ServiceSetup( + private static (EditorTestWorkspace workspace, IDiagnosticAnalyzerService analyzerService, CodeFixService codeFixService, IErrorLoggerService errorLogger) ServiceSetup( CodeFixProvider codefix, bool includeConfigurationFixProviders = false, bool throwExceptionInFixerCreation = false, @@ -331,7 +331,7 @@ private static (EditorTestWorkspace workspace, DiagnosticAnalyzerService analyze string code = "class Program { }") => ServiceSetup([codefix], includeConfigurationFixProviders, throwExceptionInFixerCreation, additionalDocument, code); - private static (EditorTestWorkspace workspace, DiagnosticAnalyzerService analyzerService, CodeFixService codeFixService, IErrorLoggerService errorLogger) ServiceSetup( + private static (EditorTestWorkspace workspace, IDiagnosticAnalyzerService analyzerService, CodeFixService codeFixService, IErrorLoggerService errorLogger) ServiceSetup( ImmutableArray codefixers, bool includeConfigurationFixProviders = false, bool throwExceptionInFixerCreation = false, @@ -355,7 +355,7 @@ private static (EditorTestWorkspace workspace, DiagnosticAnalyzerService analyze var analyzerReference = new TestAnalyzerReferenceByLanguage(DiagnosticExtensions.GetCompilerDiagnosticAnalyzersMap()); workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); - var diagnosticService = Assert.IsType(workspace.GetService()); + var diagnosticService = workspace.GetService(); var logger = SpecializedCollections.SingletonEnumerable(new Lazy(() => new TestErrorLogger())); var errorLogger = logger.First().Value; @@ -373,25 +373,13 @@ private static (EditorTestWorkspace workspace, DiagnosticAnalyzerService analyze } private static void GetDocumentAndExtensionManager( - DiagnosticAnalyzerService diagnosticService, EditorTestWorkspace workspace, out TextDocument document, out EditorLayerExtensionManager.ExtensionManager extensionManager, MockAnalyzerReference? analyzerReference = null, - TextDocumentKind documentKind = TextDocumentKind.Document) - => GetDocumentAndExtensionManager(diagnosticService, workspace, out document, out extensionManager, out _, analyzerReference, documentKind); - - private static void GetDocumentAndExtensionManager( - DiagnosticAnalyzerService diagnosticService, - EditorTestWorkspace workspace, - out TextDocument document, - out EditorLayerExtensionManager.ExtensionManager extensionManager, - out DiagnosticIncrementalAnalyzer diagnosticIncrementalAnalyzer, - MockAnalyzerReference? analyzerReference = null, TextDocumentKind documentKind = TextDocumentKind.Document) { // register diagnostic engine to solution crawler - diagnosticIncrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace)!; var reference = analyzerReference ?? new MockAnalyzerReference(); var project = workspace.CurrentSolution.Projects.Single().AddAnalyzerReference(reference); @@ -442,7 +430,8 @@ public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) } } - private class MockAnalyzerReference : AnalyzerReference, ICodeFixProviderFactory + private class MockAnalyzerReference + : AnalyzerReference, ICodeFixProviderFactory, SerializerService.TestAccessor.IAnalyzerReferenceWithGuid { public readonly ImmutableArray Fixers; public readonly ImmutableArray Analyzers; @@ -503,6 +492,8 @@ public override object Id } } + public Guid Guid { get; } = Guid.NewGuid(); + public override ImmutableArray GetAnalyzers(string language) => Analyzers; @@ -766,7 +757,7 @@ private static async Task> GetNuGetAndVsixCode using var workspace = TestWorkspace.CreateCSharp(code, composition: s_compositionWithMockDiagnosticUpdateSourceRegistrationService, openDocuments: true); - var diagnosticService = Assert.IsType(workspace.GetService()); + var diagnosticService = workspace.GetService(); var logger = SpecializedCollections.SingletonEnumerable(new Lazy(() => workspace.Services.GetRequiredService())); var fixService = new CodeFixService( @@ -879,7 +870,7 @@ public async Task TestAdditionalDocumentCodeFixAsync() // Verify available code fixes for .txt additional document 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); + GetDocumentAndExtensionManager(workspace, out var txtDocument, out var extensionManager, analyzerReference, documentKind: TextDocumentKind.AdditionalDocument); 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(); @@ -896,7 +887,7 @@ public async Task TestAdditionalDocumentCodeFixAsync() // Verify available code fixes for .log additional document 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); + GetDocumentAndExtensionManager(workspace2, out var logDocument, out extensionManager, analyzerReference, documentKind: TextDocumentKind.AdditionalDocument); 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; @@ -999,6 +990,15 @@ public async Task TestGetFixesWithDeprioritizedAnalyzerAsync( bool editOnFixLine, bool addNewLineWithEdit) { + // Disable these cases due to: + // https://github.com/dotnet/roslyn/issues/77036 + if (actionKind is DeprioritizedAnalyzer.ActionKind.SemanticModel or DeprioritizedAnalyzer.ActionKind.SymbolStartEnd && + diagnosticOnFixLineInPriorSnapshot && + !addNewLineWithEdit) + { + return; + } + // This test validates analyzer de-prioritization logic in diagnostic service for lightbulb code path. // Basically, we have a certain set of heuristics (detailed in the next comment below), under which an analyzer // which is deemed to be an expensive analyzer is moved down from 'Normal' priority code fix bucket to @@ -1033,8 +1033,9 @@ void M() var tuple = ServiceSetup(codeFix, code: code); using var workspace = tuple.workspace; - GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, - out var extensionManager, out var diagnosticIncrementalAnalyzer, analyzerReference); + var analyzerService = tuple.analyzerService; + GetDocumentAndExtensionManager(workspace, out var document, + out var extensionManager, analyzerReference); var sourceDocument = (Document)document; var root = await sourceDocument.GetRequiredSyntaxRootAsync(CancellationToken.None); @@ -1046,8 +1047,9 @@ void M() // We enable full solution analysis so the 'AnalyzeDocumentAsync' doesn't skip analysis based on whether the document is active/open. workspace.GlobalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, BackgroundAnalysisScope.FullSolution); - await diagnosticIncrementalAnalyzer.ForceAnalyzeProjectAsync(sourceDocument.Project, CancellationToken.None); - await VerifyCachedDiagnosticsAsync(sourceDocument, expectedCachedDiagnostic: diagnosticOnFixLineInPriorSnapshot, testSpan, diagnosticIncrementalAnalyzer); + var diagnostics = await analyzerService.ForceAnalyzeProjectAsync(sourceDocument.Project, CancellationToken.None); + await VerifyCachedDiagnosticsAsync( + sourceDocument, expectedCachedDiagnostic: diagnosticOnFixLineInPriorSnapshot, testSpan, diagnostics); // Compute and apply code edit if (editOnFixLine) @@ -1076,10 +1078,10 @@ void M() ? root.DescendantNodes().OfType().First().Span : root.DescendantNodes().OfType().First().Span; - await diagnosticIncrementalAnalyzer.GetDiagnosticsForIdsAsync( - sourceDocument.Project.Solution, sourceDocument.Project.Id, sourceDocument.Id, diagnosticIds: null, shouldIncludeAnalyzer: null, getDocuments: null, + await analyzerService.GetDiagnosticsForIdsAsync( + sourceDocument.Project, sourceDocument.Id, diagnosticIds: null, shouldIncludeAnalyzer: null, includeLocalDocumentDiagnostics: true, includeNonLocalDocumentDiagnostics: true, CancellationToken.None); - await diagnosticIncrementalAnalyzer.GetTestAccessor().TextDocumentOpenAsync(sourceDocument); + // await diagnosticIncrementalAnalyzer.GetTestAccessor().TextDocumentOpenAsync(sourceDocument); var lowPriorityAnalyzerData = new SuggestedActionPriorityProvider.LowPriorityAnalyzersAndDiagnosticIds(); var priorityProvider = new SuggestedActionPriorityProvider(CodeActionRequestPriority.Default, lowPriorityAnalyzerData); @@ -1139,10 +1141,12 @@ static bool GetExpectDeprioritization( return addNewLineWithEdit; } - static async Task VerifyCachedDiagnosticsAsync(Document sourceDocument, bool expectedCachedDiagnostic, TextSpan testSpan, DiagnosticIncrementalAnalyzer diagnosticIncrementalAnalyzer) + static async Task VerifyCachedDiagnosticsAsync( + Document sourceDocument, + bool expectedCachedDiagnostic, + TextSpan testSpan, + ImmutableArray cachedDiagnostics) { - var cachedDiagnostics = await diagnosticIncrementalAnalyzer.GetCachedDiagnosticsAsync(sourceDocument.Project.Solution, sourceDocument.Project.Id, sourceDocument.Id, - includeLocalDocumentDiagnostics: true, includeNonLocalDocumentDiagnostics: true, CancellationToken.None); cachedDiagnostics = cachedDiagnostics.WhereAsArray(d => !d.IsSuppressed); if (!expectedCachedDiagnostic) diff --git a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.CSharp.cs b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.CSharp.cs index b788abaaf22a3..247b8c5923e3b 100644 --- a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.CSharp.cs +++ b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.CSharp.cs @@ -1334,6 +1334,50 @@ await Assert.ThrowsAsync(async () => await TestAddAttributeAsync(input, expected, typeof(SerializableAttribute), RefKeyword)); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)] + public async Task AddAttributeWithArrayParams() + { + var input = """ + using System; + class ExampleAttribute : Attribute + { + public ExampleAttribute(int[] items) { } + } + class ExampleType + { + [Example(new[] { 1, 2, 3 })] + public void {|method:M|}() { } + } + class C + { + public void [|M|]2() { } + } + """; + var expected = """ + using System; + class ExampleAttribute : Attribute + { + public ExampleAttribute(int[] items) { } + } + class ExampleType + { + [Example(new[] { 1, 2, 3 })] + public void M() { } + } + class C + { + [Example(new[] { 1, 2, 3 })] + public void M2() { } + } + """; + await TestAddAttributeAsync(input, expected, (context) => + { + var method = context.GetAnnotatedDeclaredSymbols("method", context.SemanticModel).Single(); + var attribute = method.GetAttributes().Single(); + return attribute; + }); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)] public async Task RemoveAttributeWithTrivia() { diff --git a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs index 9ef1f3e876c23..0fbbfb405b851 100644 --- a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs +++ b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs @@ -16,7 +16,6 @@ using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Test.Utilities; @@ -526,19 +525,34 @@ internal static async Task TestAddNamedTypeAsync( CancellationToken.None); } - internal static async Task TestAddAttributeAsync( + internal static Task TestAddAttributeAsync( string initial, string expected, Type attributeClass, SyntaxToken? target = null) + { + return TestAddAttributeAsync(initial, expected, (testContext) => + { + var attr = CodeGenerationSymbolFactory.CreateAttributeData(GetTypeSymbol(attributeClass)(testContext.SemanticModel)); + return attr; + }, target); + } + + internal static async Task TestAddAttributeAsync( + string initial, + string expected, + Func attributeToGenerate, + SyntaxToken? target = null) { using var testContext = await TestContext.CreateAsync(initial, expected); - var attr = CodeGenerationSymbolFactory.CreateAttributeData(GetTypeSymbol(attributeClass)(testContext.SemanticModel)); + + var attributeData = attributeToGenerate(testContext); + var oldNode = testContext.GetDestinationNode(); 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, [attr], target, info, CancellationToken.None) + var newNode = codeGenerator.AddAttributes(oldNode, [attributeData], 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/Completion/FileSystemCompletionHelperTests.cs b/src/EditorFeatures/Test/Completion/FileSystemCompletionHelperTests.cs index d753286bb6498..54ebad543cd5d 100644 --- a/src/EditorFeatures/Test/Completion/FileSystemCompletionHelperTests.cs +++ b/src/EditorFeatures/Test/Completion/FileSystemCompletionHelperTests.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Immutable; using System.Linq; using System.Threading; diff --git a/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs index 000c997aa4adf..1cdbde9790790 100644 --- a/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs @@ -12,13 +12,12 @@ using Microsoft.CodeAnalysis.CSharp.RemoveUnnecessarySuppressions; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Diagnostics.CSharp; -using Microsoft.CodeAnalysis.Editor.Test; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Remote.Diagnostics; using Microsoft.CodeAnalysis.Remote.Testing; +using Microsoft.CodeAnalysis.Serialization; using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.SolutionCrawler; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; @@ -63,12 +62,11 @@ public async Task TestHasSuccessfullyLoadedBeingFalse() var document = GetDocumentFromIncompleteProject(workspace); var exportProvider = workspace.Services.SolutionServices.ExportProvider; - var service = Assert.IsType(exportProvider.GetExportedValue()); - var analyzer = service.CreateIncrementalAnalyzer(workspace); + var service = exportProvider.GetExportedValue(); var globalOptions = exportProvider.GetExportedValue(); - var diagnostics = await analyzer.GetDiagnosticsForIdsAsync( - workspace.CurrentSolution, projectId: null, documentId: null, diagnosticIds: null, shouldIncludeAnalyzer: null, getDocuments: null, + var diagnostics = await service.GetDiagnosticsForIdsAsync( + workspace.CurrentSolution.Projects.Single(), documentId: null, diagnosticIds: null, shouldIncludeAnalyzer: null, includeLocalDocumentDiagnostics: true, includeNonLocalDocumentDiagnostics: false, CancellationToken.None); Assert.NotEmpty(diagnostics); } @@ -178,8 +176,7 @@ public async Task TestDisabledByDefaultAnalyzerEnabledWithEditorConfig(bool enab Assert.True(applied); var exportProvider = workspace.Services.SolutionServices.ExportProvider; - var service = Assert.IsType(exportProvider.GetExportedValue()); - var analyzer = service.CreateIncrementalAnalyzer(workspace); + var service = exportProvider.GetExportedValue(); // listen to events var syntaxDiagnostic = false; @@ -189,7 +186,7 @@ public async Task TestDisabledByDefaultAnalyzerEnabledWithEditorConfig(bool enab // open document workspace.OpenDocument(document.Id); - var diagnostics = await analyzer.ForceAnalyzeProjectAsync(document.Project, CancellationToken.None); + var diagnostics = await service.ForceAnalyzeProjectAsync(document.Project, CancellationToken.None); foreach (var diagnostic in diagnostics) { @@ -220,14 +217,12 @@ private static async Task TestAnalyzerAsync( { var exportProvider = workspace.Services.SolutionServices.ExportProvider; - var service = Assert.IsType(exportProvider.GetExportedValue()); - - var analyzer = service.CreateIncrementalAnalyzer(workspace); + var service = exportProvider.GetExportedValue(); var syntax = false; var semantic = false; - var diagnostics = await analyzer.ForceAnalyzeProjectAsync(document.Project, CancellationToken.None); + var diagnostics = await service.ForceAnalyzeProjectAsync(document.Project, CancellationToken.None); (syntax, semantic) = resultSetter(syntax, semantic, diagnostics); @@ -266,8 +261,7 @@ public async Task TestHostAnalyzerOrderingAsync() var service = Assert.IsType(exportProvider.GetExportedValue()); - var incrementalAnalyzer = service.CreateIncrementalAnalyzer(workspace); - var analyzers = await incrementalAnalyzer.GetAnalyzersTestOnlyAsync(project, CancellationToken.None).ConfigureAwait(false); + var analyzers = await service.GetTestAccessor().GetAnalyzersAsync(project, CancellationToken.None).ConfigureAwait(false); var analyzersArray = analyzers.ToArray(); AssertEx.Equal( @@ -314,10 +308,9 @@ public async Task TestHostAnalyzerErrorNotLeaking() filePath: "test.cs")])); var exportProvider = workspace.Services.SolutionServices.ExportProvider; - var service = Assert.IsType(exportProvider.GetExportedValue()); + var service = exportProvider.GetExportedValue(); - var incrementalAnalyzer = service.CreateIncrementalAnalyzer(workspace); - var diagnostics = await incrementalAnalyzer.ForceAnalyzeProjectAsync(project, CancellationToken.None); + var diagnostics = await service.ForceAnalyzeProjectAsync(project, CancellationToken.None); Assert.NotEmpty(diagnostics); } @@ -400,10 +393,9 @@ private static AdhocWorkspace CreateWorkspaceWithProjectAndAnalyzer(DiagnosticAn private static async Task TestFullSolutionAnalysisForProjectAsync(AdhocWorkspace workspace, Project project, bool expectAnalyzerExecuted) { var exportProvider = workspace.Services.SolutionServices.ExportProvider; - var service = Assert.IsType(exportProvider.GetExportedValue()); + var service = exportProvider.GetExportedValue(); - var incrementalAnalyzer = service.CreateIncrementalAnalyzer(project.Solution.Workspace); - var diagnostics = await incrementalAnalyzer.ForceAnalyzeProjectAsync(project, CancellationToken.None); + var diagnostics = await service.ForceAnalyzeProjectAsync(project, CancellationToken.None); if (expectAnalyzerExecuted) { @@ -442,18 +434,18 @@ internal async Task TestAdditionalFileAnalyzer(bool registerFromInitialize, bool project = project.AddAdditionalDocument(name: "dummy2.txt", text: "Additional File2 Text", filePath: "dummy2.txt").Project; } + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences); var applied = workspace.TryApplyChanges(project.Solution); Assert.True(applied); var exportProvider = workspace.Services.SolutionServices.ExportProvider; - var service = Assert.IsType(exportProvider.GetExportedValue()); + var service = exportProvider.GetExportedValue(); - var incrementalAnalyzer = service.CreateIncrementalAnalyzer(workspace); var firstAdditionalDocument = project.AdditionalDocuments.FirstOrDefault(); workspace.OpenAdditionalDocument(firstAdditionalDocument.Id); - var diagnostics = await incrementalAnalyzer.ForceAnalyzeProjectAsync(project, CancellationToken.None); + var diagnostics = await service.ForceAnalyzeProjectAsync(project, CancellationToken.None); var expectedCount = testMultiple ? 4 : 1; @@ -511,11 +503,9 @@ internal async Task TestDiagnosticSuppressor(bool includeAnalyzer, bool includeS var project = workspace.CurrentSolution.Projects.Single(); var document = project.Documents.Single(); - var service = Assert.IsType(workspace.GetService()); + var service = workspace.GetService(); var globalOptions = workspace.GetService(); - var incrementalAnalyzer = service.CreateIncrementalAnalyzer(workspace); - switch (analysisScope) { case BackgroundAnalysisScope.None: @@ -536,7 +526,7 @@ internal async Task TestDiagnosticSuppressor(bool includeAnalyzer, bool includeS throw ExceptionUtilities.UnexpectedValue(analysisScope); } - var diagnostics = await incrementalAnalyzer.ForceAnalyzeProjectAsync(project, CancellationToken.None); + var diagnostics = await service.ForceAnalyzeProjectAsync(project, CancellationToken.None); var diagnostic = diagnostics.SingleOrDefault(); if (includeAnalyzer) @@ -630,12 +620,10 @@ void M() else Assert.IsType(document); - var service = Assert.IsType(workspace.GetService()); + var service = workspace.GetService(); var text = await document.GetTextAsync(); - var incrementalAnalyzer = service.CreateIncrementalAnalyzer(workspace); - switch (analysisScope) { case BackgroundAnalysisScope.None: @@ -661,7 +649,7 @@ void M() break; } - var diagnostics = await incrementalAnalyzer.ForceAnalyzeProjectAsync(project, CancellationToken.None); + var diagnostics = await service.ForceAnalyzeProjectAsync(project, CancellationToken.None); diagnostics = [.. diagnostics .Where(d => d.Id == IDEDiagnosticIds.RemoveUnnecessarySuppressionDiagnosticId) @@ -870,10 +858,9 @@ internal async Task TestGeneratorProducedDiagnostics(bool fullSolutionAnalysis, workspace.OpenDocument(document.Id); } - var service = Assert.IsType(workspace.GetService()); + var service = workspace.GetService(); - var incrementalAnalyzer = service.CreateIncrementalAnalyzer(workspace); - var diagnostics = await incrementalAnalyzer.ForceAnalyzeProjectAsync(project, CancellationToken.None); + var diagnostics = await service.ForceAnalyzeProjectAsync(project, CancellationToken.None); Assert.NotEmpty(diagnostics); } diff --git a/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs b/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs index 36980fea3c6c2..b30dc02875c8f 100644 --- a/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs @@ -38,7 +38,8 @@ public class IDEDiagnosticIDConfigurationTests ValidateHelpLinkForDiagnostic(diagnosticId, descriptor.HelpLinkUri); if (diagnosticId.StartsWith("ENC") || - !char.IsDigit(diagnosticId[^1])) + !char.IsDigit(diagnosticId[^1]) || + diagnosticId == IDEDiagnosticIds.CopilotImplementNotImplementedExceptionDiagnosticId) { // Ignore non-IDE diagnostic IDs (such as ENCxxxx diagnostics) and // diagnostic IDs for suggestions, fading, etc. (such as IDExxxxWithSuggestion) diff --git a/src/EditorFeatures/Test/Diagnostics/SuppressMessageAttributeWorkspaceTests.cs b/src/EditorFeatures/Test/Diagnostics/SuppressMessageAttributeWorkspaceTests.cs index 55e0553125946..cc4f1a61e97ed 100644 --- a/src/EditorFeatures/Test/Diagnostics/SuppressMessageAttributeWorkspaceTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/SuppressMessageAttributeWorkspaceTests.cs @@ -5,7 +5,6 @@ #nullable disable using System; -using System.Collections.Immutable; using System.Linq; using System.Runtime.ExceptionServices; using System.Threading; diff --git a/src/LanguageServer/ProtocolUnitTests/VSTypeScriptHandlerTests.cs b/src/EditorFeatures/Test/LanguageServer/VSTypeScriptHandlerTests.cs similarity index 65% rename from src/LanguageServer/ProtocolUnitTests/VSTypeScriptHandlerTests.cs rename to src/EditorFeatures/Test/LanguageServer/VSTypeScriptHandlerTests.cs index 043c8670f2733..4dc75d28322d7 100644 --- a/src/LanguageServer/ProtocolUnitTests/VSTypeScriptHandlerTests.cs +++ b/src/EditorFeatures/Test/LanguageServer/VSTypeScriptHandlerTests.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Immutable; +using System.Collections.Generic; using System.Composition; using System.IO; using System.Linq; @@ -13,23 +13,27 @@ using Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript; using Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.LanguageServer; using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CommonLanguageServerProtocol.Framework; using Roslyn.LanguageServer.Protocol; -using Nerdbank.Streams; using Roslyn.Test.Utilities; using StreamJsonRpc; using Xunit; using Xunit.Abstractions; -namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests; +namespace Microsoft.CodeAnalysis.Editor.UnitTests.LanguageServer; + public class VSTypeScriptHandlerTests : AbstractLanguageServerProtocolTests { public VSTypeScriptHandlerTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } - protected override TestComposition Composition => base.Composition.AddParts(typeof(TypeScriptHandlerFactory)); + protected override TestComposition Composition => EditorTestCompositions.LanguageServerProtocolEditorFeatures + .AddParts(typeof(TypeScriptHandlerFactory)) + .AddParts(typeof(TestWorkspaceRegistrationService)); [Fact] public async Task TestExternalAccessTypeScriptHandlerInvoked() @@ -88,43 +92,50 @@ public async Task TestGetSimplifierOptionsOnTypeScriptDocument() Assert.Same(SimplifierOptions.CommonDefaults, simplifierOptions); } - private async Task CreateTsTestLspServerAsync(string workspaceXml, InitializationOptions? options = null) + private async Task CreateTsTestLspServerAsync(string workspaceXml, InitializationOptions? options = null) { - var (clientStream, serverStream) = FullDuplexStream.CreatePair(); - var testWorkspace = CreateWorkspace(options, mutatingLspWorkspace: false, workspaceKind: null); testWorkspace.InitializeDocuments(XElement.Parse(workspaceXml), openDocuments: false); - // Ensure workspace operations are completed so we don't get unexpected workspace changes while running. - await WaitForWorkspaceOperationsAsync(testWorkspace); - var languageServerTarget = CreateLanguageServer(serverStream, serverStream, testWorkspace); - - return await TestLspServer.CreateAsync(testWorkspace, new ClientCapabilities(), languageServerTarget, clientStream); + return await VSTypeScriptTestLspServer.CreateAsync(testWorkspace, new InitializationOptions(), TestOutputLspLogger); } - private static RoslynLanguageServer CreateLanguageServer(Stream inputStream, Stream outputStream, EditorTestWorkspace workspace) + private class VSTypeScriptTestLspServer : AbstractTestLspServer { - var capabilitiesProvider = workspace.ExportProvider.GetExportedValue(); - var servicesProvider = workspace.ExportProvider.GetExportedValue(); - - var messageFormatter = RoslynLanguageServer.CreateJsonMessageFormatter(); - var jsonRpc = new JsonRpc(new HeaderDelimitedMessageHandler(outputStream, inputStream, messageFormatter)) + public VSTypeScriptTestLspServer(LspTestWorkspace testWorkspace, Dictionary> locations, InitializationOptions options, AbstractLspLogger logger) : base(testWorkspace, locations, options, logger) { - ExceptionStrategy = ExceptionProcessing.ISerializable, - }; - - var logger = NoOpLspLogger.Instance; + } - var languageServer = new RoslynLanguageServer( - servicesProvider, jsonRpc, messageFormatter.JsonSerializerOptions, - capabilitiesProvider, - logger, - workspace.Services.HostServices, - [InternalLanguageNames.TypeScript], - WellKnownLspServerKinds.RoslynTypeScriptLspServer); + protected override RoslynLanguageServer CreateLanguageServer(Stream inputStream, Stream outputStream, WellKnownLspServerKinds serverKind, AbstractLspLogger logger) + { + var capabilitiesProvider = TestWorkspace.ExportProvider.GetExportedValue(); + var servicesProvider = TestWorkspace.ExportProvider.GetExportedValue(); + + var messageFormatter = RoslynLanguageServer.CreateJsonMessageFormatter(); + var jsonRpc = new JsonRpc(new HeaderDelimitedMessageHandler(outputStream, inputStream, messageFormatter)) + { + ExceptionStrategy = ExceptionProcessing.ISerializable, + }; + + var languageServer = new RoslynLanguageServer( + servicesProvider, jsonRpc, messageFormatter.JsonSerializerOptions, + capabilitiesProvider, + logger, + TestWorkspace.Services.HostServices, + [InternalLanguageNames.TypeScript], + WellKnownLspServerKinds.RoslynTypeScriptLspServer); + + jsonRpc.StartListening(); + return languageServer; + } - jsonRpc.StartListening(); - return languageServer; + public static async Task CreateAsync(LspTestWorkspace testWorkspace, InitializationOptions options, AbstractLspLogger logger) + { + var locations = await GetAnnotatedLocationsAsync(testWorkspace, testWorkspace.CurrentSolution); + var server = new VSTypeScriptTestLspServer(testWorkspace, locations, options, logger); + await server.InitializeAsync(); + return server; + } } internal record TSRequest(Uri Document, string Project); diff --git a/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.TestContext.cs b/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.TestContext.cs index 8e00e418bd095..f256667745074 100644 --- a/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.TestContext.cs +++ b/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.TestContext.cs @@ -4,14 +4,12 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.IO; using System.Linq; using System.Security; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.CSharp.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.DecompiledSource; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; diff --git a/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.cs b/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.cs index fe4012be38b86..8b5996b24782a 100644 --- a/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.cs +++ b/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.cs @@ -21,7 +21,7 @@ namespace Microsoft.CodeAnalysis.Editor.UnitTests.MetadataAsSource; [UseExportProvider] public abstract partial class AbstractMetadataAsSourceTests : IAsyncLifetime { - protected static readonly string ICSharpCodeDecompilerVersion = "8.1.1.7464"; + protected static readonly string ICSharpCodeDecompilerVersion = "8.2.0.7535"; public virtual Task InitializeAsync() { diff --git a/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs b/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs index 4cba03fd1ce5d..398e549ea00c1 100644 --- a/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs +++ b/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs @@ -2,9 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.MetadataAsSource; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; diff --git a/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.cs b/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.cs index e0c0bd654e729..eb25773dd2beb 100644 --- a/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.cs +++ b/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; -using Roslyn.Utilities; using Xunit; using CS = Microsoft.CodeAnalysis.CSharp; using VB = Microsoft.CodeAnalysis.VisualBasic; diff --git a/src/EditorFeatures/Test/RenameTracking/RenameTrackingTaggerProviderTests.cs b/src/EditorFeatures/Test/RenameTracking/RenameTrackingTaggerProviderTests.cs index 7f088bd377916..19b887caa37c0 100644 --- a/src/EditorFeatures/Test/RenameTracking/RenameTrackingTaggerProviderTests.cs +++ b/src/EditorFeatures/Test/RenameTracking/RenameTrackingTaggerProviderTests.cs @@ -6,7 +6,6 @@ using System; using System.Linq; -using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Implementation.RenameTracking; using Microsoft.CodeAnalysis.Test.Utilities; diff --git a/src/EditorFeatures/Test/StackTraceExplorer/StackTraceExplorerTests.cs b/src/EditorFeatures/Test/StackTraceExplorer/StackTraceExplorerTests.cs index cea9e8f436176..f498aabe36b78 100644 --- a/src/EditorFeatures/Test/StackTraceExplorer/StackTraceExplorerTests.cs +++ b/src/EditorFeatures/Test/StackTraceExplorer/StackTraceExplorerTests.cs @@ -32,8 +32,7 @@ private static async Task TestSymbolFoundAsync(string inputLine, string code) var reparsedResult = await StackTraceAnalyzer.AnalyzeAsync(stackFrame.ToString(), CancellationToken.None); Assert.Single(reparsedResult.ParsedFrames); - var reparsedFrame = reparsedResult.ParsedFrames[0] as ParsedStackFrame; - AssertEx.NotNull(reparsedFrame); + var reparsedFrame = Assert.IsType(reparsedResult.ParsedFrames[0]); StackFrameUtils.AssertEqual(stackFrame.Root, reparsedFrame.Root); // Get the definition for the parsed frame @@ -820,9 +819,9 @@ class C var result = await StackTraceAnalyzer.AnalyzeAsync(line, CancellationToken.None); Assert.Equal(1, result.ParsedFrames.Length); - var parsedFame = result.ParsedFrames.OfType().Single(); + var parsedFrame = Assert.IsType(result.ParsedFrames[0]); var service = workspace.Services.GetRequiredService(); - var definition = await service.TryFindDefinitionAsync(workspace.CurrentSolution, parsedFame, StackFrameSymbolPart.Method, CancellationToken.None); + var definition = await service.TryFindDefinitionAsync(workspace.CurrentSolution, parsedFrame, StackFrameSymbolPart.Method, CancellationToken.None); Assert.Null(definition); } @@ -850,13 +849,89 @@ public async Task TestMetadataSymbol() var result = await StackTraceAnalyzer.AnalyzeAsync("at System.String.ToLower()", CancellationToken.None); Assert.Single(result.ParsedFrames); - var frame = result.ParsedFrames[0] as ParsedStackFrame; - AssertEx.NotNull(frame); - + var frame = Assert.IsType(result.ParsedFrames[0]); var service = workspace.Services.GetRequiredService(); var definition = await service.TryFindDefinitionAsync(workspace.CurrentSolution, frame, StackFrameSymbolPart.Method, CancellationToken.None); AssertEx.NotNull(definition); Assert.Equal("String.ToLower", definition.NameDisplayParts.ToVisibleDisplayString(includeLeftToRightMarker: false)); } + + [Fact] + public async Task TestAdditionalFileExactMatchAsync() + { + using var workspace = TestWorkspace.Create( + """ + + + + class C + { + void M() {} + } + + + @page "/" + + @code + { + void M() + { + } + } + + + + """); + + var result = await StackTraceAnalyzer.AnalyzeAsync("at Path.To.Component.M() in C:/path/to/Component.razor:line 5", CancellationToken.None); + Assert.Single(result.ParsedFrames); + + var frame = Assert.IsType(result.ParsedFrames[0]); + var service = workspace.Services.GetRequiredService(); + var (document, line) = service.GetDocumentAndLine(workspace.CurrentSolution, frame); + Assert.Equal(5, line); + + AssertEx.NotNull(document); + Assert.Equal(@"C:/path/to/Component.razor", document.FilePath); + } + + [Fact] + public async Task TestAdditionalFileNameMatchAsync() + { + using var workspace = TestWorkspace.Create( + """ + + + + class C + { + void M() {} + } + + + @page "/" + + @code + { + void M() + { + } + } + + + + """); + + var result = await StackTraceAnalyzer.AnalyzeAsync("at Path.To.Component.M() in Component.razor:line 5", CancellationToken.None); + Assert.Single(result.ParsedFrames); + + var frame = Assert.IsType(result.ParsedFrames[0]); + var service = workspace.Services.GetRequiredService(); + var (document, line) = service.GetDocumentAndLine(workspace.CurrentSolution, frame); + Assert.Equal(5, line); + + AssertEx.NotNull(document); + Assert.Equal(@"C:/path/to/Component.razor", document.FilePath); + } } diff --git a/src/EditorFeatures/Test/Structure/StructureTaggerTests.cs b/src/EditorFeatures/Test/Structure/StructureTaggerTests.cs index 3d5e668a3686d..b5c377ac93e40 100644 --- a/src/EditorFeatures/Test/Structure/StructureTaggerTests.cs +++ b/src/EditorFeatures/Test/Structure/StructureTaggerTests.cs @@ -8,7 +8,6 @@ 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; diff --git a/src/EditorFeatures/Test/SymbolFinder/DependentTypeFinderTests.cs b/src/EditorFeatures/Test/SymbolFinder/DependentTypeFinderTests.cs index 7bc0ab4d97aeb..87f8dc0ae04d1 100644 --- a/src/EditorFeatures/Test/SymbolFinder/DependentTypeFinderTests.cs +++ b/src/EditorFeatures/Test/SymbolFinder/DependentTypeFinderTests.cs @@ -12,6 +12,7 @@ using Basic.Reference.Assemblies; using Microsoft.CodeAnalysis.Editor.UnitTests; using Microsoft.CodeAnalysis.FindSymbols; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Remote.Testing; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; @@ -36,7 +37,11 @@ private static Solution AddProjectWithMetadataReferences(Solution solution, stri projectName, languageName, metadataReferences: [metadataReference], - projectReferences: projectReferences.Select(p => new ProjectReference(p))); + projectReferences: projectReferences.Select(p => new ProjectReference(p)), + compilationOptions: solution.Services + .GetRequiredLanguageService(languageName) + .GetDefaultCompilationOptions() + .WithOutputKind(OutputKind.DynamicallyLinkedLibrary)); return solution.AddProject(pi).AddDocument(did, $"{projectName}.{suffix}", SourceText.From(code)); } diff --git a/src/EditorFeatures/Test/Utilities/AsynchronousOperationListenerTests.cs b/src/EditorFeatures/Test/Utilities/AsynchronousOperationListenerTests.cs index 010ed854b6fa1..697d94b619477 100644 --- a/src/EditorFeatures/Test/Utilities/AsynchronousOperationListenerTests.cs +++ b/src/EditorFeatures/Test/Utilities/AsynchronousOperationListenerTests.cs @@ -9,7 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Shared.TestHooks; -using Roslyn.Utilities; +using Microsoft.CodeAnalysis.Threading; using Xunit; namespace Microsoft.CodeAnalysis.Editor.UnitTests.Utilities; diff --git a/src/EditorFeatures/Test/Utilities/SymbolEquivalenceComparerTests.cs b/src/EditorFeatures/Test/Utilities/SymbolEquivalenceComparerTests.cs index 2494beeb52c7b..346b781d717a5 100644 --- a/src/EditorFeatures/Test/Utilities/SymbolEquivalenceComparerTests.cs +++ b/src/EditorFeatures/Test/Utilities/SymbolEquivalenceComparerTests.cs @@ -4,7 +4,6 @@ #nullable disable -using System; using System.Collections.Generic; using System.IO; using System.Linq; diff --git a/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb b/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb index f2daa492cf9c6..5176fb2119f8f 100644 --- a/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb +++ b/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb @@ -11,18 +11,20 @@ Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.Copilot Imports Microsoft.CodeAnalysis.Diagnostics +Imports Microsoft.CodeAnalysis.DocumentationComments Imports Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests Imports Microsoft.CodeAnalysis.Editor.UnitTests Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.ErrorLogger +Imports Microsoft.CodeAnalysis.FindSymbols Imports Microsoft.CodeAnalysis.Host Imports Microsoft.CodeAnalysis.Host.Mef +Imports Microsoft.CodeAnalysis.QuickInfo Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.UnitTests Imports Roslyn.Utilities Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests - <[UseExportProvider]> Public Class CodeFixServiceTests @@ -54,8 +56,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests Dim project = workspace.CurrentSolution.Projects(0) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) - Dim analyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() Dim logger = SpecializedCollections.SingletonEnumerable(New Lazy(Of IErrorLoggerService)(Function() workspace.Services.GetService(Of IErrorLoggerService))) Dim codefixService = New CodeFixService( diagnosticService, @@ -126,8 +127,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests Dim project = workspace.CurrentSolution.Projects(0) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) - Dim analyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() Dim logger = SpecializedCollections.SingletonEnumerable(New Lazy(Of IErrorLoggerService)(Function() workspace.Services.GetService(Of IErrorLoggerService))) Dim codefixService = New CodeFixService( diagnosticService, @@ -315,7 +315,15 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests Return Task.FromResult(True) End Function - Public Function IsOnTheFlyDocsOptionEnabledAsync() As Task(Of Boolean) Implements ICopilotOptionsService.IsOnTheFlyDocsOptionEnabledASync + Public Function IsOnTheFlyDocsOptionEnabledAsync() As Task(Of Boolean) Implements ICopilotOptionsService.IsOnTheFlyDocsOptionEnabledAsync + Return Task.FromResult(True) + End Function + + Public Function IsGenerateDocumentationCommentOptionEnabledAsync() As Task(Of Boolean) Implements ICopilotOptionsService.IsGenerateDocumentationCommentOptionEnabledAsync + Return Task.FromResult(True) + End Function + + Public Function IsImplementNotImplementedExceptionEnabledAsync() As Task(Of Boolean) Implements ICopilotOptionsService.IsImplementNotImplementedExceptionEnabledAsync Return Task.FromResult(True) End Function End Class @@ -351,13 +359,29 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests Return Task.CompletedTask End Function - Public Function GetOnTheFlyDocsAsync(symbolSignature As String, declarationCode As ImmutableArray(Of String), language As String, cancellationToken As CancellationToken) As Task(Of (responseString As String, isQuotaExceeded As Boolean)) Implements ICopilotCodeAnalysisService.GetOnTheFlyDocsAsync - Return Task.FromResult(("", False)) + Public Function IsFileExcludedAsync(filePath As String, cancellationToken As CancellationToken) As Task(Of Boolean) Implements ICopilotCodeAnalysisService.IsFileExcludedAsync + Return Task.FromResult(False) + End Function + + Public Function GetDocumentationCommentAsync(proposal As DocumentationCommentProposal, cancellationToken As CancellationToken) As Task(Of (responseDictionary As Dictionary(Of String, String), isQuotaExceeded As Boolean)) Implements ICopilotCodeAnalysisService.GetDocumentationCommentAsync + Return Task.FromResult((New Dictionary(Of String, String), False)) End Function - Public Function IsFileExcludedAsync(filePath As String, cancellationToken As CancellationToken) As Task(Of Boolean) Implements ICopilotCodeAnalysisService.IsFileExcludedAsync + Public Function GetOnTheFlyDocsPromptAsync(onTheFlyDocsInfo As OnTheFlyDocsInfo, cancellationToken As CancellationToken) As Task(Of String) Implements ICopilotCodeAnalysisService.GetOnTheFlyDocsPromptAsync + Return Task.FromResult(String.Empty) + End Function + + Public Function GetOnTheFlyDocsResponseAsync(prompt As String, cancellationToken As CancellationToken) As Task(Of (responseString As String, isQuotaExceeded As Boolean)) Implements ICopilotCodeAnalysisService.GetOnTheFlyDocsResponseAsync + Return Task.FromResult((String.Empty, False)) + End Function + + Public Function IsImplementNotImplementedExceptionsAvailableAsync(cancellationToken As CancellationToken) As Task(Of Boolean) Implements ICopilotCodeAnalysisService.IsImplementNotImplementedExceptionsAvailableAsync Return Task.FromResult(False) End Function + + Public Function ImplementNotImplementedExceptionsAsync(document As Document, methodOrProperties As ImmutableDictionary(Of SyntaxNode, ImmutableArray(Of ReferencedSymbol)), cancellationToken As CancellationToken) As Task(Of ImmutableDictionary(Of SyntaxNode, ImplementationDetails)) Implements ICopilotCodeAnalysisService.ImplementNotImplementedExceptionsAsync + Return Task.FromResult(ImmutableDictionary(Of SyntaxNode, ImplementationDetails).Empty) + End Function End Class End Class End Namespace diff --git a/src/EditorFeatures/Test2/Diagnostics/DiagnosticProviderTests.vb b/src/EditorFeatures/Test2/Diagnostics/DiagnosticProviderTests.vb index 6f7c36018d869..bbb8f0f4a8012 100644 --- a/src/EditorFeatures/Test2/Diagnostics/DiagnosticProviderTests.vb +++ b/src/EditorFeatures/Test2/Diagnostics/DiagnosticProviderTests.vb @@ -261,9 +261,13 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests Next Dim diagnosticProvider = GetDiagnosticProvider(workspace) - Dim actualDiagnostics = diagnosticProvider.GetDiagnosticsForIdsAsync( - workspace.CurrentSolution, projectId:=Nothing, documentId:=Nothing, diagnosticIds:=Nothing, shouldIncludeAnalyzer:=Nothing, - includeLocalDocumentDiagnostics:=True, includeNonLocalDocumentDiagnostics:=True, CancellationToken.None).Result + Dim actualDiagnostics = New List(Of DiagnosticData) + + For Each project In workspace.CurrentSolution.Projects + actualDiagnostics.AddRange(diagnosticProvider.GetDiagnosticsForIdsAsync( + project, documentId:=Nothing, diagnosticIds:=Nothing, shouldIncludeAnalyzer:=Nothing, + includeLocalDocumentDiagnostics:=True, includeNonLocalDocumentDiagnostics:=True, CancellationToken.None).Result) + Next If diagnostics Is Nothing Then Assert.Empty(actualDiagnostics) @@ -279,14 +283,14 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests End Using End Sub - Private Shared Function GetDiagnosticProvider(workspace As EditorTestWorkspace) As DiagnosticAnalyzerService + Private Shared Function GetDiagnosticProvider(workspace As EditorTestWorkspace) As IDiagnosticAnalyzerService Dim compilerAnalyzersMap = DiagnosticExtensions.GetCompilerDiagnosticAnalyzersMap().Add( NoCompilationConstants.LanguageName, ImmutableArray.Create(Of DiagnosticAnalyzer)(New NoCompilationDocumentDiagnosticAnalyzer())) Dim analyzerReference = New TestAnalyzerReferenceByLanguage(compilerAnalyzersMap) workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences({analyzerReference})) - Dim analyzerService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) + Dim analyzerService = workspace.GetService(Of IDiagnosticAnalyzerService)() Return analyzerService End Function diff --git a/src/EditorFeatures/Test2/Diagnostics/DiagnosticServiceTests.vb b/src/EditorFeatures/Test2/Diagnostics/DiagnosticServiceTests.vb index aa4ecdbe70240..9913c17cfea6b 100644 --- a/src/EditorFeatures/Test2/Diagnostics/DiagnosticServiceTests.vb +++ b/src/EditorFeatures/Test2/Diagnostics/DiagnosticServiceTests.vb @@ -13,6 +13,7 @@ Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.Diagnostics.CSharp Imports Microsoft.CodeAnalysis.Editor.UnitTests Imports Microsoft.CodeAnalysis.Host.Mef +Imports Microsoft.CodeAnalysis.Serialization Imports Microsoft.CodeAnalysis.SolutionCrawler Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.UnitTests.Diagnostics @@ -85,7 +86,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests Dim hostAnalyzers = solution.SolutionState.Analyzers Dim project = solution.Projects(0) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() ' Verify available diagnostic descriptors/analyzers Dim descriptorsMap = hostAnalyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project) @@ -95,7 +96,6 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests Assert.Equal(workspaceDiagnosticAnalyzer.DiagDescriptor.Id, descriptors(0).Id) Dim document = project.Documents.Single() - Dim analyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) Dim diagnostics = Await GetDiagnosticsForDocumentAsync(diagnosticService, document) Assert.Equal(1, diagnostics.Length) @@ -105,6 +105,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests Dim projectAnalyzerReference1 = New AnalyzerImageReference(projectAnalyzers1, display:=NameOf(projectAnalyzers1)) Dim projectAnalyzerReferences1 = ImmutableArray.Create(Of AnalyzerReference)(projectAnalyzerReference1) project = project.WithAnalyzerReferences(projectAnalyzerReferences1) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) ' Verify available diagnostic descriptors/analyzers descriptorsMap = hostAnalyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project) @@ -120,6 +121,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests Dim projectAnalyzers2 = ImmutableArray.Create(Of DiagnosticAnalyzer)(projectDiagnosticAnalyzer2) Dim projectAnalyzerReference2 = New AnalyzerImageReference(projectAnalyzers2, display:=NameOf(projectAnalyzers2)) project = project.AddAnalyzerReference(projectAnalyzerReference2) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) ' Verify available diagnostic descriptors/analyzers descriptorsMap = hostAnalyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project) @@ -190,7 +192,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests Dim project = solution.Projects(0) Dim hostAnalyzers = solution.SolutionState.Analyzers - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() ' Add project analyzer reference with no analyzers. Dim projectAnalyzersEmpty = ImmutableArray(Of DiagnosticAnalyzer).Empty @@ -234,7 +236,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests Dim projectAnalyzerReference = New AnalyzerImageReference( ImmutableArray.Create(Of DiagnosticAnalyzer)(New TestDiagnosticAnalyzer1(1)), display:=referenceName) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() project = project.WithAnalyzerReferences(ImmutableArray.Create(Of AnalyzerReference)(projectAnalyzerReference)) @@ -270,7 +272,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests Dim project = solution.Projects(0) Dim hostAnalyzers = solution.SolutionState.Analyzers - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() ' Verify available diagnostic descriptors/analyzers Dim descriptorsMap = hostAnalyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project) @@ -282,7 +284,6 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests Dim document = project.Documents.Single() Dim span = (Await document.GetSyntaxRootAsync()).FullSpan - Dim analyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) Dim diagnostics = Await GetDiagnosticsForSpanAsync(diagnosticService, document, span) Assert.Equal(1, diagnostics.Length) Assert.Equal(workspaceDiagnosticAnalyzer.DiagDescriptor.Id, diagnostics(0).Id) @@ -334,14 +335,15 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests Dim p1 = solution.Projects.Single(Function(p) p.Language = LanguageNames.CSharp) p1 = p1.WithAnalyzerReferences(SpecializedCollections.SingletonCollection(New AnalyzerImageReference(ImmutableArray.Create(analyzer1)))) solution = p1.Solution + SerializerService.TestAccessor.AddAnalyzerImageReferences(p1.AnalyzerReferences) Dim p2 = solution.Projects.Single(Function(p) p.Language = LanguageNames.VisualBasic) p2 = p2.WithAnalyzerReferences(SpecializedCollections.SingletonCollection(New AnalyzerImageReference(ImmutableArray.Create(analyzer2)))) solution = p2.Solution + SerializerService.TestAccessor.AddAnalyzerImageReferences(p2.AnalyzerReferences) Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) - Dim analyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() Dim hostAnalyzers = solution.SolutionState.Analyzers Dim workspaceDescriptors = hostAnalyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache) @@ -382,7 +384,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests Dim analyzerReference = New TestAnalyzerReferenceByLanguage(analyzersMap) workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences({analyzerReference})) - Dim diagnosticService2 = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) + Dim diagnosticService2 = workspace.GetService(Of IDiagnosticAnalyzerService)() Dim descriptors = workspace.CurrentSolution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService2.AnalyzerInfoCache) Assert.Equal(1, descriptors.Count) @@ -430,8 +432,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests Dim analyzerReference2 = CreateAnalyzerFileReference(Assembly.GetExecutingAssembly().Location) project = project.AddAnalyzerReference(analyzerReference2) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) - Dim analyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() Dim descriptorsMap = workspace.CurrentSolution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project) ' Verify no duplicate diagnostics. @@ -482,9 +483,10 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests Dim analyzer = New ThrowsExceptionAnalyzer Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer)) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project) Assert.Equal(1, descriptorsMap.Count) @@ -493,7 +495,6 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests Dim document = project.Documents.Single() - Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) Dim diagnostics = Await GetDiagnosticsForDocumentAsync(diagnosticService, document) Assert.Empty(diagnostics) @@ -517,22 +518,22 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests Dim analyzer = New CodeBlockStartedAnalyzer(Of Microsoft.CodeAnalysis.CSharp.SyntaxKind) Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer)) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project) Assert.Equal(1, descriptorsMap.Count) Dim document = project.Documents.Single() - Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) Dim root = Await document.GetSyntaxRootAsync().ConfigureAwait(False) Dim diagnostics = Await GetDiagnosticsForSpanAsync(diagnosticService, document, root.FullSpan) Assert.Empty(diagnostics) diagnostics = Await diagnosticService.GetDiagnosticsForIdsAsync( - project.Solution, projectId:=Nothing, documentId:=Nothing, diagnosticIds:=Nothing, shouldIncludeAnalyzer:=Nothing, + project, documentId:=Nothing, diagnosticIds:=Nothing, shouldIncludeAnalyzer:=Nothing, includeLocalDocumentDiagnostics:=True, includeNonLocalDocumentDiagnostics:=True, CancellationToken.None) Dim diagnostic = diagnostics.First() Assert.True(diagnostic.Id = "AD0001") @@ -565,9 +566,8 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests project = project.AddAnalyzerReference(analyzerReference) Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() - Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) Dim span = (Await document.GetSyntaxRootAsync().ConfigureAwait(False)).FullSpan Dim diagnostics = Await GetDiagnosticsForSpanAsync(diagnosticService, document, span).ConfigureAwait(False) Assert.Equal(1, diagnostics.Length) @@ -588,8 +588,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests Using workspace = TestWorkspace.CreateWorkspace(test, composition:=s_compositionWithMockDiagnosticUpdateSourceRegistrationService) Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) - Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() For Each actionKind As OperationAnalyzer.ActionKind In [Enum].GetValues(GetType(OperationAnalyzer.ActionKind)) Dim solution = workspace.CurrentSolution @@ -597,13 +596,14 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests Dim analyzer = New OperationAnalyzer(actionKind) Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer)) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project) Assert.Equal(1, descriptorsMap.Count) Dim document = project.Documents.Single() Dim diagnostics = Await diagnosticService.GetDiagnosticsForIdsAsync( - project.Solution, project.Id, documentId:=Nothing, diagnosticIds:=Nothing, shouldIncludeAnalyzer:=Nothing, + project, documentId:=Nothing, diagnosticIds:=Nothing, shouldIncludeAnalyzer:=Nothing, includeLocalDocumentDiagnostics:=True, includeNonLocalDocumentDiagnostics:=True, CancellationToken.None) Assert.Equal(1, diagnostics.Length) Dim diagnostic = diagnostics.First() @@ -630,16 +630,16 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests Dim analyzer = New CodeBlockEndedAnalyzer() Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer)) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project) Assert.Equal(1, descriptorsMap.Count) Dim document = project.Documents.Single() - Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) Dim diagnostics = Await GetDiagnosticsForDocumentAsync(diagnosticService, document) Assert.Equal(1, diagnostics.Length) @@ -664,9 +664,10 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests Dim analyzer = New CodeBlockStartedAndEndedAnalyzer(Of Microsoft.CodeAnalysis.CSharp.SyntaxKind) Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer)) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() ' Ensure no duplicate diagnostics. Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project) @@ -674,7 +675,6 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests Dim document = project.Documents.Single() - Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) Dim diagnostics = Await GetDiagnosticsForDocumentAsync(diagnosticService, document) Assert.Equal(1, diagnostics.Length) Dim diagnostic = diagnostics.First() @@ -740,9 +740,10 @@ class AnonymousFunctions Dim analyzer = New CodeBlockStartedAndEndedAnalyzer(Of Microsoft.CodeAnalysis.CSharp.SyntaxKind) Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer)) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() ' Ensure no duplicate diagnostics. Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project) @@ -750,7 +751,6 @@ class AnonymousFunctions Dim document = project.Documents.Single() - Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) Dim diagnostics = Await GetDiagnosticsForDocumentAsync(diagnosticService, document) Assert.Equal(4, diagnostics.Length) @@ -776,10 +776,10 @@ class AnonymousFunctions Dim analyzer = New CompilationEndedAnalyzer Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer)) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) - Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project) Assert.Equal(1, descriptorsMap.Count) @@ -801,7 +801,7 @@ class AnonymousFunctions ' Test "GetDiagnosticsForIdsAsync" does force computation of compilation end diagnostics. ' Verify compilation diagnostics are reported with correct location info when asked for project diagnostics. Dim projectDiagnostics = Await diagnosticService.GetDiagnosticsForIdsAsync( - project.Solution, project.Id, documentId:=Nothing, + project, documentId:=Nothing, diagnosticIds:=Nothing, shouldIncludeAnalyzer:=Nothing, includeLocalDocumentDiagnostics:=True, includeNonLocalDocumentDiagnostics:=True, CancellationToken.None) Assert.Equal(2, projectDiagnostics.Length) @@ -837,6 +837,7 @@ class AnonymousFunctions Dim analyzer = New StatefulCompilationAnalyzer Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer)) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) Dim projectDiagnostics = Await DiagnosticProviderTestUtilities.GetProjectDiagnosticsAsync(workspace, project) Assert.Equal(1, projectDiagnostics.Count()) @@ -862,6 +863,7 @@ class AnonymousFunctions Dim analyzer = New StatefulCompilationAnalyzer Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer)) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) ' Make couple of dummy invocations to GetDocumentDiagnostics. Dim document = project.Documents.Single() @@ -901,6 +903,7 @@ class AnonymousFunctions Dim analyzer = New StatefulCompilationAnalyzer Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer)) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) Dim projectDiagnostics = Await DiagnosticProviderTestUtilities.GetProjectDiagnosticsAsync(workspace, project) @@ -936,17 +939,18 @@ class AnonymousFunctions Dim analyzer = New NamedTypeAnalyzer Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer)) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) + Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() - Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project) Assert.Equal(1, descriptorsMap.Count) ' Verify no duplicate analysis/diagnostics. Dim document = project.Documents.Single() Dim diagnostics = (Await diagnosticService.GetDiagnosticsForIdsAsync( - project.Solution, project.Id, documentId:=Nothing, diagnosticIds:=Nothing, shouldIncludeAnalyzer:=Nothing, + project, documentId:=Nothing, diagnosticIds:=Nothing, shouldIncludeAnalyzer:=Nothing, includeLocalDocumentDiagnostics:=True, includeNonLocalDocumentDiagnostics:=True, CancellationToken.None)). Select(Function(d) d.Id = NamedTypeAnalyzer.DiagDescriptor.Id) @@ -975,9 +979,10 @@ class AnonymousFunctions Dim analyzer = New PartialTypeDiagnosticAnalyzer(indexOfDeclToReportDiagnostic:=1) Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer)) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project) Assert.Equal(1, descriptorsMap.Count) @@ -985,7 +990,6 @@ class AnonymousFunctions Dim document = project.Documents.Single(Function(d) d.Name = "Test1.cs") Dim fullSpan = (Await document.GetSyntaxRootAsync()).FullSpan - Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) Dim diagnostics = Await GetDiagnosticsForSpanAsync(diagnosticService, document, fullSpan) Assert.Equal(1, diagnostics.Length) Assert.Equal(PartialTypeDiagnosticAnalyzer.DiagDescriptor.Id, diagnostics.Single().Id) @@ -1031,17 +1035,17 @@ class AnonymousFunctions ' Test partial type diagnostic reported on all source files. Dim analyzerReference = New AnalyzerImageReference(analyzers) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project) Assert.Equal(1, descriptorsMap.Count) ' Verify project diagnostics contains diagnostics reported on both partial definitions. - Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) Dim diagnostics = Await diagnosticService.GetDiagnosticsForIdsAsync( - project.Solution, project.Id, documentId:=Nothing, diagnosticIds:=Nothing, shouldIncludeAnalyzer:=Nothing, + project, documentId:=Nothing, diagnosticIds:=Nothing, shouldIncludeAnalyzer:=Nothing, includeLocalDocumentDiagnostics:=True, includeNonLocalDocumentDiagnostics:=True, CancellationToken.None) Assert.Equal(2, diagnostics.Length) Dim file1HasDiag = False, file2HasDiag = False @@ -1083,9 +1087,10 @@ public class B Dim analyzer As DiagnosticAnalyzer = New CodeBlockOrSyntaxNodeAnalyzer(isCodeBlockAnalyzer:=True) Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(analyzer)) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project) Assert.Equal(1, descriptorsMap.Count) @@ -1093,7 +1098,6 @@ public class B Dim document = project.Documents.Single() Dim fullSpan = (Await document.GetSyntaxRootAsync()).FullSpan - Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) Dim diagnostics = Await GetDiagnosticsForSpanAsync(diagnosticService, document, fullSpan) Assert.Equal(6, diagnostics.Length) Assert.Equal(3, diagnostics.Where(Function(d) d.Id = CodeBlockOrSyntaxNodeAnalyzer.Descriptor1.Id).Count) @@ -1126,9 +1130,10 @@ public class B Dim analyzer As DiagnosticAnalyzer = New CodeBlockOrSyntaxNodeAnalyzer(isCodeBlockAnalyzer:=False) Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(analyzer)) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project) Assert.Equal(1, descriptorsMap.Count) @@ -1136,7 +1141,6 @@ public class B Dim document = project.Documents.Single() Dim fullSpan = (Await document.GetSyntaxRootAsync()).FullSpan - Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) Dim diagnostics = Await GetDiagnosticsForSpanAsync(diagnosticService, document, fullSpan) Assert.Equal(3, diagnostics.Length) @@ -1169,9 +1173,10 @@ public class B Dim analyzer As DiagnosticAnalyzer = New MethodSymbolAnalyzer Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(analyzer)) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project) Assert.Equal(1, descriptorsMap.Count) @@ -1180,8 +1185,6 @@ public class B Dim text = Await document.GetTextAsync() Dim fullSpan = (Await document.GetSyntaxRootAsync()).FullSpan - Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) - Dim diagnostics = (Await GetDiagnosticsForSpanAsync(diagnosticService, document, fullSpan)). OrderBy(Function(d) d.DataLocation.UnmappedFileSpan.GetClampedTextSpan(text).Start).ToArray() @@ -1221,9 +1224,10 @@ End Class Dim analyzer = New MustOverrideMethodAnalyzer() Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer)) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project) Assert.Equal(1, descriptorsMap.Count) @@ -1231,7 +1235,6 @@ End Class Dim document = project.Documents.Single() Dim fullSpan = (Await document.GetSyntaxRootAsync()).FullSpan - Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) Dim diagnostics = Await GetDiagnosticsForSpanAsync(diagnosticService, document, fullSpan) Assert.Equal(1, diagnostics.Length) Assert.Equal(1, diagnostics.Where(Function(d) d.Id = MustOverrideMethodAnalyzer.Descriptor1.Id).Count) @@ -1284,9 +1287,10 @@ public class B Dim analyzer = New FieldDeclarationAnalyzer() Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer)) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project) Assert.Equal(1, descriptorsMap.Count) @@ -1294,7 +1298,6 @@ public class B Dim document = project.Documents.Single() Dim fullSpan = (Await document.GetSyntaxRootAsync()).FullSpan - Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) Dim text = Await document.GetTextAsync() Dim diagnostics = (Await GetDiagnosticsForSpanAsync(diagnosticService, document, fullSpan)). OrderBy(Function(d) d.DataLocation.UnmappedFileSpan.GetClampedTextSpan(text).Start). @@ -1331,9 +1334,10 @@ public class B Dim analyzer = New FieldDeclarationAnalyzer() Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer)) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project) Assert.Equal(1, descriptorsMap.Count) @@ -1341,7 +1345,6 @@ public class B Dim document = project.Documents.Single() Dim fullSpan = (Await document.GetSyntaxRootAsync()).FullSpan - Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) Dim text = Await document.GetTextAsync() Dim diagnostics = (Await GetDiagnosticsForSpanAsync(diagnosticService, document, fullSpan)). OrderBy(Function(d) d.DataLocation.UnmappedFileSpan.GetClampedTextSpan(text).Start). @@ -1397,6 +1400,7 @@ public class B Dim analyzer = New CompilationAnalyzerWithAnalyzerOptions() Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer)) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) ' Add additional document Dim additionalDocText = "First" @@ -1404,8 +1408,7 @@ public class B project = additionalDoc.Project Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) - Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() Await TestCompilationAnalyzerWithAnalyzerOptionsCoreAsync(project, additionalDocText, diagnosticService) @@ -1419,7 +1422,10 @@ public class B End Using End Function - Private Shared Async Function TestCompilationAnalyzerWithAnalyzerOptionsCoreAsync(project As Project, expectedDiagnosticMessage As String, diagnosticService As DiagnosticAnalyzerService) As Task + Private Shared Async Function TestCompilationAnalyzerWithAnalyzerOptionsCoreAsync( + project As Project, + expectedDiagnosticMessage As String, + diagnosticService As IDiagnosticAnalyzerService) As Task Dim descriptorsMap = project.Solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project) Assert.Equal(1, descriptorsMap.Count) @@ -1952,16 +1958,16 @@ End Class Dim analyzer = New CodeBlockActionAnalyzer(onlyStatelessAction) Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer)) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project) Assert.Equal(1, descriptorsMap.Count) Dim document = project.Documents.Single() - Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) Dim diagnostics = Await GetDiagnosticsForDocumentAsync(diagnosticService, document) Dim expectedCount = If(onlyStatelessAction, 1, 2) @@ -2012,16 +2018,16 @@ namespace ConsoleApplication1 ' Add analyzer Dim analyzerReference = New AnalyzerImageReference(analyzers.ToImmutableArray()) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project) Assert.Equal(1, descriptorsMap.Count) Dim document = project.Documents.Single() - Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) Dim diagnostics = Await GetDiagnosticsForDocumentAsync(diagnosticService, document) Assert.Equal(1, diagnostics.Length) @@ -2079,10 +2085,10 @@ class MyClass Dim analyzer = New AnalyzerWithNoSupportedDiagnostics() Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer)) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) - Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() ' Verify available diagnostic descriptors/analyzers Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project) @@ -2118,10 +2124,10 @@ class MyClass Dim analyzer = New CompilationAnalyzerWithSeverity(DiagnosticSeverity.Hidden, configurable:=False) Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer)) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) - Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() ' Verify available diagnostic descriptors Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project) @@ -2131,11 +2137,8 @@ class MyClass Assert.Equal(analyzer.Descriptor.Id, descriptors.Single().Id) ' Get cached project diagnostics. - Dim diagnostics = Await diagnosticService.GetCachedDiagnosticsAsync( - workspace, project.Id, documentId:=Nothing, - includeLocalDocumentDiagnostics:=True, - includeNonLocalDocumentDiagnostics:=True, - CancellationToken.None) + Dim diagnostics = Await diagnosticService.ForceAnalyzeProjectAsync( + project, CancellationToken.None) ' in v2, solution crawler never creates non-local hidden diagnostics. ' v2 still creates those for LB and explicit queries such as FixAll. @@ -2144,7 +2147,7 @@ class MyClass ' Get diagnostics explicitly Dim hiddenDiagnostics = Await diagnosticService.GetDiagnosticsForIdsAsync( - project.Solution, project.Id, documentId:=Nothing, diagnosticIds:=Nothing, shouldIncludeAnalyzer:=Nothing, + project, documentId:=Nothing, diagnosticIds:=Nothing, shouldIncludeAnalyzer:=Nothing, includeLocalDocumentDiagnostics:=True, includeNonLocalDocumentDiagnostics:=True, CancellationToken.None) Assert.Equal(1, hiddenDiagnostics.Length) Assert.Equal(analyzer.Descriptor.Id, hiddenDiagnostics.Single().Id) @@ -2175,6 +2178,7 @@ class C Dim analyzer = DiagnosticExtensions.GetCompilerDiagnosticAnalyzer(LanguageNames.CSharp) Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(analyzer)) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) ' Get span to analyze Dim document = project.Documents.Single() @@ -2183,8 +2187,7 @@ class C Dim span = localDecl.Span Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) - Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() ' Verify diagnostics for span Dim diagnostics = Await GetDiagnosticsForSpanAsync(diagnosticService, document, span) @@ -2222,16 +2225,16 @@ class C Dim analyzer = New EnsureNoMergedNamespaceSymbolAnalyzer() Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer)) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project) Assert.Equal(1, descriptorsMap.Count) - Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) Dim diagnostics = Await diagnosticService.GetDiagnosticsForIdsAsync( - project.Solution, project.Id, documentId:=Nothing, diagnosticIds:=Nothing, shouldIncludeAnalyzer:=Nothing, + project, documentId:=Nothing, diagnosticIds:=Nothing, shouldIncludeAnalyzer:=Nothing, includeLocalDocumentDiagnostics:=True, includeNonLocalDocumentDiagnostics:=True, CancellationToken.None) Assert.Empty(diagnostics) End Using @@ -2267,10 +2270,10 @@ class MyClass Dim compilerAnalyzer = New CSharpCompilerDiagnosticAnalyzer() Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(Of DiagnosticAnalyzer)(compilerAnalyzer, syntaxAnalyzer, semanticAnalyzer)) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) - Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() ' Get diagnostics for span for the given DiagnosticKind Dim document = project.Documents.Single() @@ -2337,10 +2340,10 @@ class MyClass Dim compilerAnalyzer = New CSharpCompilerDiagnosticAnalyzer() Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(Of DiagnosticAnalyzer)(compilerAnalyzer, syntaxAnalyzer, semanticAnalyzer)) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) - Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() ' Get diagnostics for span for fine grained DiagnosticKind in random order Dim document = project.Documents.Single() @@ -2427,9 +2430,10 @@ public class C Dim analyzer = New AllActionsAnalyzer() Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer)) project = project.AddAnalyzerReference(analyzerReference) + SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences) Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project) Assert.Equal(1, descriptorsMap.Count) @@ -2441,7 +2445,6 @@ public class C Assert.Equal("M1", firstMethodDecl.Identifier.ValueText) Dim span = firstMethodDecl.Span - Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace) Dim text = Await document.GetTextAsync() Dim diagnostics = Await GetDiagnosticsForSpanAsync(diagnosticService, document, span) Assert.Empty(diagnostics) diff --git a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.ConstructorSymbols.vb b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.ConstructorSymbols.vb index 21ea35471f180..c805f54928310 100644 --- a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.ConstructorSymbols.vb +++ b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.ConstructorSymbols.vb @@ -1379,6 +1379,29 @@ class C } + + Await TestAPIAndFeature(input, kind, host) + End Function + + + Public Async Function PartialConstructor(kind As TestKind, host As TestHost) As Task + Dim input = + + + +using System; +partial class Program +{ + public partial {|Definition:Program|}(); + public partial {|Definition:P$$rogram|}() { } + + static void Main(string[] args) + { + var p = new [|Program|](); + } +} + + Await TestAPIAndFeature(input, kind, host) End Function diff --git a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.EventSymbols.vb b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.EventSymbols.vb index a102c5854d806..ded1fcc943905 100644 --- a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.EventSymbols.vb +++ b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.EventSymbols.vb @@ -462,5 +462,29 @@ class C3_2 : I3 Await TestAPI(input, host) End Function + + + Public Async Function PartialEvent(kind As TestKind, host As TestHost) As Task + Dim input = + + + +using System; +partial class Program +{ + public static partial event Action {|Definition:Event|}; + public static partial event Action {|Definition:E$$vent|} { add { } remove { } } + + static void Main(string[] args) + { + Program.[|Event|] += null; + Program.[|Event|] -= null; + } +} + + + + Await TestAPIAndFeature(input, kind, host) + End Function End Class End Namespace diff --git a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.ExtensionMethodSymbols.vb b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.ExtensionMethodSymbols.vb index f6c4339682901..cdcd735dc53d8 100644 --- a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.ExtensionMethodSymbols.vb +++ b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.ExtensionMethodSymbols.vb @@ -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. -Imports System.Threading.Tasks Imports Microsoft.CodeAnalysis.Remote.Testing Namespace Microsoft.CodeAnalysis.Editor.UnitTests.FindReferences diff --git a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.ExtensionSymbols.vb b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.ExtensionSymbols.vb new file mode 100644 index 0000000000000..195ad461e2fec --- /dev/null +++ b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.ExtensionSymbols.vb @@ -0,0 +1,159 @@ +' Licensed to the .NET Foundation under one or more agreements. +' The .NET Foundation licenses this file to you under the MIT license. +' See the LICENSE file in the project root for more information. + +Imports Microsoft.CodeAnalysis.Remote.Testing + +Namespace Microsoft.CodeAnalysis.Editor.UnitTests.FindReferences + + Partial Public Class FindReferencesTests + + Public Async Function TestModernExtensionMethod1(kind As TestKind, host As TestHost) As Task + Dim input = + + + + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + Public Async Function TestModernExtensionMethod2(kind As TestKind, host As TestHost) As Task + Dim input = + + + + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + Public Async Function TestModernExtensionProperty1(kind As TestKind, host As TestHost) As Task + Dim input = + + + 0; + } +} +]]> + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + Public Async Function TestModernExtensionMethodParameter1(kind As TestKind, host As TestHost) As Task + Dim input = + + + + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + Public Async Function TestModernExtensionMethodTypeParameter1(kind As TestKind, host As TestHost) As Task + Dim input = + + + (string s) + { + public int ExtensionMethod([|T|] t) + { + return s.Length; + } + } +} +]]> + + + + Await TestAPIAndFeature(input, kind, host) + End Function + End Class +End Namespace diff --git a/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb b/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb index 68843dbf48673..676e9918d23c0 100644 --- a/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb +++ b/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb @@ -314,6 +314,69 @@ class Program Await TestAsync(workspace) End Function + + Public Async Function TestCSharpGotoDefinitionPartialEvent() As Task + Dim workspace = + + + + partial class Test + { + public partial event System.Action E; + } + + + partial class Test + { + void Goo() + { + var t = new Test(); + int i = t.E$$; + } + + public partial event System.Action [|E|] + { + add { } + remove { } + } + } + + + + + Await TestAsync(workspace) + End Function + + + Public Async Function TestCSharpGotoDefinitionPartialConstructor() As Task + Dim workspace = + + + + partial class Test + { + public partial Test(); + } + + + partial class Test + { + void Goo() + { + var t = new Te$$st(); + } + + public partial [|Test|]() + { + } + } + + + + + Await TestAsync(workspace) + End Function + Public Async Function TestCSharpGotoDefinitionOnMethodCall1() As Task Dim workspace = @@ -4072,8 +4135,6 @@ partial partial class Program Await TestAsync(workspace) End Function -#Disable Warning RSEXPERIMENTAL002 ' Type is for evaluation purposes only and is subject to change or removal in future updates. - Private Const s_interceptsLocationCode = " namespace System.Runtime.CompilerServices { @@ -4363,6 +4424,88 @@ public partial class Program Await TestAsync(workspace) End Function -#Enable Warning RSEXPERIMENTAL002 ' Type is for evaluation purposes only and is subject to change or removal in future updates. + + Public Async Function TestCSharpGoToExtensionMethod1() As Task + Dim workspace = + + + + static class Extensions + { + extension(string s) + { + public void [|Goo|]() { } + } + } + + class X + { + void M(string s) + { + s.$$Goo(); + } + } + + + + + Await TestAsync(workspace) + End Function + + + Public Async Function TestCSharpGoToExtensionMethod2() As Task + Dim workspace = + + + + static class Extensions + { + extension(string s) + { + public static void [|Goo|]() { } + } + } + + class X + { + void M(string s) + { + string.$$Goo(); + } + } + + + + + Await TestAsync(workspace) + End Function + + + Public Async Function TestCSharpGoToExtensionProperty() As Task + Dim workspace = + + + + static class Extensions + { + extension(string s) + { + public int [|Goo|] => 0; + } + } + + class X + { + void M(string s) + { + var v = s.$$Goo; + } + } + + + + + Await TestAsync(workspace) + End Function End Class End Namespace diff --git a/src/EditorFeatures/Test2/GoToDefinition/GoToDefinitionCommandHandlerTests.vb b/src/EditorFeatures/Test2/GoToDefinition/GoToDefinitionCommandHandlerTests.vb index bdd248e842de0..cdeca6bf967c3 100644 --- a/src/EditorFeatures/Test2/GoToDefinition/GoToDefinitionCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/GoToDefinition/GoToDefinitionCommandHandlerTests.vb @@ -56,9 +56,7 @@ class C Dim provider = workspace.GetService(Of IAsynchronousOperationListenerProvider)() Dim waiter = provider.GetWaiter(FeatureAttribute.GoToDefinition) Dim handler = New GoToDefinitionCommandHandler( - workspace.GetService(Of IGlobalOptionService), workspace.GetService(Of IThreadingContext), - workspace.GetService(Of IUIThreadOperationExecutor), provider) handler.ExecuteCommand(New GoToDefinitionCommandArgs(view, baseDocument.GetTextBuffer()), TestCommandExecutionContext.Create()) @@ -98,9 +96,7 @@ int y = x$$ Dim provider = workspace.GetService(Of IAsynchronousOperationListenerProvider)() Dim waiter = provider.GetWaiter(FeatureAttribute.GoToDefinition) Dim handler = New GoToDefinitionCommandHandler( - workspace.GetService(Of IGlobalOptionService), workspace.GetService(Of IThreadingContext), - workspace.GetService(Of IUIThreadOperationExecutor), provider) handler.ExecuteCommand(New GoToDefinitionCommandArgs(view, document.GetTextBuffer()), TestCommandExecutionContext.Create()) @@ -143,9 +139,7 @@ class C Dim provider = workspace.GetService(Of IAsynchronousOperationListenerProvider)() Dim waiter = provider.GetWaiter(FeatureAttribute.GoToDefinition) Dim handler = New GoToDefinitionCommandHandler( - workspace.GetService(Of IGlobalOptionService), workspace.GetService(Of IThreadingContext), - workspace.GetService(Of IUIThreadOperationExecutor), provider) Dim snapshot = document.GetTextBuffer().CurrentSnapshot diff --git a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb index 3c9256fba03e2..2b55a8fed7ea3 100644 --- a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb @@ -12,6 +12,7 @@ Imports Microsoft.CodeAnalysis.Completion.Providers Imports Microsoft.CodeAnalysis.CSharp Imports Microsoft.CodeAnalysis.CSharp.ExternalAccess.Pythia.Api Imports Microsoft.CodeAnalysis.CSharp.Formatting +Imports Microsoft.CodeAnalysis.CSharp.Shared.Extensions Imports Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.AsyncCompletion Imports Microsoft.CodeAnalysis.Editor.Shared.Options Imports Microsoft.CodeAnalysis.Editor.[Shared].Utilities @@ -12820,5 +12821,130 @@ internal class Program Await state.AssertCompletionItemsContain("C", displayTextSuffix:="") End Using End Function + + + + Public Async Function TestExtensionParameter1(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + + static class C + { + extension($$) + { + } + } + , + showCompletionInArgumentLists:=showCompletionInArgumentLists, languageVersion:=LanguageVersionExtensions.CSharpNext) + + state.SendInvokeCompletionList() + Await state.AssertCompletionItemsContain("string", displayTextSuffix:="") + End Using + End Function + + + + Public Async Function TestExtensionParameter2(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + + static class C + { + extension(Customer $$) + { + } + } + , + showCompletionInArgumentLists:=showCompletionInArgumentLists, languageVersion:=LanguageVersionExtensions.CSharpNext) + + state.SendInvokeCompletionList() + Await state.AssertCompletionItemsContain("customer", displayTextSuffix:="") + End Using + End Function + + + + Public Async Function TestSpeculativeTInExtension(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + + static class C + { + extension(Customer customer) + { + $$ + } + } + , + showCompletionInArgumentLists:=showCompletionInArgumentLists, languageVersion:=LanguageVersionExtensions.CSharpNext) + + state.SendInvokeCompletionList() + Await state.AssertCompletionItemsContain("T", displayTextSuffix:="") + End Using + End Function + + + + Public Async Function TestReturnSymbolInExtension1(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + + using System; + + static class C + { + extension(Customer customer) + { + $$ + } + } + , + showCompletionInArgumentLists:=showCompletionInArgumentLists, languageVersion:=LanguageVersionExtensions.CSharpNext) + + state.SendInvokeCompletionList() + Await state.AssertCompletionItemsContain("String", displayTextSuffix:="") + End Using + End Function + + + + Public Async Function TestReturnSymbolInExtension2(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + + using System; + + static class C + { + extension(Customer customer) + { + public $$ + } + } + , + showCompletionInArgumentLists:=showCompletionInArgumentLists, languageVersion:=LanguageVersionExtensions.CSharpNext) + + state.SendInvokeCompletionList() + Await state.AssertCompletionItemsContain("String", displayTextSuffix:="") + End Using + End Function + + + Public Async Function TestStaticExtensionMethod(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + + using System; + + object.$$ + + static class C + { + extension(object o) + { + public static void EM() { } + } + } + , + showCompletionInArgumentLists:=showCompletionInArgumentLists, languageVersion:=LanguageVersionExtensions.CSharpNext) + + state.SendInvokeCompletionList() + Await state.AssertCompletionItemsContain("EM", displayTextSuffix:="") + End Using + End Function End Class End Namespace diff --git a/src/EditorFeatures/Test2/IntelliSense/CompletionServiceTests.vb b/src/EditorFeatures/Test2/IntelliSense/CompletionServiceTests.vb index ab5edbe9480e7..f1b0f2327a4a7 100644 --- a/src/EditorFeatures/Test2/IntelliSense/CompletionServiceTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/CompletionServiceTests.vb @@ -4,6 +4,7 @@ Imports System.Collections.Immutable Imports System.Composition +Imports System.Threading Imports Microsoft.CodeAnalysis.Completion Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Host @@ -134,7 +135,7 @@ $$ Return Task.CompletedTask End Function - Public Overrides Function GetDescriptionAsync(document As Document, item As CompletionItem, cancellationToken As Threading.CancellationToken) As Task(Of CompletionDescription) + Public Overrides Function GetDescriptionAsync(document As Document, item As CompletionItem, cancellationToken As CancellationToken) As Task(Of CompletionDescription) Return Task.FromResult(CompletionDescription.FromText(DescriptionText)) End Function End Class diff --git a/src/EditorFeatures/Test2/IntelliSense/SignatureHelpControllerTests.vb b/src/EditorFeatures/Test2/IntelliSense/SignatureHelpControllerTests.vb index 2409e8479831e..66d9c617a1253 100644 --- a/src/EditorFeatures/Test2/IntelliSense/SignatureHelpControllerTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/SignatureHelpControllerTests.vb @@ -113,7 +113,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense Private Shared ReadOnly s_controllerMocksMap As New ConditionalWeakTable(Of Controller, ControllerMocks) Private Shared Function GetMocks(controller As Controller) As ControllerMocks Dim result As ControllerMocks = Nothing - Roslyn.Utilities.Contract.ThrowIfFalse(s_controllerMocksMap.TryGetValue(controller, result)) + Contract.ThrowIfFalse(s_controllerMocksMap.TryGetValue(controller, result)) Return result End Function diff --git a/src/EditorFeatures/Test2/NavigationBar/CSharpNavigationBarTests.vb b/src/EditorFeatures/Test2/NavigationBar/CSharpNavigationBarTests.vb index effd06d0c34e7..5bac824ee61aa 100644 --- a/src/EditorFeatures/Test2/NavigationBar/CSharpNavigationBarTests.vb +++ b/src/EditorFeatures/Test2/NavigationBar/CSharpNavigationBarTests.vb @@ -367,5 +367,28 @@ class C Item("C", Glyph.ClassInternal), False, Item("explicit operator checked string(C x)", Glyph.Operator), False) End Function + + + Public Async Function TestModernExtensionMethod1(host As TestHost) As Task + Await AssertSelectedItemsAreAsync( + + + +static class C +{ + extension(string s) + { + public void Goo()$$ + { + } + } +} + + + , + host, + Item("C.extension(string)", Glyph.ClassPublic), False, + Item("Goo()", Glyph.MethodPublic), False) + End Function End Class End Namespace diff --git a/src/EditorFeatures/TestUtilities/AbstractCommandHandlerTestState.cs b/src/EditorFeatures/TestUtilities/AbstractCommandHandlerTestState.cs index 3ac452b07a1a8..6b00f7ebc79e0 100644 --- a/src/EditorFeatures/TestUtilities/AbstractCommandHandlerTestState.cs +++ b/src/EditorFeatures/TestUtilities/AbstractCommandHandlerTestState.cs @@ -225,7 +225,7 @@ public CaretPosition GetCaretPoint() => TextView.Caret.Position; /// - /// Used in synchronous methods to ensure all outstanding work has been + /// Used in synchronous methods to ensure all outstanding work has been /// completed. /// public void AssertNoAsynchronousOperationsRunning() diff --git a/src/EditorFeatures/TestUtilities/ChangeSignature/TestChangeSignatureOptionsService.cs b/src/EditorFeatures/TestUtilities/ChangeSignature/TestChangeSignatureOptionsService.cs index 18d1b47e9c2d4..a90a4db89a0a5 100644 --- a/src/EditorFeatures/TestUtilities/ChangeSignature/TestChangeSignatureOptionsService.cs +++ b/src/EditorFeatures/TestUtilities/ChangeSignature/TestChangeSignatureOptionsService.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.ChangeSignature; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Test.Utilities.ChangeSignature; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.UnitTests.ChangeSignature; diff --git a/src/EditorFeatures/TestUtilities/Classification/FormattedClassification.cs b/src/EditorFeatures/TestUtilities/Classification/FormattedClassification.cs index e5fe84c3f9b88..d114b959a19b9 100644 --- a/src/EditorFeatures/TestUtilities/Classification/FormattedClassification.cs +++ b/src/EditorFeatures/TestUtilities/Classification/FormattedClassification.cs @@ -7,7 +7,6 @@ using System; using System.Collections.Immutable; using System.Linq; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.UnitTests.Classification { diff --git a/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs b/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs index 55e0869431cca..b4808de89e235 100644 --- a/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs +++ b/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs @@ -15,6 +15,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.AsyncCompletion; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -636,7 +637,7 @@ private async Task VerifyCustomCommitWorkerAsync( { using var workspaceFixture = GetOrCreateWorkspaceFixture(); - MarkupTestFile.GetPosition(expectedCodeAfterCommit, out var actualExpectedCode, out int expectedCaretPosition); + MarkupTestFile.GetPositionAndSpan(expectedCodeAfterCommit, out var actualExpectedCode, out var expectedCaretPosition, out TextSpan? expectedSelectionSpan); var options = GetCompletionOptions(); @@ -661,10 +662,15 @@ private async Task VerifyCustomCommitWorkerAsync( var textBuffer = workspaceFixture.Target.CurrentDocument.GetTextBuffer(); var actualCodeAfterCommit = textBuffer.CurrentSnapshot.AsText().ToString(); + var selectionSpan = commit.NewSelection ?? textView.Selection.StreamSelectionSpan.SnapshotSpan.Span.ToTextSpan(); var caretPosition = commit.NewPosition ?? textView.Caret.Position.BufferPosition.Position; AssertEx.EqualOrDiff(actualExpectedCode, actualCodeAfterCommit); - Assert.Equal(expectedCaretPosition, caretPosition); + + if (expectedSelectionSpan != null) + Assert.Equal(expectedSelectionSpan, selectionSpan); + else if (expectedCaretPosition != null) + Assert.Equal(expectedCaretPosition, caretPosition); } private void VerifyCustomCommitWorker( diff --git a/src/EditorFeatures/TestUtilities/Diagnostics/DiagnosticTaggerWrapper.cs b/src/EditorFeatures/TestUtilities/Diagnostics/DiagnosticTaggerWrapper.cs index f78dc19aca163..e8537f2d2b2a6 100644 --- a/src/EditorFeatures/TestUtilities/Diagnostics/DiagnosticTaggerWrapper.cs +++ b/src/EditorFeatures/TestUtilities/Diagnostics/DiagnosticTaggerWrapper.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.InlineDiagnostics; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.CodeAnalysis.Editor.Tagging; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.SolutionCrawler; using Microsoft.CodeAnalysis.Test.Utilities; diff --git a/src/EditorFeatures/TestUtilities/Diagnostics/MockDiagnosticAnalyzerService.cs b/src/EditorFeatures/TestUtilities/Diagnostics/MockDiagnosticAnalyzerService.cs deleted file mode 100644 index 7c4baeeb75e67..0000000000000 --- a/src/EditorFeatures/TestUtilities/Diagnostics/MockDiagnosticAnalyzerService.cs +++ /dev/null @@ -1,73 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Composition; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.Text; - -namespace Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics -{ - [Export(typeof(IDiagnosticAnalyzerService)), Shared, PartNotDiscoverable] - internal class MockDiagnosticAnalyzerService : IDiagnosticAnalyzerService - { - private readonly ArrayBuilder<(DiagnosticData Diagnostic, DiagnosticKind KindFilter)> _diagnosticsWithKindFilter; - public bool RequestedRefresh; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public MockDiagnosticAnalyzerService(IGlobalOptionService globalOptions) - { - GlobalOptions = globalOptions; - _diagnosticsWithKindFilter = ArrayBuilder<(DiagnosticData Diagnostic, DiagnosticKind KindFilter)>.GetInstance(); - } - - public void AddDiagnostic(DiagnosticData diagnostic, DiagnosticKind diagnosticKind) - => _diagnosticsWithKindFilter.Add((diagnostic, diagnosticKind)); - - public void AddDiagnostics(ImmutableArray diagnostics, DiagnosticKind diagnosticKind) - { - foreach (var diagnostic in diagnostics) - AddDiagnostic(diagnostic, diagnosticKind); - } - - public void RequestDiagnosticRefresh() - => RequestedRefresh = true; - - public DiagnosticAnalyzerInfoCache AnalyzerInfoCache - => throw new NotImplementedException(); - - public IGlobalOptionService GlobalOptions { get; } - - public bool ContainsDiagnostics(Workspace workspace, ProjectId projectId) - => throw new NotImplementedException(); - - public Task ForceAnalyzeProjectAsync(Project project, CancellationToken cancellationToken) - => throw new NotImplementedException(); - - public Task> GetCachedDiagnosticsAsync(Workspace workspace, ProjectId? projectId, DocumentId? documentId, bool includeLocalDocumentDiagnostics, bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken) - => throw new NotImplementedException(); - - public Task> GetDiagnosticsAsync(Solution solution, ProjectId? projectId, DocumentId? documentId, bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken) - => throw new NotImplementedException(); - - public Task> GetDiagnosticsForIdsAsync(Solution solution, ProjectId? projectId, DocumentId? documentId, ImmutableHashSet? diagnosticIds, Func? shouldIncludeAnalyzer, Func>? getDocuments, bool includeLocalDocumentDiagnostics, bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken) - => throw new NotImplementedException(); - - public Task> GetDiagnosticsForSpanAsync(TextDocument document, TextSpan? range, Func? shouldIncludeDiagnostic, bool includeCompilerDiagnostics, ICodeActionRequestPriorityProvider priorityProvider, DiagnosticKind diagnosticKind, bool isExplicit, CancellationToken cancellationToken) - => Task.FromResult(_diagnosticsWithKindFilter.Where(d => diagnosticKind == d.KindFilter).Select(d => d.Diagnostic).ToImmutableArray()); - - public Task> GetProjectDiagnosticsForIdsAsync(Solution solution, ProjectId? projectId, ImmutableHashSet? diagnosticIds, Func? shouldIncludeAnalyzer, bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken) - => throw new NotImplementedException(); - } -} diff --git a/src/EditorFeatures/TestUtilities/ExtractInterface/AbstractExtractInterfaceTests.cs b/src/EditorFeatures/TestUtilities/ExtractInterface/AbstractExtractInterfaceTests.cs index 6e8b6d2f410c5..c911544f93e60 100644 --- a/src/EditorFeatures/TestUtilities/ExtractInterface/AbstractExtractInterfaceTests.cs +++ b/src/EditorFeatures/TestUtilities/ExtractInterface/AbstractExtractInterfaceTests.cs @@ -26,7 +26,8 @@ public static async Task TestExtractInterfaceCommandCSharpAsync( string expectedNamespaceName = null, string expectedTypeParameterSuffix = null, string expectedUpdatedOriginalDocumentCode = null, - string expectedInterfaceCode = null) + string expectedInterfaceCode = null, + ParseOptions parseOptions = null) { await TestExtractInterfaceCommandAsync( markup, @@ -37,7 +38,8 @@ await TestExtractInterfaceCommandAsync( expectedNamespaceName, expectedTypeParameterSuffix, expectedUpdatedOriginalDocumentCode, - expectedInterfaceCode); + expectedInterfaceCode, + parseOptions: parseOptions); } public static async Task TestExtractInterfaceCodeActionCSharpAsync( @@ -94,9 +96,11 @@ private static async Task TestExtractInterfaceCommandAsync( string expectedTypeParameterSuffix = null, string expectedUpdatedOriginalDocumentCode = null, string expectedInterfaceCode = null, - CompilationOptions compilationOptions = null) + CompilationOptions compilationOptions = null, + ParseOptions parseOptions = null) { - using var testState = ExtractInterfaceTestState.Create(markup, languageName, compilationOptions, + using var testState = ExtractInterfaceTestState.Create( + markup, languageName, compilationOptions, parseOptions, options: new OptionsCollection(languageName) { { CodeStyleOptions2.AccessibilityModifiersRequired, AccessibilityModifiersRequired.Never, NotificationOption2.Silent } @@ -112,7 +116,7 @@ private static async Task TestExtractInterfaceCommandAsync( if (expectedMemberName != null) { - Assert.Equal(1, testState.TestExtractInterfaceOptionsService.AllExtractableMembers.Count()); + Assert.Equal(1, testState.TestExtractInterfaceOptionsService.AllExtractableMembers.Length); Assert.Equal(expectedMemberName, testState.TestExtractInterfaceOptionsService.AllExtractableMembers.Single().Name); } diff --git a/src/EditorFeatures/TestUtilities/ExtractInterface/ExtractInterfaceTestState.cs b/src/EditorFeatures/TestUtilities/ExtractInterface/ExtractInterfaceTestState.cs index 3c3d768448bb6..b60c8e0dae112 100644 --- a/src/EditorFeatures/TestUtilities/ExtractInterface/ExtractInterfaceTestState.cs +++ b/src/EditorFeatures/TestUtilities/ExtractInterface/ExtractInterfaceTestState.cs @@ -12,7 +12,6 @@ using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.ExtractInterface; using Microsoft.CodeAnalysis.Notification; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; diff --git a/src/EditorFeatures/TestUtilities/ExtractInterface/TestExtractInterfaceOptions.cs b/src/EditorFeatures/TestUtilities/ExtractInterface/TestExtractInterfaceOptions.cs index 846c12ca6ba8b..d3b047d196645 100644 --- a/src/EditorFeatures/TestUtilities/ExtractInterface/TestExtractInterfaceOptions.cs +++ b/src/EditorFeatures/TestUtilities/ExtractInterface/TestExtractInterfaceOptions.cs @@ -6,8 +6,8 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Composition; -using System.Threading; using Microsoft.CodeAnalysis.ExtractInterface; using Microsoft.CodeAnalysis.Host.Mef; @@ -18,9 +18,9 @@ namespace Microsoft.CodeAnalysis.Editor.UnitTests.ExtractInterface; [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] internal sealed class TestExtractInterfaceOptionsService() : IExtractInterfaceOptionsService { - public IEnumerable AllExtractableMembers { get; private set; } + public ImmutableArray AllExtractableMembers { get; private set; } public string DefaultInterfaceName { get; private set; } - public List ConflictingTypeNames { get; private set; } + public ImmutableArray ConflictingTypeNames { get; private set; } public string DefaultNamespace { get; private set; } public string GeneratedNameTypeParameterSuffix { get; set; } @@ -32,12 +32,11 @@ internal sealed class TestExtractInterfaceOptionsService() : IExtractInterfaceOp public ExtractInterfaceOptionsResult GetExtractInterfaceOptions( Document document, - List extractableMembers, + ImmutableArray extractableMembers, string defaultInterfaceName, - List conflictingTypeNames, + ImmutableArray conflictingTypeNames, string defaultNamespace, - string generatedNameTypeParameterSuffix, - CancellationToken cancellationToken) + string generatedNameTypeParameterSuffix) { this.AllExtractableMembers = extractableMembers; this.DefaultInterfaceName = defaultInterfaceName; diff --git a/src/EditorFeatures/TestUtilities/Microsoft.CodeAnalysis.EditorFeatures.Test.Utilities.csproj b/src/EditorFeatures/TestUtilities/Microsoft.CodeAnalysis.EditorFeatures.Test.Utilities.csproj index 540e000766193..0b19db7854e6a 100644 --- a/src/EditorFeatures/TestUtilities/Microsoft.CodeAnalysis.EditorFeatures.Test.Utilities.csproj +++ b/src/EditorFeatures/TestUtilities/Microsoft.CodeAnalysis.EditorFeatures.Test.Utilities.csproj @@ -10,10 +10,6 @@ false true - - - - diff --git a/src/EditorFeatures/TestUtilities/NavigateTo/AbstractNavigateToTests.cs b/src/EditorFeatures/TestUtilities/NavigateTo/AbstractNavigateToTests.cs index ce6b83a2906dc..26171ca394dbe 100644 --- a/src/EditorFeatures/TestUtilities/NavigateTo/AbstractNavigateToTests.cs +++ b/src/EditorFeatures/TestUtilities/NavigateTo/AbstractNavigateToTests.cs @@ -27,7 +27,6 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Language.NavigateTo.Interfaces; -using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.PatternMatching; using Microsoft.VisualStudio.Utilities; using Roslyn.Test.EditorUtilities.NavigateTo; diff --git a/src/EditorFeatures/TestUtilities/NavigateTo/NavigateToTestAggregator.Callback.cs b/src/EditorFeatures/TestUtilities/NavigateTo/NavigateToTestAggregator.Callback.cs index af0b25b4bef97..54e667b22a550 100644 --- a/src/EditorFeatures/TestUtilities/NavigateTo/NavigateToTestAggregator.Callback.cs +++ b/src/EditorFeatures/TestUtilities/NavigateTo/NavigateToTestAggregator.Callback.cs @@ -7,8 +7,8 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; +using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.Language.NavigateTo.Interfaces; -using Roslyn.Utilities; namespace Roslyn.Test.EditorUtilities.NavigateTo { diff --git a/src/EditorFeatures/TestUtilities/NavigateTo/NavigateToTestAggregator.cs b/src/EditorFeatures/TestUtilities/NavigateTo/NavigateToTestAggregator.cs index 3610e24b04132..9829cbe60bc3a 100644 --- a/src/EditorFeatures/TestUtilities/NavigateTo/NavigateToTestAggregator.cs +++ b/src/EditorFeatures/TestUtilities/NavigateTo/NavigateToTestAggregator.cs @@ -6,9 +6,9 @@ using System.Collections.Generic; using System.Threading.Tasks; +using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.Language.NavigateTo.Interfaces; using Moq; -using Roslyn.Utilities; namespace Roslyn.Test.EditorUtilities.NavigateTo { diff --git a/src/EditorFeatures/TestUtilities/SignatureHelp/AbstractSignatureHelpProviderTests.cs b/src/EditorFeatures/TestUtilities/SignatureHelp/AbstractSignatureHelpProviderTests.cs index 30083d8e8c448..760c486e4c9c0 100644 --- a/src/EditorFeatures/TestUtilities/SignatureHelp/AbstractSignatureHelpProviderTests.cs +++ b/src/EditorFeatures/TestUtilities/SignatureHelp/AbstractSignatureHelpProviderTests.cs @@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp.Presentation; using Microsoft.CodeAnalysis.LanguageService; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SignatureHelp; using Microsoft.CodeAnalysis.Test.Utilities; diff --git a/src/EditorFeatures/TestUtilities/Squiggles/SquiggleUtilities.cs b/src/EditorFeatures/TestUtilities/Squiggles/SquiggleUtilities.cs index b76d73bede467..1757d7874b973 100644 --- a/src/EditorFeatures/TestUtilities/Squiggles/SquiggleUtilities.cs +++ b/src/EditorFeatures/TestUtilities/Squiggles/SquiggleUtilities.cs @@ -4,7 +4,6 @@ #nullable disable -using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; diff --git a/src/EditorFeatures/TestUtilities/Squiggles/TestDiagnosticTagProducer.cs b/src/EditorFeatures/TestUtilities/Squiggles/TestDiagnosticTagProducer.cs index 67f6f4c7346da..557baa3b52d67 100644 --- a/src/EditorFeatures/TestUtilities/Squiggles/TestDiagnosticTagProducer.cs +++ b/src/EditorFeatures/TestUtilities/Squiggles/TestDiagnosticTagProducer.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text.Tagging; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.UnitTests.Squiggles; diff --git a/src/EditorFeatures/TestUtilities/Structure/AbstractSyntaxNodeStructureProviderTests.cs b/src/EditorFeatures/TestUtilities/Structure/AbstractSyntaxNodeStructureProviderTests.cs index 239e5692b2e79..473d944da5ffb 100644 --- a/src/EditorFeatures/TestUtilities/Structure/AbstractSyntaxNodeStructureProviderTests.cs +++ b/src/EditorFeatures/TestUtilities/Structure/AbstractSyntaxNodeStructureProviderTests.cs @@ -9,7 +9,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Structure; using Xunit; diff --git a/src/EditorFeatures/TestUtilities/Structure/AbstractSyntaxStructureProviderTests.cs b/src/EditorFeatures/TestUtilities/Structure/AbstractSyntaxStructureProviderTests.cs index 53d6264cb552a..d553cb6d826c8 100644 --- a/src/EditorFeatures/TestUtilities/Structure/AbstractSyntaxStructureProviderTests.cs +++ b/src/EditorFeatures/TestUtilities/Structure/AbstractSyntaxStructureProviderTests.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.Structure; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.Editor.UnitTests.Structure; diff --git a/src/EditorFeatures/TestUtilities/Structure/AbstractSyntaxTriviaStructureProviderTests.cs b/src/EditorFeatures/TestUtilities/Structure/AbstractSyntaxTriviaStructureProviderTests.cs index c678acd1b4253..b730b6036133c 100644 --- a/src/EditorFeatures/TestUtilities/Structure/AbstractSyntaxTriviaStructureProviderTests.cs +++ b/src/EditorFeatures/TestUtilities/Structure/AbstractSyntaxTriviaStructureProviderTests.cs @@ -8,7 +8,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Structure; namespace Microsoft.CodeAnalysis.Editor.UnitTests.Structure diff --git a/src/EditorFeatures/TestUtilities/Workspaces/EditorTestWorkspace.cs b/src/EditorFeatures/TestUtilities/Workspaces/EditorTestWorkspace.cs index 291cc01aced8b..a425a709ea646 100644 --- a/src/EditorFeatures/TestUtilities/Workspaces/EditorTestWorkspace.cs +++ b/src/EditorFeatures/TestUtilities/Workspaces/EditorTestWorkspace.cs @@ -6,8 +6,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System.Threading; -using System.Threading.Tasks; using System.Xml.Linq; using Microsoft.CodeAnalysis.CSharp.DecompiledSource; using Microsoft.CodeAnalysis.Diagnostics; @@ -17,7 +15,6 @@ using Microsoft.CodeAnalysis.Editor.UnitTests; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServer; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text.Shared.Extensions; using Microsoft.VisualStudio.Composition; @@ -31,12 +28,11 @@ namespace Microsoft.CodeAnalysis.Test.Utilities; -public partial class EditorTestWorkspace : TestWorkspace, ILspWorkspace +public partial class EditorTestWorkspace : TestWorkspace { private const string ReferencesOnDiskAttributeName = "ReferencesOnDisk"; private readonly Dictionary _createdTextBuffers = []; - private readonly bool _supportsLspMutation; internal EditorTestWorkspace( TestComposition? composition = null, @@ -44,8 +40,7 @@ internal EditorTestWorkspace( Guid solutionTelemetryId = default, bool disablePartialSolutions = true, bool ignoreUnchangeableDocumentsWhenApplyingChanges = true, - WorkspaceConfigurationOptions? configurationOptions = null, - bool supportsLspMutation = false) + WorkspaceConfigurationOptions? configurationOptions = null) : base(composition ?? EditorTestCompositions.EditorFeatures, workspaceKind, solutionTelemetryId, @@ -53,22 +48,6 @@ internal EditorTestWorkspace( ignoreUnchangeableDocumentsWhenApplyingChanges, configurationOptions) { - _supportsLspMutation = supportsLspMutation; - } - - bool ILspWorkspace.SupportsMutation => _supportsLspMutation; - - ValueTask ILspWorkspace.UpdateTextIfPresentAsync(DocumentId documentId, SourceText sourceText, CancellationToken cancellationToken) - { - Contract.ThrowIfFalse(_supportsLspMutation); - OnDocumentTextChanged(documentId, sourceText, PreservationMode.PreserveIdentity, requireDocumentPresent: false); - return ValueTaskFactory.CompletedTask; - } - - internal override ValueTask TryOnDocumentClosedAsync(DocumentId documentId, CancellationToken cancellationToken) - { - Contract.ThrowIfFalse(_supportsLspMutation); - return base.TryOnDocumentClosedAsync(documentId, cancellationToken); } private protected override EditorTestHostDocument CreateDocument( diff --git a/src/EditorFeatures/Text/Extensions.SnapshotSourceText.cs b/src/EditorFeatures/Text/Extensions.SnapshotSourceText.cs index 06c9a5c27f9e0..4dfb2f8e10b36 100644 --- a/src/EditorFeatures/Text/Extensions.SnapshotSourceText.cs +++ b/src/EditorFeatures/Text/Extensions.SnapshotSourceText.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.IO; using System.Linq; using System.Runtime.CompilerServices; diff --git a/src/EditorFeatures/Text/ITextImageHelpers.cs b/src/EditorFeatures/Text/ITextImageHelpers.cs index 5f3f60e2a3216..7770777f92a9d 100644 --- a/src/EditorFeatures/Text/ITextImageHelpers.cs +++ b/src/EditorFeatures/Text/ITextImageHelpers.cs @@ -4,8 +4,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.VisualStudio.Text; diff --git a/src/EditorFeatures/Text/Shared/Extensions/ITextSnapshotExtensions.cs b/src/EditorFeatures/Text/Shared/Extensions/ITextSnapshotExtensions.cs index 27f3a280aa6cd..e1ab19415e9d6 100644 --- a/src/EditorFeatures/Text/Shared/Extensions/ITextSnapshotExtensions.cs +++ b/src/EditorFeatures/Text/Shared/Extensions/ITextSnapshotExtensions.cs @@ -5,7 +5,6 @@ using System; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Tagging; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Text.Shared.Extensions { diff --git a/src/EditorFeatures/Text/Shared/Extensions/ITextSnapshotLineExtensions.cs b/src/EditorFeatures/Text/Shared/Extensions/ITextSnapshotLineExtensions.cs index 71421eb46de34..93dc129501c48 100644 --- a/src/EditorFeatures/Text/Shared/Extensions/ITextSnapshotLineExtensions.cs +++ b/src/EditorFeatures/Text/Shared/Extensions/ITextSnapshotLineExtensions.cs @@ -7,7 +7,6 @@ using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Editor.OptionsExtensionMethods; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Text.Shared.Extensions { diff --git a/src/EditorFeatures/VisualBasic/CodeCleanup/VisualBasicCodeCleanupService.vb b/src/EditorFeatures/VisualBasic/CodeCleanup/VisualBasicCodeCleanupService.vb index fee5d7f6359b2..c23580a6824f3 100644 --- a/src/EditorFeatures/VisualBasic/CodeCleanup/VisualBasicCodeCleanupService.vb +++ b/src/EditorFeatures/VisualBasic/CodeCleanup/VisualBasicCodeCleanupService.vb @@ -30,7 +30,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeCleanup New DiagnosticSet(FeaturesResources.Apply_parentheses_preferences, IDEDiagnosticIds.RemoveUnnecessaryParenthesesDiagnosticId, IDEDiagnosticIds.AddRequiredParenthesesDiagnosticId), New DiagnosticSet(AnalyzersResources.Add_accessibility_modifiers, - IDEDiagnosticIds.AddAccessibilityModifiersDiagnosticId), + IDEDiagnosticIds.AddOrRemoveAccessibilityModifiersDiagnosticId), New DiagnosticSet(FeaturesResources.Apply_coalesce_expression_preferences, IDEDiagnosticIds.UseCoalesceExpressionForTernaryConditionalCheckDiagnosticId), New DiagnosticSet(FeaturesResources.Apply_object_collection_initialization_preferences, diff --git a/src/EditorFeatures/VisualBasic/DocumentationComments/DocumentationCommentCommandHandler.vb b/src/EditorFeatures/VisualBasic/DocumentationComments/DocumentationCommentCommandHandler.vb index adf1516f82f55..0b05ceb21e86c 100644 --- a/src/EditorFeatures/VisualBasic/DocumentationComments/DocumentationCommentCommandHandler.vb +++ b/src/EditorFeatures/VisualBasic/DocumentationComments/DocumentationCommentCommandHandler.vb @@ -28,9 +28,10 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.DocumentationComments uiThreadOperationExecutor As IUIThreadOperationExecutor, undoHistoryRegistry As ITextUndoHistoryRegistry, editorOperationsFactoryService As IEditorOperationsFactoryService, - editorOptionsService As EditorOptionsService) + editorOptionsService As EditorOptionsService, + generateDocumentationCommentManager As CopilotGenerateDocumentationCommentManager) - MyBase.New(uiThreadOperationExecutor, undoHistoryRegistry, editorOperationsFactoryService, editorOptionsService) + MyBase.New(uiThreadOperationExecutor, undoHistoryRegistry, editorOperationsFactoryService, editorOptionsService, generateDocumentationCommentManager) End Sub Protected Overrides ReadOnly Property ExteriorTriviaText As String diff --git a/src/EditorFeatures/VisualBasic/EndConstructGeneration/ReplaceSpanResult.vb b/src/EditorFeatures/VisualBasic/EndConstructGeneration/ReplaceSpanResult.vb index 909b925f7be53..da7392e50945a 100644 --- a/src/EditorFeatures/VisualBasic/EndConstructGeneration/ReplaceSpanResult.vb +++ b/src/EditorFeatures/VisualBasic/EndConstructGeneration/ReplaceSpanResult.vb @@ -17,7 +17,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration Private ReadOnly _newCaretPosition As Integer? Public Sub New(snapshotSpan As SnapshotSpan, replacementText As String, newCaretPosition As Integer?) - ThrowIfNull(replacementText) + Contract.ThrowIfNull(replacementText) _snapshotSpan = snapshotSpan _replacementText = replacementText diff --git a/src/EditorFeatures/VisualBasic/Microsoft.CodeAnalysis.VisualBasic.EditorFeatures.vbproj b/src/EditorFeatures/VisualBasic/Microsoft.CodeAnalysis.VisualBasic.EditorFeatures.vbproj index 6f4fcb44d0880..e823fb16776ab 100644 --- a/src/EditorFeatures/VisualBasic/Microsoft.CodeAnalysis.VisualBasic.EditorFeatures.vbproj +++ b/src/EditorFeatures/VisualBasic/Microsoft.CodeAnalysis.VisualBasic.EditorFeatures.vbproj @@ -29,7 +29,7 @@ - + diff --git a/src/EditorFeatures/VisualBasicTest/ChangeSignature/ReorderParameters.InvocationLocations.vb b/src/EditorFeatures/VisualBasicTest/ChangeSignature/ReorderParameters.InvocationLocations.vb index 0b6e46604c2db..aab4aded50829 100644 --- a/src/EditorFeatures/VisualBasicTest/ChangeSignature/ReorderParameters.InvocationLocations.vb +++ b/src/EditorFeatures/VisualBasicTest/ChangeSignature/ReorderParameters.InvocationLocations.vb @@ -585,7 +585,7 @@ End Class]]>.NormalizedValue() #Region "Code Refactoring" - Public Async Function ReorderIndexerParameters_CodeRefactoring_InMethodDeclaration() As Threading.Tasks.Task + Public Async Function ReorderIndexerParameters_CodeRefactoring_InMethodDeclaration() As Task Dim markup = .NormalizedValue() End Function - Public Async Function ReorderIndexerParameters_CodeRefactoring_NotInMethodBody() As Threading.Tasks.Task + Public Async Function ReorderIndexerParameters_CodeRefactoring_NotInMethodBody() As Task Dim markup = .NormalizedValue() End Function - Public Async Function ReorderIndexerParameters_CodeRefactoring_InCallSite_ViaCodeAction() As Threading.Tasks.Task + Public Async Function ReorderIndexerParameters_CodeRefactoring_InCallSite_ViaCodeAction() As Task Dim markup = Return MyBase.GetHashCode()$$ End Function - Sub bar() + Sub bar() End Sub End Class @@ -1246,7 +1246,7 @@ Public Class Class2 Public Overrides Sub M( i As Integer) MyBase.M(i)$$ End Sub - ' Comment on body + ' Comment on body End Class]]> Await VerifyCustomCommitProviderAsync(markupBeforeCommit.Value.Replace(vbLf, vbCrLf), "M(i As Integer)", expectedCode.Value.Replace(vbLf, vbCrLf)) diff --git a/src/EditorFeatures/VisualBasicTest/Diagnostics/AbstractVisualBasicDiagnosticProviderBasedUserDiagnosticTest.vb b/src/EditorFeatures/VisualBasicTest/Diagnostics/AbstractVisualBasicDiagnosticProviderBasedUserDiagnosticTest.vb index b87ec47eb3680..b3af39f3ff3d3 100644 --- a/src/EditorFeatures/VisualBasicTest/Diagnostics/AbstractVisualBasicDiagnosticProviderBasedUserDiagnosticTest.vb +++ b/src/EditorFeatures/VisualBasicTest/Diagnostics/AbstractVisualBasicDiagnosticProviderBasedUserDiagnosticTest.vb @@ -28,7 +28,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics End Function Friend Overloads Async Function TestAsync( - initialMarkup As XElement, expected As XElement, Optional index As Integer = 0) As Threading.Tasks.Task + initialMarkup As XElement, expected As XElement, Optional index As Integer = 0) As Task Dim initialMarkupStr = initialMarkup.ConvertTestSourceTag() Dim expectedStr = expected.ConvertTestSourceTag() @@ -37,7 +37,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics index:=index) End Function - Protected Overloads Async Function TestMissingAsync(initialMarkup As XElement) As Threading.Tasks.Task + Protected Overloads Async Function TestMissingAsync(initialMarkup As XElement) As Task Dim initialMarkupStr = initialMarkup.ConvertTestSourceTag() Await MyBase.TestMissingAsync(initialMarkupStr, New TestParameters(parseOptions:=Nothing, compilationOptions:=_compilationOptions)) diff --git a/src/EditorFeatures/VisualBasicTest/ExtractMethod/ExtractMethodTests.ControlFlowAnalysis.vb b/src/EditorFeatures/VisualBasicTest/ExtractMethod/ExtractMethodTests.ControlFlowAnalysis.vb index dcc551f6e8f9e..240afe523411c 100644 --- a/src/EditorFeatures/VisualBasicTest/ExtractMethod/ExtractMethodTests.ControlFlowAnalysis.vb +++ b/src/EditorFeatures/VisualBasicTest/ExtractMethod/ExtractMethodTests.ControlFlowAnalysis.vb @@ -15,7 +15,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.ExtractMethod Public Class FlowAnalysis - Public Async Function TestExitSub() As Threading.Tasks.Task + Public Async Function TestExitSub() As Task Dim code = Class Test Sub Test() [|Exit Sub|] @@ -26,7 +26,7 @@ End Class End Function - Public Async Function TestExitFunction() As Threading.Tasks.Task + Public Async Function TestExitFunction() As Task Dim code = Class Test Function Test1() As Integer Console.Write(42) @@ -271,7 +271,7 @@ End Class End Function - Public Async Function BugFix6313_2() As Threading.Tasks.Task + Public Async Function BugFix6313_2() As Task Dim code = Imports System Class A diff --git a/src/EditorFeatures/VisualBasicTest/ExtractMethod/ExtractMethodTests.TriviaProcessor.vb b/src/EditorFeatures/VisualBasicTest/ExtractMethod/ExtractMethodTests.TriviaProcessor.vb index dd7e134ac7838..14a593768af58 100644 --- a/src/EditorFeatures/VisualBasicTest/ExtractMethod/ExtractMethodTests.TriviaProcessor.vb +++ b/src/EditorFeatures/VisualBasicTest/ExtractMethod/ExtractMethodTests.TriviaProcessor.vb @@ -9,7 +9,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.ExtractMethod Public Class TriviaProcessor - Public Async Function TestCommentBeforeCode() As Threading.Tasks.Task + Public Async Function TestCommentBeforeCode() As Task Dim code = Class C Sub M() [|'comment @@ -32,7 +32,7 @@ End Class End Function - Public Async Function LineContinuation() As Threading.Tasks.Task + Public Async Function LineContinuation() As Task Dim code = Module Program Sub Main Dim x = [|1. _ @@ -55,7 +55,7 @@ End Module End Function - Public Async Function LineContinuation2() As Threading.Tasks.Task + Public Async Function LineContinuation2() As Task Dim code = Imports System Imports System.Collections.Generic Imports System.Linq @@ -98,7 +98,7 @@ End Module End Function - Public Async Function ImplicitLineContinuation() As Threading.Tasks.Task + Public Async Function ImplicitLineContinuation() As Task Dim code = Imports System.Linq Module A Sub Main() @@ -123,7 +123,7 @@ End Module End Function - Public Async Function ImplicitLineContinuation2() As Threading.Tasks.Task + Public Async Function ImplicitLineContinuation2() As Task Dim code = Imports System.Linq Module A Sub Main() diff --git a/src/EditorFeatures/VisualBasicTest/Formatting/CodeCleanUpTests.vb b/src/EditorFeatures/VisualBasicTest/Formatting/CodeCleanUpTests.vb index e2eff36a2a1c4..123c74f17b5b5 100644 --- a/src/EditorFeatures/VisualBasicTest/Formatting/CodeCleanUpTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Formatting/CodeCleanUpTests.vb @@ -215,7 +215,7 @@ End Class End Function - Public Function VisualBasicAddAccessibilityModifiers() As Task + Public Function VisualBasicAddOrRemoveAccessibilityModifiers() As Task Dim code As String = "Class Program Public Shared Sub Method() Console.WriteLine(""Hello"") diff --git a/src/EditorFeatures/VisualBasicTest/Formatting/FormattingEngineTests_Venus.vb b/src/EditorFeatures/VisualBasicTest/Formatting/FormattingEngineTests_Venus.vb index 0aef18c39f966..a8a0221d97a60 100644 --- a/src/EditorFeatures/VisualBasicTest/Formatting/FormattingEngineTests_Venus.vb +++ b/src/EditorFeatures/VisualBasicTest/Formatting/FormattingEngineTests_Venus.vb @@ -14,7 +14,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Formatting End Sub - Public Async Function SimpleOneLineNugget() As Threading.Tasks.Task + Public Async Function SimpleOneLineNugget() As Task Dim code = Imports System Imports System.Collections.Generic Imports System.Linq @@ -44,7 +44,7 @@ End Module - Public Async Function SimpleScriptBlock() As Threading.Tasks.Task + Public Async Function SimpleScriptBlock() As Task Dim code = Imports System Imports System.Collections.Generic Imports System.Linq @@ -75,7 +75,7 @@ End Module End Function - Public Async Function SimpleMultiLineNugget() As Threading.Tasks.Task + Public Async Function SimpleMultiLineNugget() As Task Dim code = Imports System Imports System.Collections.Generic Imports System.Linq @@ -113,7 +113,7 @@ End Module - Public Async Function SimpleQueryWithinNugget() As Threading.Tasks.Task + Public Async Function SimpleQueryWithinNugget() As Task Dim code = Imports System Imports System.Collections.Generic Imports System.Linq @@ -151,7 +151,7 @@ End Module End Function - Public Async Function SingleLineFunctionLambdaInNugget() As Threading.Tasks.Task + Public Async Function SingleLineFunctionLambdaInNugget() As Task Dim code = Imports System Imports System.Collections.Generic Imports System.Linq @@ -186,7 +186,7 @@ End Module End Function - Public Async Function MultiLineFunctionLambdaInNugget() As Threading.Tasks.Task + Public Async Function MultiLineFunctionLambdaInNugget() As Task Dim code = Imports System Imports System.Collections.Generic Imports System.Linq @@ -246,7 +246,7 @@ End Module ''' The rule has to be set up for each set of spans, currently we test just one Private Shared Async Function AssertFormatWithBaseIndentAfterReplacingLfToCrLfAsync(content As String, expected As String, - baseIndentation As Integer) As Threading.Tasks.Task + baseIndentation As Integer) As Task ' do this since xml value put only vbLf content = content.Replace(vbLf, vbCrLf) diff --git a/src/EditorFeatures/VisualBasicTest/Formatting/Indentation/SmartTokenFormatter_FormatTokenTests.vb b/src/EditorFeatures/VisualBasicTest/Formatting/Indentation/SmartTokenFormatter_FormatTokenTests.vb index 6aa0312032bef..e57a62172f560 100644 --- a/src/EditorFeatures/VisualBasicTest/Formatting/Indentation/SmartTokenFormatter_FormatTokenTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Formatting/Indentation/SmartTokenFormatter_FormatTokenTests.vb @@ -174,7 +174,7 @@ End Class Assert.NotNull(Await Record.ExceptionAsync(Function() TestAsync(codeWithMarkup, indentation, indentStyle:=indentStyle))) End Function - Private Shared Async Function TestAsync(codeWithMarkup As String, indentation As Integer, Optional indentStyle As FormattingOptions2.IndentStyle = FormattingOptions2.IndentStyle.Smart) As Threading.Tasks.Task + Private Shared Async Function TestAsync(codeWithMarkup As String, indentation As Integer, Optional indentStyle As FormattingOptions2.IndentStyle = FormattingOptions2.IndentStyle.Smart) As Task Dim code As String = Nothing Dim position As Integer = 0 MarkupTestFile.GetPosition(codeWithMarkup, code, position) diff --git a/src/EditorFeatures/VisualBasicTest/SignatureHelp/AbstractVisualBasicSignatureHelpProviderTests.vb b/src/EditorFeatures/VisualBasicTest/SignatureHelp/AbstractVisualBasicSignatureHelpProviderTests.vb index 81f35e47e6fed..28bd205b74a1e 100644 --- a/src/EditorFeatures/VisualBasicTest/SignatureHelp/AbstractVisualBasicSignatureHelpProviderTests.vb +++ b/src/EditorFeatures/VisualBasicTest/SignatureHelp/AbstractVisualBasicSignatureHelpProviderTests.vb @@ -11,7 +11,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.SignatureHelp ' We want to skip script testing in all VB stuff for now. - Protected Overrides Function TestAsync(markupWithPositionAndOptSpan As String, Optional expectedOrderedItemsOrNull As IEnumerable(Of SignatureHelpTestItem) = Nothing, Optional usePreviousCharAsTrigger As Boolean = False, Optional sourceCodeKind As Microsoft.CodeAnalysis.SourceCodeKind? = Nothing, Optional experimental As Boolean = False) As Threading.Tasks.Task + Protected Overrides Function TestAsync(markupWithPositionAndOptSpan As String, Optional expectedOrderedItemsOrNull As IEnumerable(Of SignatureHelpTestItem) = Nothing, Optional usePreviousCharAsTrigger As Boolean = False, Optional sourceCodeKind As Microsoft.CodeAnalysis.SourceCodeKind? = Nothing, Optional experimental As Boolean = False) As Task If (sourceCodeKind.HasValue) Then Return MyBase.TestAsync(markupWithPositionAndOptSpan, expectedOrderedItemsOrNull, usePreviousCharAsTrigger, sourceCodeKind, experimental) Else @@ -19,7 +19,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.SignatureHelp End If End Function - Protected Overrides Function VerifyCurrentParameterNameAsync(markupWithPosition As String, expectedParameterName As String, Optional sourceCodeKind As Microsoft.CodeAnalysis.SourceCodeKind? = Nothing) As Threading.Tasks.Task + Protected Overrides Function VerifyCurrentParameterNameAsync(markupWithPosition As String, expectedParameterName As String, Optional sourceCodeKind As Microsoft.CodeAnalysis.SourceCodeKind? = Nothing) As Task If (sourceCodeKind.HasValue) Then Return MyBase.VerifyCurrentParameterNameAsync(markupWithPosition, expectedParameterName, sourceCodeKind) Else diff --git a/src/EditorFeatures/VisualBasicTest/Structure/CommentStructureTests.vb b/src/EditorFeatures/VisualBasicTest/Structure/CommentStructureTests.vb index 65dcd079c2464..07000d1247ea7 100644 --- a/src/EditorFeatures/VisualBasicTest/Structure/CommentStructureTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Structure/CommentStructureTests.vb @@ -29,7 +29,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Outlining ElseIf token.TrailingTrivia.Contains(trivia) Then Return CreateCommentsRegions(token.TrailingTrivia) Else - Throw Roslyn.Utilities.ExceptionUtilities.Unreachable + Throw ExceptionUtilities.Unreachable End If End Function diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs index 11229c7f76d1f..04af7e975cd94 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs @@ -837,7 +837,7 @@ private static Binder CreateBinderChain( { // We're re-getting the namespace, rather than using the one containing // the current frame method, because we want the merged namespace. - @namespace = @namespace.GetNestedNamespace(namespaceName); + @namespace = @namespace.GetNestedNamespace(namespaceName)!; RoslynDebug.AssertNotNull(@namespace); } else diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EENamedTypeSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EENamedTypeSymbol.cs index c0ae503882254..23643883a6bba 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EENamedTypeSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EENamedTypeSymbol.cs @@ -323,6 +323,9 @@ public sealed override bool IsRefLikeType get { return false; } } + internal override string ExtensionName + => throw ExceptionUtilities.Unreachable(); + public sealed override bool IsReadOnly { get { return false; } @@ -356,6 +359,8 @@ internal override bool IsInterface internal override bool HasPossibleWellKnownCloneMethod() => false; internal override bool IsInterpolatedStringHandlerType => false; + internal sealed override ParameterSymbol ExtensionParameter => null; + [Conditional("DEBUG")] internal static void VerifyTypeParameters(Symbol container, ImmutableArray typeParameters) { diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/SynthesizedContextMethodSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/SynthesizedContextMethodSymbol.cs index 14cfe904b623a..47f0ed0f0b488 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/SynthesizedContextMethodSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/SynthesizedContextMethodSymbol.cs @@ -18,7 +18,7 @@ namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator /// expressions outside of a method - specifically, binding /// DebuggerDisplayAttribute expressions. /// - internal sealed class SynthesizedContextMethodSymbol : SynthesizedInstanceMethodSymbol + internal sealed class SynthesizedContextMethodSymbol : SynthesizedMethodSymbol { private readonly NamedTypeSymbol _container; diff --git a/src/ExpressionEvaluator/Core/Source/FunctionResolver/Microsoft.CodeAnalysis.FunctionResolver.csproj b/src/ExpressionEvaluator/Core/Source/FunctionResolver/Microsoft.CodeAnalysis.FunctionResolver.csproj index 3271d4fbd6d4d..5744d70120de4 100644 --- a/src/ExpressionEvaluator/Core/Source/FunctionResolver/Microsoft.CodeAnalysis.FunctionResolver.csproj +++ b/src/ExpressionEvaluator/Core/Source/FunctionResolver/Microsoft.CodeAnalysis.FunctionResolver.csproj @@ -10,9 +10,6 @@ true - - Compiler\ExceptionUtilities.cs - Compiler\MetadataTypeCodeExtensions.cs @@ -25,9 +22,6 @@ Compiler\CommonGeneratedNames.cs - - Compiler\NullableAttributes.cs - Compiler\RoslynString.cs @@ -64,5 +58,6 @@ + diff --git a/src/ExpressionEvaluator/Core/Source/ResultProvider/Portable/Microsoft.CodeAnalysis.ResultProvider.csproj b/src/ExpressionEvaluator/Core/Source/ResultProvider/Portable/Microsoft.CodeAnalysis.ResultProvider.csproj index 4c83167c2a17a..c28f388bd2ddc 100644 --- a/src/ExpressionEvaluator/Core/Source/ResultProvider/Portable/Microsoft.CodeAnalysis.ResultProvider.csproj +++ b/src/ExpressionEvaluator/Core/Source/ResultProvider/Portable/Microsoft.CodeAnalysis.ResultProvider.csproj @@ -28,21 +28,9 @@ Compiler\InternalUtilities\EnumField.cs - - Compiler\InternalUtilities\ExceptionUtilities.cs - - - Compiler\InternalUtilities\NullableAttributes.cs - Compiler\InternalUtilities\ReflectionUtilities.cs - - Compilers\InternalUtilities\InterpolatedStringHandlerAttribute.cs - - - Compilers\InternalUtilities\InterpolatedStringHandlerArgumentAttribute.cs - Compiler\InternalUtilities\ObjectPool`1.cs @@ -90,4 +78,5 @@ + \ No newline at end of file diff --git a/src/ExpressionEvaluator/Core/Test/ExpressionCompiler/NamespaceTypeDefinitionNoBase.cs b/src/ExpressionEvaluator/Core/Test/ExpressionCompiler/NamespaceTypeDefinitionNoBase.cs index bd857b6fc3ffb..9adcc73fa102b 100644 --- a/src/ExpressionEvaluator/Core/Test/ExpressionCompiler/NamespaceTypeDefinitionNoBase.cs +++ b/src/ExpressionEvaluator/Core/Test/ExpressionCompiler/NamespaceTypeDefinitionNoBase.cs @@ -132,13 +132,13 @@ internal NamespaceTypeDefinitionNoBase(INamespaceTypeDefinition underlyingType) public sealed override bool Equals(object obj) { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } public sealed override int GetHashCode() { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. - throw Roslyn.Utilities.ExceptionUtilities.Unreachable(); + throw ExceptionUtilities.Unreachable(); } } } diff --git a/src/ExpressionEvaluator/Core/Test/ResultProvider/Microsoft.CodeAnalysis.ResultProvider.Utilities.csproj b/src/ExpressionEvaluator/Core/Test/ResultProvider/Microsoft.CodeAnalysis.ResultProvider.Utilities.csproj index 7def48e1d75a6..a62c0965c6d4a 100644 --- a/src/ExpressionEvaluator/Core/Test/ResultProvider/Microsoft.CodeAnalysis.ResultProvider.Utilities.csproj +++ b/src/ExpressionEvaluator/Core/Test/ResultProvider/Microsoft.CodeAnalysis.ResultProvider.Utilities.csproj @@ -40,21 +40,9 @@ Compiler\InternalUtilities\EnumField.cs - - Compiler\InternalUtilities\ExceptionUtilities.cs - - - Compiler\InternalUtilities\NullableAttributes.cs - Compiler\InternalUtilities\ReflectionUtilities.cs - - Compilers\InternalUtilities\InterpolatedStringHandlerAttribute.cs - - - Compilers\InternalUtilities\InterpolatedStringHandlerArgumentAttribute.cs - Compiler\InternalUtilities\ObjectPool`1.cs @@ -94,4 +82,5 @@ + diff --git a/src/Features/CSharp/Portable/AddImport/CSharpAddImportFeatureService.cs b/src/Features/CSharp/Portable/AddImport/CSharpAddImportFeatureService.cs index e779f7003170d..7a7db60392937 100644 --- a/src/Features/CSharp/Portable/AddImport/CSharpAddImportFeatureService.cs +++ b/src/Features/CSharp/Portable/AddImport/CSharpAddImportFeatureService.cs @@ -6,7 +6,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Composition; using System.Linq; using System.Threading; diff --git a/src/Features/CSharp/Portable/CSharpFeaturesResources.resx b/src/Features/CSharp/Portable/CSharpFeaturesResources.resx index 8171ec91bb9d0..5c501128a87f7 100644 --- a/src/Features/CSharp/Portable/CSharpFeaturesResources.resx +++ b/src/Features/CSharp/Portable/CSharpFeaturesResources.resx @@ -581,4 +581,10 @@ required property + + Convert '{0}' extension methods to extension + + + Convert all extension methods in '{0}' to extension + \ No newline at end of file diff --git a/src/Features/CSharp/Portable/CodeRefactorings/EnableNullable/EnableNullableCodeRefactoringProvider.FixAllProvider.cs b/src/Features/CSharp/Portable/CodeRefactorings/EnableNullable/EnableNullableCodeRefactoringProvider.FixAllProvider.cs index 238b2127dab7c..284bc6945b647 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/EnableNullable/EnableNullableCodeRefactoringProvider.FixAllProvider.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/EnableNullable/EnableNullableCodeRefactoringProvider.FixAllProvider.cs @@ -61,14 +61,11 @@ private sealed class FixAllCodeAction(Func, CancellationToken, Task> _createChangedSolution = createChangedSolution; - protected override async Task> ComputePreviewOperationsAsync(CancellationToken cancellationToken) + protected override async Task> ComputeOperationsAsync(IProgress progress, CancellationToken cancellationToken) { var changedSolution = await _createChangedSolution( - CodeActionPurpose.Preview, CodeAnalysisProgress.None, cancellationToken).ConfigureAwait(false); - if (changedSolution is null) - return []; - - return new CodeActionOperation[] { new ApplyChangesOperation(changedSolution) }; + CodeActionPurpose.Preview, progress, cancellationToken).ConfigureAwait(false); + return changedSolution is null ? [] : [new ApplyChangesOperation(changedSolution)]; } } } diff --git a/src/Features/CSharp/Portable/CodeRefactorings/MoveType/CSharpMoveTypeService.cs b/src/Features/CSharp/Portable/CodeRefactorings/MoveType/CSharpMoveTypeService.cs index d59700a5386cd..429d77ba862fe 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/MoveType/CSharpMoveTypeService.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/MoveType/CSharpMoveTypeService.cs @@ -20,6 +20,9 @@ namespace Microsoft.CodeAnalysis.CSharp.CodeRefactorings.MoveType; internal sealed class CSharpMoveTypeService() : AbstractMoveTypeService { + protected override (string name, int arity) GetSymbolNameAndArity(BaseTypeDeclarationSyntax syntax) + => (syntax.Identifier.ValueText, syntax is TypeDeclarationSyntax { TypeParameterList.Parameters.Count: var arity } ? arity : 0); + protected override bool IsMemberDeclaration(SyntaxNode syntaxNode) => syntaxNode is MemberDeclarationSyntax; diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/CompletionUtilities.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/CompletionUtilities.cs index 2e61efc068f70..b17b102ed3365 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/CompletionUtilities.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/CompletionUtilities.cs @@ -9,11 +9,9 @@ using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers; @@ -188,30 +186,53 @@ public static SyntaxNode GetTargetCaretPositionForMethod(BaseMethodDeclarationSy } } - public static SyntaxNode GetTargetCaretNodeForInsertedMember(SyntaxNode caretTarget) + public static TextSpan GetTargetSelectionSpanForMethod(BaseMethodDeclarationSyntax methodDeclaration) + { + if (methodDeclaration.ExpressionBody is not null) + { + // select the expression span + return methodDeclaration.ExpressionBody.Expression.Span; + } + else if (methodDeclaration.Body is not null) + { + // select the last statement in the method + return methodDeclaration.Body.Statements.Last().Span; + } + else + { + return methodDeclaration.Span; + } + } + + public static TextSpan GetTargetSelectionSpanForInsertedMember(SyntaxNode caretTarget) { switch (caretTarget) { case EventFieldDeclarationSyntax: - // Inserted Event declarations are a single line, so move to the end of the line. - return caretTarget; + // Inserted Event declarations are a single line, so move caret to the end of the line. + return new TextSpan(caretTarget.Span.End, 0); case BaseMethodDeclarationSyntax methodDeclaration: - return GetTargetCaretPositionForMethod(methodDeclaration); + return GetTargetSelectionSpanForMethod(methodDeclaration); case BasePropertyDeclarationSyntax propertyDeclaration: { - // property: no accessors; move to the end of the declaration if (propertyDeclaration.AccessorList is { Accessors: [var firstAccessor, ..] }) { - // move to the end of the last statement of the first accessor + // select the last statement of the first accessor var firstAccessorStatement = (SyntaxNode)firstAccessor.Body?.Statements.LastOrDefault() ?? firstAccessor.ExpressionBody!.Expression; - return firstAccessorStatement; + return firstAccessorStatement.Span; + } + else if (propertyDeclaration is PropertyDeclarationSyntax propertyDeclarationSyntax && propertyDeclarationSyntax.ExpressionBody.Expression is ExpressionSyntax expression) + { + // expression-bodied property: select the expression + return expression.Span; } else { - return propertyDeclaration; + // property: no accessors; move caret to the end of the declaration + return new TextSpan(propertyDeclaration.Span.End, 0); } } diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProvider.ItemGetter.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProvider.ItemGetter.cs index 019a0e89063e7..f1d474d0dbae5 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProvider.ItemGetter.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProvider.ItemGetter.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Immutable; -using System.ComponentModel; using System.Linq; using System.Text; using System.Threading; diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProvider.cs index 9312dc1603a1a..36ebd6c640332 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProvider.cs @@ -17,7 +17,6 @@ using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers; @@ -97,9 +96,9 @@ protected override SyntaxNode GetSyntax(SyntaxToken token) throw ExceptionUtilities.UnexpectedValue(token); } - protected override int GetTargetCaretPosition(SyntaxNode caretTarget) + protected override TextSpan GetTargetSelectionSpan(SyntaxNode caretTarget) { - return CompletionUtilities.GetTargetCaretNodeForInsertedMember(caretTarget).GetLocation().SourceSpan.End; + return CompletionUtilities.GetTargetSelectionSpanForInsertedMember(caretTarget); } public override async Task ProvideCompletionsAsync(CompletionContext context) diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/KeywordCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/KeywordCompletionProvider.cs index 7958a6948366e..500cbacf8d656 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/KeywordCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/KeywordCompletionProvider.cs @@ -15,166 +15,160 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers; -[ExportCompletionProvider(nameof(KeywordCompletionProvider), LanguageNames.CSharp)] +[ExportCompletionProvider(nameof(KeywordCompletionProvider), LanguageNames.CSharp), Shared] [ExtensionOrder(After = nameof(NamedParameterCompletionProvider))] -[Shared] -internal class KeywordCompletionProvider : AbstractKeywordCompletionProvider +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class KeywordCompletionProvider() : AbstractKeywordCompletionProvider([ + new AbstractKeywordRecommender(), + new AddKeywordRecommender(), + new AliasKeywordRecommender(), + new AllowsKeywordRecommender(), + new AndKeywordRecommender(), + new AnnotationsKeywordRecommender(), + new AscendingKeywordRecommender(), + new AsKeywordRecommender(), + new AssemblyKeywordRecommender(), + new AsyncKeywordRecommender(), + new BaseKeywordRecommender(), + new BoolKeywordRecommender(), + new BreakKeywordRecommender(), + new ByKeywordRecommender(), + new ByteKeywordRecommender(), + new CaseKeywordRecommender(), + new CatchKeywordRecommender(), + new CharKeywordRecommender(), + new CheckedKeywordRecommender(), + new ChecksumKeywordRecommender(), + new ClassKeywordRecommender(), + new ConstKeywordRecommender(), + new ContinueKeywordRecommender(), + new DecimalKeywordRecommender(), + new DefaultKeywordRecommender(), + new DefineKeywordRecommender(), + new DelegateKeywordRecommender(), + new DescendingKeywordRecommender(), + new DisableKeywordRecommender(), + new DoKeywordRecommender(), + new DoubleKeywordRecommender(), + new DynamicKeywordRecommender(), + new ElifKeywordRecommender(), + new ElseKeywordRecommender(), + new EnableKeywordRecommender(), + new EndIfKeywordRecommender(), + new EndRegionKeywordRecommender(), + new EnumKeywordRecommender(), + new EqualsKeywordRecommender(), + new ErrorKeywordRecommender(), + new EventKeywordRecommender(), + new ExplicitKeywordRecommender(), + new ExtensionKeywordRecommender(), + new ExternKeywordRecommender(), + new FalseKeywordRecommender(), + new FieldKeywordRecommender(), + new FileKeywordRecommender(), + new FinallyKeywordRecommender(), + new FixedKeywordRecommender(), + new FloatKeywordRecommender(), + new ForEachKeywordRecommender(), + new ForKeywordRecommender(), + new FromKeywordRecommender(), + new GetKeywordRecommender(), + new GlobalKeywordRecommender(), + new GotoKeywordRecommender(), + new GroupKeywordRecommender(), + new HiddenKeywordRecommender(), + new IfKeywordRecommender(), + new ImplicitKeywordRecommender(), + new InitKeywordRecommender(), + new InKeywordRecommender(), + new InterfaceKeywordRecommender(), + new InternalKeywordRecommender(), + new IntKeywordRecommender(), + new IntoKeywordRecommender(), + new IsKeywordRecommender(), + new JoinKeywordRecommender(), + new LetKeywordRecommender(), + new LineKeywordRecommender(), + new LoadKeywordRecommender(), + new LockKeywordRecommender(), + new LongKeywordRecommender(), + new ManagedKeywordRecommender(), + new MethodKeywordRecommender(), + new ModuleKeywordRecommender(), + new NameOfKeywordRecommender(), + new NamespaceKeywordRecommender(), + new NewKeywordRecommender(), + new NintKeywordRecommender(), + new NotKeywordRecommender(), + new NotNullKeywordRecommender(), + new NuintKeywordRecommender(), + new NullableKeywordRecommender(), + new NullKeywordRecommender(), + new ObjectKeywordRecommender(), + new OnKeywordRecommender(), + new OperatorKeywordRecommender(), + new OrderByKeywordRecommender(), + new OrKeywordRecommender(), + new OutKeywordRecommender(), + new OverrideKeywordRecommender(), + new ParamKeywordRecommender(), + new ParamsKeywordRecommender(), + new PartialKeywordRecommender(), + new PragmaKeywordRecommender(), + new PrivateKeywordRecommender(), + new PropertyKeywordRecommender(), + new ProtectedKeywordRecommender(), + new PublicKeywordRecommender(), + new ReadOnlyKeywordRecommender(), + new RecordKeywordRecommender(), + new ReferenceKeywordRecommender(), + new RefKeywordRecommender(), + new RegionKeywordRecommender(), + new RemoveKeywordRecommender(), + new RequiredKeywordRecommender(), + new RestoreKeywordRecommender(), + new ReturnKeywordRecommender(), + new SByteKeywordRecommender(), + new ScopedKeywordRecommender(), + new SealedKeywordRecommender(), + new SelectKeywordRecommender(), + new SetKeywordRecommender(), + new ShortKeywordRecommender(), + new SizeOfKeywordRecommender(), + new StackAllocKeywordRecommender(), + new StaticKeywordRecommender(), + new StringKeywordRecommender(), + new StructKeywordRecommender(), + new SwitchKeywordRecommender(), + new ThisKeywordRecommender(), + new ThrowKeywordRecommender(), + new TrueKeywordRecommender(), + new TryKeywordRecommender(), + new TypeKeywordRecommender(), + new TypeOfKeywordRecommender(), + new TypeVarKeywordRecommender(), + new UIntKeywordRecommender(), + new ULongKeywordRecommender(), + new UncheckedKeywordRecommender(), + new UndefKeywordRecommender(), + new UnmanagedKeywordRecommender(), + new UnsafeKeywordRecommender(), + new UShortKeywordRecommender(), + new UsingKeywordRecommender(), + new VarKeywordRecommender(), + new VirtualKeywordRecommender(), + new VoidKeywordRecommender(), + new VolatileKeywordRecommender(), + new WarningKeywordRecommender(), + new WarningsKeywordRecommender(), + new WhenKeywordRecommender(), + new WhereKeywordRecommender(), + new WhileKeywordRecommender(), + new WithKeywordRecommender(), + new YieldKeywordRecommender(), + ]) { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public KeywordCompletionProvider() - : base( - [ - new AbstractKeywordRecommender(), - new AddKeywordRecommender(), - new AliasKeywordRecommender(), - new AllowsKeywordRecommender(), - new AndKeywordRecommender(), - new AnnotationsKeywordRecommender(), - new AscendingKeywordRecommender(), - new AsKeywordRecommender(), - new AssemblyKeywordRecommender(), - new AsyncKeywordRecommender(), - new BaseKeywordRecommender(), - new BoolKeywordRecommender(), - new BreakKeywordRecommender(), - new ByKeywordRecommender(), - new ByteKeywordRecommender(), - new CaseKeywordRecommender(), - new CatchKeywordRecommender(), - new CharKeywordRecommender(), - new CheckedKeywordRecommender(), - new ChecksumKeywordRecommender(), - new ClassKeywordRecommender(), - new ConstKeywordRecommender(), - new ContinueKeywordRecommender(), - new DecimalKeywordRecommender(), - new DefaultKeywordRecommender(), - new DefineKeywordRecommender(), - new DelegateKeywordRecommender(), - new DescendingKeywordRecommender(), - new DisableKeywordRecommender(), - new DoKeywordRecommender(), - new DoubleKeywordRecommender(), - new DynamicKeywordRecommender(), - new ElifKeywordRecommender(), - new ElseKeywordRecommender(), - new EnableKeywordRecommender(), - new EndIfKeywordRecommender(), - new EndRegionKeywordRecommender(), - new EnumKeywordRecommender(), - new EqualsKeywordRecommender(), - new ErrorKeywordRecommender(), - new EventKeywordRecommender(), - new ExplicitKeywordRecommender(), - new ExternKeywordRecommender(), - new FalseKeywordRecommender(), - new FieldKeywordRecommender(), - new FileKeywordRecommender(), - new FinallyKeywordRecommender(), - new FixedKeywordRecommender(), - new FloatKeywordRecommender(), - new ForEachKeywordRecommender(), - new ForKeywordRecommender(), - new FromKeywordRecommender(), - new GetKeywordRecommender(), - new GlobalKeywordRecommender(), - new GotoKeywordRecommender(), - new GroupKeywordRecommender(), - new HiddenKeywordRecommender(), - new IfKeywordRecommender(), - new ImplicitKeywordRecommender(), - new InitKeywordRecommender(), - new InKeywordRecommender(), - new InterfaceKeywordRecommender(), - new InternalKeywordRecommender(), - new IntKeywordRecommender(), - new IntoKeywordRecommender(), - new IsKeywordRecommender(), - new JoinKeywordRecommender(), - new LetKeywordRecommender(), - new LineKeywordRecommender(), - new LoadKeywordRecommender(), - new LockKeywordRecommender(), - new LongKeywordRecommender(), - new ManagedKeywordRecommender(), - new MethodKeywordRecommender(), - new ModuleKeywordRecommender(), - new NameOfKeywordRecommender(), - new NamespaceKeywordRecommender(), - new NewKeywordRecommender(), - new NintKeywordRecommender(), - new NotKeywordRecommender(), - new NotNullKeywordRecommender(), - new NuintKeywordRecommender(), - new NullableKeywordRecommender(), - new NullKeywordRecommender(), - new ObjectKeywordRecommender(), - new OnKeywordRecommender(), - new OperatorKeywordRecommender(), - new OrderByKeywordRecommender(), - new OrKeywordRecommender(), - new OutKeywordRecommender(), - new OverrideKeywordRecommender(), - new ParamKeywordRecommender(), - new ParamsKeywordRecommender(), - new PartialKeywordRecommender(), - new PragmaKeywordRecommender(), - new PrivateKeywordRecommender(), - new PropertyKeywordRecommender(), - new ProtectedKeywordRecommender(), - new PublicKeywordRecommender(), - new ReadOnlyKeywordRecommender(), - new RecordKeywordRecommender(), - new ReferenceKeywordRecommender(), - new RefKeywordRecommender(), - new RegionKeywordRecommender(), - new RemoveKeywordRecommender(), - new RequiredKeywordRecommender(), - new RestoreKeywordRecommender(), - new ReturnKeywordRecommender(), - new SByteKeywordRecommender(), - new ScopedKeywordRecommender(), - new SealedKeywordRecommender(), - new SelectKeywordRecommender(), - new SetKeywordRecommender(), - new ShortKeywordRecommender(), - new SizeOfKeywordRecommender(), - new StackAllocKeywordRecommender(), - new StaticKeywordRecommender(), - new StringKeywordRecommender(), - new StructKeywordRecommender(), - new SwitchKeywordRecommender(), - new ThisKeywordRecommender(), - new ThrowKeywordRecommender(), - new TrueKeywordRecommender(), - new TryKeywordRecommender(), - new TypeKeywordRecommender(), - new TypeOfKeywordRecommender(), - new TypeVarKeywordRecommender(), - new UIntKeywordRecommender(), - new ULongKeywordRecommender(), - new UncheckedKeywordRecommender(), - new UndefKeywordRecommender(), - new UnmanagedKeywordRecommender(), - new UnsafeKeywordRecommender(), - new UShortKeywordRecommender(), - new UsingKeywordRecommender(), - new VarKeywordRecommender(), - new VirtualKeywordRecommender(), - new VoidKeywordRecommender(), - new VolatileKeywordRecommender(), - new WarningKeywordRecommender(), - new WarningsKeywordRecommender(), - new WhenKeywordRecommender(), - new WhereKeywordRecommender(), - new WhileKeywordRecommender(), - new WithKeywordRecommender(), - new YieldKeywordRecommender(), - ]) - { - } - internal override string Language => LanguageNames.CSharp; public override bool IsInsertionTrigger(SourceText text, int characterPosition, CompletionOptions options) diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/OperatorsAndIndexer/UnnamedSymbolCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/OperatorsAndIndexer/UnnamedSymbolCompletionProvider.cs index 8e5999af497b1..00570566f14be 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/OperatorsAndIndexer/UnnamedSymbolCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/OperatorsAndIndexer/UnnamedSymbolCompletionProvider.cs @@ -16,7 +16,6 @@ using Microsoft.CodeAnalysis.Recommendations; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers; diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/OverrideCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/OverrideCompletionProvider.cs index 0dfefd0d30513..a126df2d1f5c6 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/OverrideCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/OverrideCompletionProvider.cs @@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers; @@ -204,8 +203,8 @@ public override ImmutableArray FilterOverrides(ImmutableArray return filteredMembers.Length > 0 ? filteredMembers : members; } - protected override int GetTargetCaretPosition(SyntaxNode caretTarget) + protected override TextSpan GetTargetSelectionSpan(SyntaxNode caretTarget) { - return CompletionUtilities.GetTargetCaretNodeForInsertedMember(caretTarget).GetLocation().SourceSpan.End; + return CompletionUtilities.GetTargetSelectionSpanForInsertedMember(caretTarget); } } diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/PartialMethodCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/PartialMethodCompletionProvider.cs index 65f39e620f798..f1c6f787a9098 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/PartialMethodCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/PartialMethodCompletionProvider.cs @@ -61,10 +61,10 @@ protected override SyntaxNode GetSyntax(SyntaxToken token) ?? throw ExceptionUtilities.UnexpectedValue(token); } - protected override int GetTargetCaretPosition(SyntaxNode caretTarget) + protected override TextSpan GetTargetSelectionSpan(SyntaxNode caretTarget) { var methodDeclaration = (MethodDeclarationSyntax)caretTarget; - return CompletionUtilities.GetTargetCaretPositionForMethod(methodDeclaration).GetLocation().SourceSpan.End; + return CompletionUtilities.GetTargetSelectionSpanForInsertedMember(methodDeclaration); } protected override SyntaxToken GetToken(CompletionItem completionItem, SyntaxTree tree, CancellationToken cancellationToken) diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/PropertySubPatternCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/PropertySubPatternCompletionProvider.cs index 76a30bd231ad3..1c3bfbed51d03 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/PropertySubPatternCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/PropertySubPatternCompletionProvider.cs @@ -18,7 +18,6 @@ using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers; diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/SnippetCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/SnippetCompletionProvider.cs index 6df55c5e6ee55..a7b7a5ce93764 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/SnippetCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/SnippetCompletionProvider.cs @@ -51,6 +51,7 @@ internal sealed class SnippetCompletionProvider : LSPCompletionProvider CSharpSnippetIdentifiers.StaticIntMain, CSharpSnippetIdentifiers.Struct, CSharpSnippetIdentifiers.StaticVoidMain, + CSharpSnippetIdentifiers.Using, CSharpSnippetIdentifiers.While ]; diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/SpeculativeTCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/SpeculativeTCompletionProvider.cs index e63e511349261..7b47119643a4c 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/SpeculativeTCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/SpeculativeTCompletionProvider.cs @@ -101,7 +101,7 @@ private static bool IsStartOfSpeculativeTContext(SyntaxTree syntaxTree, int posi { var token = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken); - return syntaxTree.IsMemberDeclarationContext(position, context: null, SyntaxKindSet.AllMemberModifiers, SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, canBePartial: true, cancellationToken) || + return syntaxTree.IsMemberDeclarationContext(position, context: null, SyntaxKindSet.AllMemberModifiers, SyntaxKindSet.NonEnumTypeDeclarations, canBePartial: true, cancellationToken) || syntaxTree.IsStatementContext(position, token, cancellationToken) || syntaxTree.IsGlobalMemberDeclarationContext(position, SyntaxKindSet.AllGlobalMemberModifiers, cancellationToken) || syntaxTree.IsGlobalStatementContext(position, cancellationToken) || diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AbstractKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AbstractKeywordRecommender.cs index b5fa226cdc805..618804e218ce7 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AbstractKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AbstractKeywordRecommender.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class AbstractKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class AbstractKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.AbstractKeyword) { private static readonly ISet s_validNonInterfaceMemberModifiers = new HashSet(SyntaxFacts.EqualityComparer) { @@ -45,11 +45,6 @@ internal class AbstractKeywordRecommender : AbstractSyntacticSingleKeywordRecomm SyntaxKind.FileKeyword, }; - public AbstractKeywordRecommender() - : base(SyntaxKind.AbstractKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AddKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AddKeywordRecommender.cs index 1435aa60d1a65..6e8ab182339bd 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AddKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AddKeywordRecommender.cs @@ -8,13 +8,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class AddKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class AddKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.AddKeyword) { - public AddKeywordRecommender() - : base(SyntaxKind.AddKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.TargetToken.IsAccessorDeclarationContext(position, SyntaxKind.AddKeyword); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AliasKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AliasKeywordRecommender.cs index f3f6d2c5f56ea..7d6320f01b172 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AliasKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AliasKeywordRecommender.cs @@ -9,13 +9,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class AliasKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class AliasKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.AliasKeyword) { - public AliasKeywordRecommender() - : base(SyntaxKind.AliasKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { // cases: diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AllowsKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AllowsKeywordRecommender.cs index 4a805d2a16ba7..c047705a1c956 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AllowsKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AllowsKeywordRecommender.cs @@ -9,13 +9,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class AllowsKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class AllowsKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.AllowsKeyword) { - public AllowsKeywordRecommender() - : base(SyntaxKind.AllowsKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return IsAllowsRefStructConstraintContext(context); diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AndKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AndKeywordRecommender.cs index b38e4af55dd06..efe7e52e95c98 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AndKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AndKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class AndKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class AndKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.AndKeyword) { - public AndKeywordRecommender() - : base(SyntaxKind.AndKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.IsAtEndOfPattern; } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AnnotationsKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AnnotationsKeywordRecommender.cs index 3137f750a709c..371f3fb4f6020 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AnnotationsKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AnnotationsKeywordRecommender.cs @@ -7,13 +7,9 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class AnnotationsKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class AnnotationsKeywordRecommender() + : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.AnnotationsKeyword, isValidInPreprocessorContext: true) { - public AnnotationsKeywordRecommender() - : base(SyntaxKind.AnnotationsKeyword, isValidInPreprocessorContext: true) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var previousToken1 = context.TargetToken; diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AsKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AsKeywordRecommender.cs index 4bd98f826ca8d..948e99553d869 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AsKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AsKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class AsKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class AsKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.AsKeyword) { - public AsKeywordRecommender() - : base(SyntaxKind.AsKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => !context.IsInNonUserCode && context.IsIsOrAsOrSwitchOrWithExpressionContext; } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AscendingKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AscendingKeywordRecommender.cs index 7676ae1f91bad..5671c1ed87b4f 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AscendingKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AscendingKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class AscendingKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class AscendingKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.AscendingKeyword) { - public AscendingKeywordRecommender() - : base(SyntaxKind.AscendingKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.TargetToken.IsOrderByDirectionContext(); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AssemblyKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AssemblyKeywordRecommender.cs index 511ecb03a91c7..a7ea2679d1324 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AssemblyKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AssemblyKeywordRecommender.cs @@ -9,13 +9,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class AssemblyKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class AssemblyKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.AssemblyKeyword) { - public AssemblyKeywordRecommender() - : base(SyntaxKind.AssemblyKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var token = context.TargetToken; diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AsyncKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AsyncKeywordRecommender.cs index 938e52df3c476..bbb1fc81cdaab 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AsyncKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AsyncKeywordRecommender.cs @@ -10,13 +10,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class AsyncKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class AsyncKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.AsyncKeyword, isValidInPreprocessorContext: false) { - public AsyncKeywordRecommender() - : base(SyntaxKind.AsyncKeyword, isValidInPreprocessorContext: false) - { - } - private static readonly ISet s_validLocalFunctionModifiers = new HashSet(SyntaxFacts.EqualityComparer) { SyntaxKind.StaticKeyword, @@ -42,7 +37,7 @@ private static bool InMemberDeclarationContext(int position, CSharpSyntaxContext || context.SyntaxTree.IsGlobalMemberDeclarationContext(position, SyntaxKindSet.AllGlobalMemberModifiers, cancellationToken) || context.IsMemberDeclarationContext( validModifiers: SyntaxKindSet.AllMemberModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, canBePartial: true, cancellationToken: cancellationToken); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/BaseKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/BaseKeywordRecommender.cs index 1395a08503574..b78b3b3745e7b 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/BaseKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/BaseKeywordRecommender.cs @@ -10,13 +10,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class BaseKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class BaseKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.BaseKeyword) { - public BaseKeywordRecommender() - : base(SyntaxKind.BaseKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { // We need to at least be in a type declaration context. This prevents us from showing diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/BoolKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/BoolKeywordRecommender.cs index d8a0e47124241..bfaae8ae25f9d 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/BoolKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/BoolKeywordRecommender.cs @@ -11,13 +11,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class BoolKeywordRecommender : AbstractSpecialTypePreselectingKeywordRecommender +internal sealed class BoolKeywordRecommender() : AbstractSpecialTypePreselectingKeywordRecommender(SyntaxKind.BoolKeyword) { - public BoolKeywordRecommender() - : base(SyntaxKind.BoolKeyword) - { - } - protected override bool IsValidContextWorker(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var syntaxTree = context.SyntaxTree; @@ -46,8 +41,8 @@ protected override bool IsValidContextWorker(int position, CSharpSyntaxContext c context.IsPossibleTupleContext || context.IsMemberDeclarationContext( validModifiers: SyntaxKindSet.AllMemberModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, - canBePartial: false, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, + canBePartial: true, cancellationToken: cancellationToken); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/BreakKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/BreakKeywordRecommender.cs index 0b2408309c513..12279599e2196 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/BreakKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/BreakKeywordRecommender.cs @@ -10,13 +10,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class BreakKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class BreakKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.BreakKeyword) { - public BreakKeywordRecommender() - : base(SyntaxKind.BreakKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ByKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ByKeywordRecommender.cs index e0a41695d0bb2..7b77ea5eec5e8 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ByKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ByKeywordRecommender.cs @@ -10,13 +10,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class ByKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class ByKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.ByKeyword) { - public ByKeywordRecommender() - : base(SyntaxKind.ByKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { // cases: diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ByteKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ByteKeywordRecommender.cs index c9b5ebfd4d1aa..a7b5e06e48371 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ByteKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ByteKeywordRecommender.cs @@ -11,13 +11,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class ByteKeywordRecommender : AbstractSpecialTypePreselectingKeywordRecommender +internal sealed class ByteKeywordRecommender() : AbstractSpecialTypePreselectingKeywordRecommender(SyntaxKind.ByteKeyword) { - public ByteKeywordRecommender() - : base(SyntaxKind.ByteKeyword) - { - } - protected override bool IsValidContextWorker(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var syntaxTree = context.SyntaxTree; @@ -47,8 +42,8 @@ protected override bool IsValidContextWorker(int position, CSharpSyntaxContext c context.IsPossibleTupleContext || context.IsMemberDeclarationContext( validModifiers: SyntaxKindSet.AllMemberModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, - canBePartial: false, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, + canBePartial: true, cancellationToken: cancellationToken); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/CaseKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/CaseKeywordRecommender.cs index d45fa895ef8ac..2a5e494498cc5 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/CaseKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/CaseKeywordRecommender.cs @@ -9,13 +9,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class CaseKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class CaseKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.CaseKeyword) { - public CaseKeywordRecommender() - : base(SyntaxKind.CaseKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/CatchKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/CatchKeywordRecommender.cs index 3662ee41ebed9..9d34aaa5c5f09 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/CatchKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/CatchKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class CatchKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class CatchKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.CatchKeyword) { - public CatchKeywordRecommender() - : base(SyntaxKind.CatchKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.SyntaxTree.IsCatchOrFinallyContext(position, context.LeftToken); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/CharKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/CharKeywordRecommender.cs index 7f1da322b9aa7..95aca34d8a3b0 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/CharKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/CharKeywordRecommender.cs @@ -11,13 +11,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class CharKeywordRecommender : AbstractSpecialTypePreselectingKeywordRecommender +internal sealed class CharKeywordRecommender() : AbstractSpecialTypePreselectingKeywordRecommender(SyntaxKind.CharKeyword) { - public CharKeywordRecommender() - : base(SyntaxKind.CharKeyword) - { - } - protected override bool IsValidContextWorker(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var syntaxTree = context.SyntaxTree; @@ -46,8 +41,8 @@ protected override bool IsValidContextWorker(int position, CSharpSyntaxContext c context.IsPossibleTupleContext || context.IsMemberDeclarationContext( validModifiers: SyntaxKindSet.AllMemberModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, - canBePartial: false, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, + canBePartial: true, cancellationToken: cancellationToken); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/CheckedKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/CheckedKeywordRecommender.cs index 606e0dfa120ee..a2cc6065078d8 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/CheckedKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/CheckedKeywordRecommender.cs @@ -10,13 +10,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class CheckedKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class CheckedKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.CheckedKeyword) { - public CheckedKeywordRecommender() - : base(SyntaxKind.CheckedKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { if (context.IsStatementContext || diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ChecksumKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ChecksumKeywordRecommender.cs index 24c0523e6d6ca..d35436aa98fd8 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ChecksumKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ChecksumKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class ChecksumKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class ChecksumKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.ChecksumKeyword, isValidInPreprocessorContext: true) { - public ChecksumKeywordRecommender() - : base(SyntaxKind.ChecksumKeyword, isValidInPreprocessorContext: true) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { // # pragma | diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ClassKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ClassKeywordRecommender.cs index 9102e13a1777b..4937e10c9e00b 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ClassKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ClassKeywordRecommender.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class ClassKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class ClassKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.ClassKeyword) { private static readonly ISet s_validModifiers = new HashSet(SyntaxFacts.EqualityComparer) { @@ -25,11 +25,6 @@ internal class ClassKeywordRecommender : AbstractSyntacticSingleKeywordRecommend SyntaxKind.FileKeyword, }; - public ClassKeywordRecommender() - : base(SyntaxKind.ClassKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var syntaxTree = context.SyntaxTree; @@ -37,7 +32,7 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context context.IsGlobalStatementContext || context.IsTypeDeclarationContext( validModifiers: s_validModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, canBePartial: true, cancellationToken: cancellationToken) || context.IsRecordDeclarationContext(s_validModifiers, cancellationToken) || diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ConstKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ConstKeywordRecommender.cs index 7c0fe78ee4912..af781fdb2f3d4 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ConstKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ConstKeywordRecommender.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class ConstKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class ConstKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.ConstKeyword) { private static readonly ISet s_validModifiers = new HashSet(SyntaxFacts.EqualityComparer) { @@ -28,11 +28,6 @@ internal class ConstKeywordRecommender : AbstractSyntacticSingleKeywordRecommend SyntaxKind.PrivateKeyword, }; - public ConstKeywordRecommender() - : base(SyntaxKind.ConstKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ContinueKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ContinueKeywordRecommender.cs index 6ec1cc64b0e1b..48cd8fc9e7079 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ContinueKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ContinueKeywordRecommender.cs @@ -10,13 +10,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class ContinueKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class ContinueKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.ContinueKeyword) { - public ContinueKeywordRecommender() - : base(SyntaxKind.ContinueKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { if (!context.IsStatementContext) diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DecimalKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DecimalKeywordRecommender.cs index 89c52e2e156fa..0ddc2cebf60e0 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DecimalKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DecimalKeywordRecommender.cs @@ -11,13 +11,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class DecimalKeywordRecommender : AbstractSpecialTypePreselectingKeywordRecommender +internal sealed class DecimalKeywordRecommender() : AbstractSpecialTypePreselectingKeywordRecommender(SyntaxKind.DecimalKeyword) { - public DecimalKeywordRecommender() - : base(SyntaxKind.DecimalKeyword) - { - } - protected override bool IsValidContextWorker(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var syntaxTree = context.SyntaxTree; @@ -46,8 +41,8 @@ protected override bool IsValidContextWorker(int position, CSharpSyntaxContext c context.IsPossibleTupleContext || context.IsMemberDeclarationContext( validModifiers: SyntaxKindSet.AllMemberModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, - canBePartial: false, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, + canBePartial: true, cancellationToken: cancellationToken); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DefaultKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DefaultKeywordRecommender.cs index 4a44532fc58bb..188576daaea57 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DefaultKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DefaultKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class DefaultKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class DefaultKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.DefaultKeyword, isValidInPreprocessorContext: true) { - public DefaultKeywordRecommender() - : base(SyntaxKind.DefaultKeyword, isValidInPreprocessorContext: true) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DefineKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DefineKeywordRecommender.cs index 695838bb564b1..c4e9b9b882d96 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DefineKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DefineKeywordRecommender.cs @@ -8,13 +8,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class DefineKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class DefineKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.DefineKeyword, isValidInPreprocessorContext: true) { - public DefineKeywordRecommender() - : base(SyntaxKind.DefineKeyword, isValidInPreprocessorContext: true) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.IsPreProcessorKeywordContext && context.SyntaxTree.IsBeforeFirstToken(position, cancellationToken); diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DelegateKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DelegateKeywordRecommender.cs index 6b00e220af89c..8a89291292c7c 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DelegateKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DelegateKeywordRecommender.cs @@ -28,7 +28,7 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context IsAfterAsyncKeywordInExpressionContext(context, cancellationToken) || context.IsTypeDeclarationContext( validModifiers: s_validModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, canBePartial: false, cancellationToken: cancellationToken)) { diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DescendingKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DescendingKeywordRecommender.cs index 2b3a0c1c0f2ae..75ceeb107e0b9 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DescendingKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DescendingKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class DescendingKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class DescendingKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.DescendingKeyword) { - public DescendingKeywordRecommender() - : base(SyntaxKind.DescendingKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.TargetToken.IsOrderByDirectionContext(); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DisableKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DisableKeywordRecommender.cs index ad3b3dd970523..d673115143674 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DisableKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DisableKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class DisableKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class DisableKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.DisableKeyword, isValidInPreprocessorContext: true) { - public DisableKeywordRecommender() - : base(SyntaxKind.DisableKeyword, isValidInPreprocessorContext: true) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var previousToken1 = context.TargetToken; diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DoKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DoKeywordRecommender.cs index c08d2634c328e..ce5fd34ce6740 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DoKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DoKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class DoKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class DoKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.DoKeyword) { - public DoKeywordRecommender() - : base(SyntaxKind.DoKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.IsStatementContext || context.IsGlobalStatementContext; } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DoubleKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DoubleKeywordRecommender.cs index d3186c219d6c3..1eea7f3af0b26 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DoubleKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DoubleKeywordRecommender.cs @@ -11,13 +11,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class DoubleKeywordRecommender : AbstractSpecialTypePreselectingKeywordRecommender +internal sealed class DoubleKeywordRecommender() : AbstractSpecialTypePreselectingKeywordRecommender(SyntaxKind.DoubleKeyword) { - public DoubleKeywordRecommender() - : base(SyntaxKind.DoubleKeyword) - { - } - protected override bool IsValidContextWorker(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var syntaxTree = context.SyntaxTree; @@ -46,8 +41,8 @@ protected override bool IsValidContextWorker(int position, CSharpSyntaxContext c context.IsPossibleTupleContext || context.IsMemberDeclarationContext( validModifiers: SyntaxKindSet.AllMemberModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, - canBePartial: false, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, + canBePartial: true, cancellationToken: cancellationToken); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DynamicKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DynamicKeywordRecommender.cs index 293458e9899f1..2bf8fb80d5d37 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DynamicKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DynamicKeywordRecommender.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class DynamicKeywordRecommender : IKeywordRecommender +internal sealed class DynamicKeywordRecommender : IKeywordRecommender { private static bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { @@ -31,7 +31,7 @@ public ImmutableArray RecommendKeywords(int position, CSharp : []; } - protected static bool IsDynamicTypeContext( + private static bool IsDynamicTypeContext( int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var syntaxTree = context.SyntaxTree; @@ -63,8 +63,8 @@ protected static bool IsDynamicTypeContext( syntaxTree.IsGlobalMemberDeclarationContext(position, SyntaxKindSet.AllGlobalMemberModifiers, cancellationToken) || context.IsMemberDeclarationContext( validModifiers: SyntaxKindSet.AllMemberModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, - canBePartial: false, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, + canBePartial: true, cancellationToken: cancellationToken); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ElifKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ElifKeywordRecommender.cs index 5ff98840b21f1..072f5cf512582 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ElifKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ElifKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class ElifKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class ElifKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.ElifKeyword, isValidInPreprocessorContext: true) { - public ElifKeywordRecommender() - : base(SyntaxKind.ElifKeyword, isValidInPreprocessorContext: true) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.IsPreProcessorKeywordContext; } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ElseKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ElseKeywordRecommender.cs index 2fe2b078a1522..6390290ae90bb 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ElseKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ElseKeywordRecommender.cs @@ -9,13 +9,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class ElseKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class ElseKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.ElseKeyword, isValidInPreprocessorContext: true) { - public ElseKeywordRecommender() - : base(SyntaxKind.ElseKeyword, isValidInPreprocessorContext: true) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { if (context.IsPreProcessorKeywordContext) diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/EnableKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/EnableKeywordRecommender.cs index fc345c8f8eec4..b8c56a7511556 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/EnableKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/EnableKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class EnableKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class EnableKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.EnableKeyword, isValidInPreprocessorContext: true) { - public EnableKeywordRecommender() - : base(SyntaxKind.EnableKeyword, isValidInPreprocessorContext: true) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var previousToken1 = context.TargetToken; diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/EndIfKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/EndIfKeywordRecommender.cs index 3f88e5985b0eb..4c2f537f8ea66 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/EndIfKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/EndIfKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class EndIfKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class EndIfKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.EndIfKeyword, isValidInPreprocessorContext: true) { - public EndIfKeywordRecommender() - : base(SyntaxKind.EndIfKeyword, isValidInPreprocessorContext: true) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.IsPreProcessorKeywordContext; } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/EndRegionKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/EndRegionKeywordRecommender.cs index 2ce9c088fca51..e97b33bef0bb3 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/EndRegionKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/EndRegionKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class EndRegionKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class EndRegionKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.EndRegionKeyword, isValidInPreprocessorContext: true, shouldFormatOnCommit: true) { - public EndRegionKeywordRecommender() - : base(SyntaxKind.EndRegionKeyword, isValidInPreprocessorContext: true, shouldFormatOnCommit: true) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.IsPreProcessorKeywordContext; } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/EnumKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/EnumKeywordRecommender.cs index d2c0ff0abe005..e96a0ecb1ee14 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/EnumKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/EnumKeywordRecommender.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class EnumKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class EnumKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.EnumKeyword) { private static readonly ISet s_validModifiers = new HashSet(SyntaxFacts.EqualityComparer) { @@ -19,18 +19,13 @@ internal class EnumKeywordRecommender : AbstractSyntacticSingleKeywordRecommende SyntaxKind.ProtectedKeyword, }; - public EnumKeywordRecommender() - : base(SyntaxKind.EnumKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return context.IsGlobalStatementContext || context.IsTypeDeclarationContext( validModifiers: s_validModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, canBePartial: false, cancellationToken: cancellationToken); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/EqualsKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/EqualsKeywordRecommender.cs index 6273639451bc5..94152eed802bd 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/EqualsKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/EqualsKeywordRecommender.cs @@ -9,13 +9,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class EqualsKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class EqualsKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.EqualsKeyword) { - public EqualsKeywordRecommender() - : base(SyntaxKind.EqualsKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { // cases: diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ErrorKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ErrorKeywordRecommender.cs index c8aac6fad50b5..707f192319b97 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ErrorKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ErrorKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class ErrorKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class ErrorKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.ErrorKeyword, isValidInPreprocessorContext: true) { - public ErrorKeywordRecommender() - : base(SyntaxKind.ErrorKeyword, isValidInPreprocessorContext: true) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.IsPreProcessorKeywordContext; } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/EventKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/EventKeywordRecommender.cs index 8fcdd6a51aac0..42cee0617a245 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/EventKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/EventKeywordRecommender.cs @@ -39,8 +39,8 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context return (context.IsGlobalStatementContext && syntaxTree.IsScript()) || syntaxTree.IsGlobalMemberDeclarationContext(position, SyntaxKindSet.AllGlobalMemberModifiers, cancellationToken) || - context.IsMemberDeclarationContext(validModifiers: s_validClassModifiers, validTypeDeclarations: SyntaxKindSet.ClassInterfaceRecordTypeDeclarations, canBePartial: false, cancellationToken: cancellationToken) || - context.IsMemberDeclarationContext(validModifiers: s_validStructModifiers, validTypeDeclarations: SyntaxKindSet.StructOnlyTypeDeclarations, canBePartial: false, cancellationToken: cancellationToken) || - context.IsMemberAttributeContext(SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, includingRecordParameters: false, cancellationToken); + context.IsMemberDeclarationContext(validModifiers: s_validClassModifiers, validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, canBePartial: true, cancellationToken: cancellationToken) || + context.IsMemberDeclarationContext(validModifiers: s_validStructModifiers, validTypeDeclarations: SyntaxKindSet.StructOnlyTypeDeclarations, canBePartial: true, cancellationToken: cancellationToken) || + context.IsMemberAttributeContext(SyntaxKindSet.NonEnumTypeDeclarations, includingRecordParameters: false, cancellationToken); } } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ExplicitKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ExplicitKeywordRecommender.cs index b0dbf2efebe31..b5613bc31c191 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ExplicitKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ExplicitKeywordRecommender.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class ExplicitKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class ExplicitKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.ExplicitKeyword) { private static readonly ISet s_validNonInterfaceMemberModifiers = new HashSet(SyntaxFacts.EqualityComparer) { @@ -27,11 +27,6 @@ internal class ExplicitKeywordRecommender : AbstractSyntacticSingleKeywordRecomm SyntaxKind.UnsafeKeyword, }; - public ExplicitKeywordRecommender() - : base(SyntaxKind.ExplicitKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { if (context.IsMemberDeclarationContext(validModifiers: s_validNonInterfaceMemberModifiers, validTypeDeclarations: SyntaxKindSet.ClassStructRecordTypeDeclarations, canBePartial: false, cancellationToken: cancellationToken)) diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ExtensionKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ExtensionKeywordRecommender.cs new file mode 100644 index 0000000000000..ce7bc623fce5e --- /dev/null +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ExtensionKeywordRecommender.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.Collections.Generic; +using System.Threading; +using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; + +namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; + +internal sealed class ExtensionKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.ExtensionKeyword) +{ + private static readonly ISet s_validModifiers = new HashSet(SyntaxFacts.EqualityComparer); + private static readonly ISet s_validTypeDeclarations = new HashSet(SyntaxFacts.EqualityComparer) + { + SyntaxKind.ClassDeclaration + }; + + protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) + { + return + context.ContainingTypeDeclaration?.Modifiers.Any(SyntaxKind.StaticKeyword) is true && + context.IsTypeDeclarationContext( + validModifiers: s_validModifiers, + validTypeDeclarations: s_validTypeDeclarations, + canBePartial: false, + cancellationToken); + } +} diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ExternKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ExternKeywordRecommender.cs index 4826f6fe419f2..843a3dad47ace 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ExternKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ExternKeywordRecommender.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class ExternKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class ExternKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.ExternKeyword) { private static readonly ISet s_validModifiers = new HashSet(SyntaxFacts.EqualityComparer) { @@ -42,11 +42,6 @@ internal class ExternKeywordRecommender : AbstractSyntacticSingleKeywordRecommen SyntaxKind.UnsafeKeyword }; - public ExternKeywordRecommender() - : base(SyntaxKind.ExternKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var syntaxTree = context.SyntaxTree; @@ -56,7 +51,7 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context syntaxTree.IsGlobalMemberDeclarationContext(position, s_validGlobalModifiers, cancellationToken) || context.IsMemberDeclarationContext( validModifiers: s_validModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, canBePartial: false, cancellationToken: cancellationToken) || context.SyntaxTree.IsLocalFunctionDeclarationContext(position, s_validLocalFunctionModifiers, cancellationToken); diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FalseKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FalseKeywordRecommender.cs index d51e8b52d8879..6f0c1104bbefd 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FalseKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FalseKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class FalseKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class FalseKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.FalseKeyword, isValidInPreprocessorContext: true) { - public FalseKeywordRecommender() - : base(SyntaxKind.FalseKeyword, isValidInPreprocessorContext: true) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FileKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FileKeywordRecommender.cs index 73510f4b46dd1..826699f2aa505 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FileKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FileKeywordRecommender.cs @@ -11,17 +11,12 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class FileKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class FileKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.FileKeyword) { private static readonly ISet s_validModifiers = SyntaxKindSet.AllMemberModifiers .Where(s => s != SyntaxKind.FileKeyword && !SyntaxFacts.IsAccessibilityModifier(s)) .ToSet(); - public FileKeywordRecommender() - : base(SyntaxKind.FileKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return context.ContainingTypeDeclaration == null diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FinallyKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FinallyKeywordRecommender.cs index ab711d32b68ec..080bd52098674 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FinallyKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FinallyKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class FinallyKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class FinallyKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.FinallyKeyword) { - public FinallyKeywordRecommender() - : base(SyntaxKind.FinallyKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.SyntaxTree.IsCatchOrFinallyContext(position, context.LeftToken); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FixedKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FixedKeywordRecommender.cs index a7577b1acabfe..f360eab7ab89b 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FixedKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FixedKeywordRecommender.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class FixedKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class FixedKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.FixedKeyword) { private static readonly ISet s_validModifiers = new HashSet(SyntaxFacts.EqualityComparer) { @@ -21,11 +21,6 @@ internal class FixedKeywordRecommender : AbstractSyntacticSingleKeywordRecommend SyntaxKind.UnsafeKeyword, }; - public FixedKeywordRecommender() - : base(SyntaxKind.FixedKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => IsUnsafeStatementContext(context) || IsMemberDeclarationContext(context, cancellationToken); diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FloatKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FloatKeywordRecommender.cs index 5fd2119e67386..8a96db64e4bfa 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FloatKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FloatKeywordRecommender.cs @@ -11,13 +11,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class FloatKeywordRecommender : AbstractSpecialTypePreselectingKeywordRecommender +internal sealed class FloatKeywordRecommender() : AbstractSpecialTypePreselectingKeywordRecommender(SyntaxKind.FloatKeyword) { - public FloatKeywordRecommender() - : base(SyntaxKind.FloatKeyword) - { - } - protected override bool IsValidContextWorker(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var syntaxTree = context.SyntaxTree; @@ -46,8 +41,8 @@ protected override bool IsValidContextWorker(int position, CSharpSyntaxContext c context.IsPossibleTupleContext || context.IsMemberDeclarationContext( validModifiers: SyntaxKindSet.AllMemberModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, - canBePartial: false, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, + canBePartial: true, cancellationToken: cancellationToken); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ForEachKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ForEachKeywordRecommender.cs index a6205dc9fc236..6f79827f24500 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ForEachKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ForEachKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class ForEachKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class ForEachKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.ForEachKeyword) { - public ForEachKeywordRecommender() - : base(SyntaxKind.ForEachKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ForKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ForKeywordRecommender.cs index f9650905da950..4444c1465c0b0 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ForKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ForKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class ForKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class ForKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.ForKeyword) { - public ForKeywordRecommender() - : base(SyntaxKind.ForKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.IsStatementContext || context.IsGlobalStatementContext; } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FromKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FromKeywordRecommender.cs index 92e2383fa433a..c1f92982e8030 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FromKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FromKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class FromKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class FromKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.FromKeyword) { - public FromKeywordRecommender() - : base(SyntaxKind.FromKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var syntaxTree = context.SyntaxTree; diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/GetKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/GetKeywordRecommender.cs index 0167db80144ac..aa2cf1e444176 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/GetKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/GetKeywordRecommender.cs @@ -8,13 +8,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class GetKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class GetKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.GetKeyword) { - public GetKeywordRecommender() - : base(SyntaxKind.GetKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/GlobalKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/GlobalKeywordRecommender.cs index f2d7e65824754..6a29d5ba5d3a7 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/GlobalKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/GlobalKeywordRecommender.cs @@ -9,13 +9,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class GlobalKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class GlobalKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.GlobalKeyword) { - public GlobalKeywordRecommender() - : base(SyntaxKind.GlobalKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var syntaxTree = context.SyntaxTree; diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/GotoKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/GotoKeywordRecommender.cs index 9e606dbe09025..8c2792cccae3e 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/GotoKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/GotoKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class GotoKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class GotoKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.GotoKeyword) { - public GotoKeywordRecommender() - : base(SyntaxKind.GotoKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.IsStatementContext || context.IsGlobalStatementContext; } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/GroupKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/GroupKeywordRecommender.cs index 4980092241f3c..e8e6425185461 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/GroupKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/GroupKeywordRecommender.cs @@ -8,13 +8,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class GroupKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class GroupKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.GroupKeyword) { - public GroupKeywordRecommender() - : base(SyntaxKind.GroupKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var token = context.TargetToken; diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/HiddenKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/HiddenKeywordRecommender.cs index 022299a64f1f4..ea1ec031491f1 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/HiddenKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/HiddenKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class HiddenKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class HiddenKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.HiddenKeyword, isValidInPreprocessorContext: true) { - public HiddenKeywordRecommender() - : base(SyntaxKind.HiddenKeyword, isValidInPreprocessorContext: true) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { // cases: diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/IfKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/IfKeywordRecommender.cs index 1499e9b475ada..21e71459b9371 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/IfKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/IfKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class IfKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class IfKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.IfKeyword, isValidInPreprocessorContext: true) { - public IfKeywordRecommender() - : base(SyntaxKind.IfKeyword, isValidInPreprocessorContext: true) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ImplicitKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ImplicitKeywordRecommender.cs index 91665dc9014c9..d55f8a27a49fb 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ImplicitKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ImplicitKeywordRecommender.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class ImplicitKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class ImplicitKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.ImplicitKeyword) { private static readonly ISet s_validNonInterfaceMemberModifiers = new HashSet(SyntaxFacts.EqualityComparer) { @@ -27,11 +27,6 @@ internal class ImplicitKeywordRecommender : AbstractSyntacticSingleKeywordRecomm SyntaxKind.UnsafeKeyword, }; - public ImplicitKeywordRecommender() - : base(SyntaxKind.ImplicitKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { if (context.IsMemberDeclarationContext(validModifiers: s_validNonInterfaceMemberModifiers, validTypeDeclarations: SyntaxKindSet.ClassStructRecordTypeDeclarations, canBePartial: false, cancellationToken: cancellationToken)) diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/InKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/InKeywordRecommender.cs index 25ebc0dc3647e..fdfed14df36b1 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/InKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/InKeywordRecommender.cs @@ -10,13 +10,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class InKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class InKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.InKeyword) { - public InKeywordRecommender() - : base(SyntaxKind.InKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var syntaxTree = context.SyntaxTree; diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/InitKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/InitKeywordRecommender.cs index 3121422afe03f..afa0035f02b9f 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/InitKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/InitKeywordRecommender.cs @@ -8,13 +8,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class InitKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class InitKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.InitKeyword) { - public InitKeywordRecommender() - : base(SyntaxKind.InitKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/IntKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/IntKeywordRecommender.cs index 37f5011ee1f69..3ccaa9304d466 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/IntKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/IntKeywordRecommender.cs @@ -42,8 +42,8 @@ protected override bool IsValidContextWorker(int position, CSharpSyntaxContext c context.IsPossibleTupleContext || context.IsMemberDeclarationContext( validModifiers: SyntaxKindSet.AllMemberModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, - canBePartial: false, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, + canBePartial: true, cancellationToken: cancellationToken); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/InterfaceKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/InterfaceKeywordRecommender.cs index ccd6bab4d1484..b5c548d93f714 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/InterfaceKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/InterfaceKeywordRecommender.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class InterfaceKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class InterfaceKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.InterfaceKeyword) { private static readonly ISet s_validModifiers = new HashSet(SyntaxFacts.EqualityComparer) { @@ -20,18 +20,13 @@ internal class InterfaceKeywordRecommender : AbstractSyntacticSingleKeywordRecom SyntaxKind.UnsafeKeyword }; - public InterfaceKeywordRecommender() - : base(SyntaxKind.InterfaceKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return context.IsGlobalStatementContext || context.IsTypeDeclarationContext( validModifiers: s_validModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, canBePartial: true, cancellationToken: cancellationToken); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/InternalKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/InternalKeywordRecommender.cs index 6836a4e78275d..06a8b50c05b76 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/InternalKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/InternalKeywordRecommender.cs @@ -9,13 +9,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class InternalKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class InternalKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.InternalKeyword) { - public InternalKeywordRecommender() - : base(SyntaxKind.InternalKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return @@ -39,7 +34,7 @@ private static bool IsValidContextForAccessor(CSharpSyntaxContext context) private static bool IsValidContextForMember(CSharpSyntaxContext context, CancellationToken cancellationToken) { if (context.SyntaxTree.IsGlobalMemberDeclarationContext(context.Position, SyntaxKindSet.AllGlobalMemberModifiers, cancellationToken) || - context.IsMemberDeclarationContext(validModifiers: SyntaxKindSet.AllMemberModifiers, validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, canBePartial: false, cancellationToken: cancellationToken)) + context.IsMemberDeclarationContext(validModifiers: SyntaxKindSet.AllMemberModifiers, validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, canBePartial: false, cancellationToken: cancellationToken)) { return CheckPreviousAccessibilityModifiers(context); } @@ -49,7 +44,7 @@ private static bool IsValidContextForMember(CSharpSyntaxContext context, Cancell private static bool IsValidContextForType(CSharpSyntaxContext context, CancellationToken cancellationToken) { - if (context.IsTypeDeclarationContext(validModifiers: SyntaxKindSet.AllTypeModifiers, validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, canBePartial: false, cancellationToken: cancellationToken)) + if (context.IsTypeDeclarationContext(validModifiers: SyntaxKindSet.AllTypeModifiers, validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, canBePartial: false, cancellationToken: cancellationToken)) { return CheckPreviousAccessibilityModifiers(context); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/IntoKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/IntoKeywordRecommender.cs index 4f12793e4f4e6..86e5a72f815a4 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/IntoKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/IntoKeywordRecommender.cs @@ -10,13 +10,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class IntoKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class IntoKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.IntoKeyword) { - public IntoKeywordRecommender() - : base(SyntaxKind.IntoKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/IsKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/IsKeywordRecommender.cs index 4f7bcfc2072c5..b1602eda69473 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/IsKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/IsKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class IsKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class IsKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.IsKeyword) { - public IsKeywordRecommender() - : base(SyntaxKind.IsKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { // cases: diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/JoinKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/JoinKeywordRecommender.cs index 5b292040505d4..fac60b6838946 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/JoinKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/JoinKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class JoinKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class JoinKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.JoinKeyword) { - public JoinKeywordRecommender() - : base(SyntaxKind.JoinKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.SyntaxTree.IsValidContextForJoinClause(position, context.LeftToken); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/LetKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/LetKeywordRecommender.cs index 9880d572bc173..799bb5981d203 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/LetKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/LetKeywordRecommender.cs @@ -8,13 +8,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class LetKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class LetKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.LetKeyword) { - public LetKeywordRecommender() - : base(SyntaxKind.LetKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var token = context.TargetToken; diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/LineKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/LineKeywordRecommender.cs index 645eca23f69ce..6bbe5a76dcc6a 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/LineKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/LineKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class LineKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class LineKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.LineKeyword, isValidInPreprocessorContext: true) { - public LineKeywordRecommender() - : base(SyntaxKind.LineKeyword, isValidInPreprocessorContext: true) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.IsPreProcessorKeywordContext; } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/LoadKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/LoadKeywordRecommender.cs index 41f1a6bbcbb78..789d3316b4968 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/LoadKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/LoadKeywordRecommender.cs @@ -8,13 +8,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class LoadKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class LoadKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.LoadKeyword, isValidInPreprocessorContext: true) { - public LoadKeywordRecommender() - : base(SyntaxKind.LoadKeyword, isValidInPreprocessorContext: true) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var syntaxTree = context.SyntaxTree; diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/LockKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/LockKeywordRecommender.cs index 687866b7874af..a0ffa8605ebd2 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/LockKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/LockKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class LockKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class LockKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.LockKeyword) { - public LockKeywordRecommender() - : base(SyntaxKind.LockKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.IsStatementContext || context.IsGlobalStatementContext; } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/LongKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/LongKeywordRecommender.cs index 54cc4818a037d..c40b72585e082 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/LongKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/LongKeywordRecommender.cs @@ -11,13 +11,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class LongKeywordRecommender : AbstractSpecialTypePreselectingKeywordRecommender +internal sealed class LongKeywordRecommender() : AbstractSpecialTypePreselectingKeywordRecommender(SyntaxKind.LongKeyword) { - public LongKeywordRecommender() - : base(SyntaxKind.LongKeyword) - { - } - protected override bool IsValidContextWorker(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var syntaxTree = context.SyntaxTree; @@ -47,8 +42,8 @@ protected override bool IsValidContextWorker(int position, CSharpSyntaxContext c context.IsPossibleTupleContext || context.IsMemberDeclarationContext( validModifiers: SyntaxKindSet.AllMemberModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, - canBePartial: false, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, + canBePartial: true, cancellationToken: cancellationToken); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ManagedKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ManagedKeywordRecommender.cs index 843244716dd46..7b8323f12f409 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ManagedKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ManagedKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class ManagedKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class ManagedKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.ManagedKeyword) { - public ManagedKeywordRecommender() - : base(SyntaxKind.ManagedKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.SyntaxTree.IsFunctionPointerCallingConventionContext(context.TargetToken); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/MethodKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/MethodKeywordRecommender.cs index 87ff3b4947bae..9ff6e77a30883 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/MethodKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/MethodKeywordRecommender.cs @@ -14,7 +14,7 @@ internal sealed class MethodKeywordRecommender() : AbstractSyntacticSingleKeywor { protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { - if (context.IsMemberAttributeContext(SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, includingRecordParameters: false, cancellationToken)) + if (context.IsMemberAttributeContext(SyntaxKindSet.NonEnumTypeDeclarations, includingRecordParameters: false, cancellationToken)) return true; var token = context.TargetToken; diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ModuleKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ModuleKeywordRecommender.cs index a1d40d6d268a4..8bab53fe1f5ca 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ModuleKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ModuleKeywordRecommender.cs @@ -10,13 +10,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class ModuleKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class ModuleKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.ModuleKeyword) { - public ModuleKeywordRecommender() - : base(SyntaxKind.ModuleKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { if (context.IsTypeAttributeContext(cancellationToken)) diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NameOfKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NameOfKeywordRecommender.cs index 3046b484e68cc..8e52b33a7467b 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NameOfKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NameOfKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class NameOfKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class NameOfKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.NameOfKeyword) { - public NameOfKeywordRecommender() - : base(SyntaxKind.NameOfKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NamespaceKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NamespaceKeywordRecommender.cs index 4708ade62a49d..7a5b8c98e9d70 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NamespaceKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NamespaceKeywordRecommender.cs @@ -10,13 +10,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class NamespaceKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class NamespaceKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.NamespaceKeyword) { - public NamespaceKeywordRecommender() - : base(SyntaxKind.NamespaceKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var syntaxTree = context.SyntaxTree; diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NewKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NewKeywordRecommender.cs index a8ba3376974ca..a9fe82cee4220 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NewKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NewKeywordRecommender.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class NewKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class NewKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.NewKeyword) { private static readonly ISet s_validMemberModifiers = new HashSet(SyntaxFacts.EqualityComparer) { @@ -30,7 +30,7 @@ internal class NewKeywordRecommender : AbstractSyntacticSingleKeywordRecommender SyntaxKind.VolatileKeyword, }; - protected static readonly ISet ValidTypeModifiers = new HashSet(SyntaxFacts.EqualityComparer) + private static readonly ISet ValidTypeModifiers = new HashSet(SyntaxFacts.EqualityComparer) { SyntaxKind.AbstractKeyword, SyntaxKind.InternalKeyword, @@ -42,11 +42,6 @@ internal class NewKeywordRecommender : AbstractSyntacticSingleKeywordRecommender SyntaxKind.UnsafeKeyword }; - public NewKeywordRecommender() - : base(SyntaxKind.NewKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NotKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NotKeywordRecommender.cs index 580ac26655f37..047de30f2a829 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NotKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NotKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class NotKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class NotKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.NotKeyword) { - public NotKeywordRecommender() - : base(SyntaxKind.NotKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.IsAtStartOfPattern; } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NotnullKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NotnullKeywordRecommender.cs index 16d25b78936d1..996ee34cf0871 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NotnullKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NotnullKeywordRecommender.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class NotNullKeywordRecommender : IKeywordRecommender +internal sealed class NotNullKeywordRecommender : IKeywordRecommender { public ImmutableArray RecommendKeywords(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NullKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NullKeywordRecommender.cs index bc4d1b532abfb..201df1ecf8f59 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NullKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NullKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class NullKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class NullKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.NullKeyword) { - public NullKeywordRecommender() - : base(SyntaxKind.NullKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.IsAnyExpressionContext || context.IsStatementContext || diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NullableKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NullableKeywordRecommender.cs index de2074a42b9d3..ee8b1f254697a 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NullableKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NullableKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class NullableKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class NullableKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.NullableKeyword, isValidInPreprocessorContext: true) { - public NullableKeywordRecommender() - : base(SyntaxKind.NullableKeyword, isValidInPreprocessorContext: true) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.IsPreProcessorKeywordContext; } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ObjectKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ObjectKeywordRecommender.cs index 88e691ef9650b..51eb6ea8b527d 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ObjectKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ObjectKeywordRecommender.cs @@ -11,13 +11,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class ObjectKeywordRecommender : AbstractSpecialTypePreselectingKeywordRecommender +internal sealed class ObjectKeywordRecommender() : AbstractSpecialTypePreselectingKeywordRecommender(SyntaxKind.ObjectKeyword) { - public ObjectKeywordRecommender() - : base(SyntaxKind.ObjectKeyword) - { - } - protected override bool IsValidContextWorker(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var syntaxTree = context.SyntaxTree; @@ -45,8 +40,8 @@ protected override bool IsValidContextWorker(int position, CSharpSyntaxContext c context.IsPossibleTupleContext || context.IsMemberDeclarationContext( validModifiers: SyntaxKindSet.AllMemberModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, - canBePartial: false, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, + canBePartial: true, cancellationToken: cancellationToken); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OnKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OnKeywordRecommender.cs index 3a837c275a228..df24c6cc1b69f 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OnKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OnKeywordRecommender.cs @@ -9,13 +9,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class OnKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class OnKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.OnKeyword) { - public OnKeywordRecommender() - : base(SyntaxKind.OnKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { // cases: diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OperatorKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OperatorKeywordRecommender.cs index d84e2761e63d2..72dcfa0391a60 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OperatorKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OperatorKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class OperatorKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class OperatorKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.OperatorKeyword) { - public OperatorKeywordRecommender() - : base(SyntaxKind.OperatorKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { // cases: @@ -22,7 +17,6 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context var token = context.TargetToken; return - token.Kind() is SyntaxKind.ImplicitKeyword or - SyntaxKind.ExplicitKeyword; + token.Kind() is SyntaxKind.ImplicitKeyword or SyntaxKind.ExplicitKeyword; } } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OrKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OrKeywordRecommender.cs index 325167c1cb05b..026f7552bd6a0 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OrKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OrKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class OrKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class OrKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.OrKeyword) { - public OrKeywordRecommender() - : base(SyntaxKind.OrKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.IsAtEndOfPattern; } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OrderByKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OrderByKeywordRecommender.cs index dbd6cd10a614e..b56b9616675b4 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OrderByKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OrderByKeywordRecommender.cs @@ -8,13 +8,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class OrderByKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class OrderByKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.OrderByKeyword) { - public OrderByKeywordRecommender() - : base(SyntaxKind.OrderByKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var token = context.TargetToken; diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OutKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OutKeywordRecommender.cs index 1197922281e17..3185ca210629a 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OutKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OutKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class OutKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class OutKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.OutKeyword) { - public OutKeywordRecommender() - : base(SyntaxKind.OutKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var syntaxTree = context.SyntaxTree; diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OverrideKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OverrideKeywordRecommender.cs index 754299cd041cb..50c90bd7ec639 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OverrideKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OverrideKeywordRecommender.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class OverrideKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class OverrideKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.OverrideKeyword) { private static readonly ISet s_validMemberModifiers = new HashSet(SyntaxFacts.EqualityComparer) { @@ -23,11 +23,6 @@ internal class OverrideKeywordRecommender : AbstractSyntacticSingleKeywordRecomm SyntaxKind.AbstractKeyword, }; - public OverrideKeywordRecommender() - : base(SyntaxKind.OverrideKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { if (!context.IsMemberDeclarationContext( diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ParamsKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ParamsKeywordRecommender.cs index 51bca79b76354..309050b9264b9 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ParamsKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ParamsKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class ParamsKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class ParamsKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.ParamsKeyword) { - public ParamsKeywordRecommender() - : base(SyntaxKind.ParamsKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.SyntaxTree.IsParamsModifierContext(position, context.LeftToken, cancellationToken); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/PartialKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/PartialKeywordRecommender.cs index 6a708de5cc59c..cf5fdf9fdd792 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/PartialKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/PartialKeywordRecommender.cs @@ -12,13 +12,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class PartialKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class PartialKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.PartialKeyword) { - public PartialKeywordRecommender() - : base(SyntaxKind.PartialKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/PragmaKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/PragmaKeywordRecommender.cs index 343e7a168d418..14753537a9009 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/PragmaKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/PragmaKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class PragmaKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class PragmaKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.PragmaKeyword, isValidInPreprocessorContext: true) { - public PragmaKeywordRecommender() - : base(SyntaxKind.PragmaKeyword, isValidInPreprocessorContext: true) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.IsPreProcessorKeywordContext; } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/PrivateKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/PrivateKeywordRecommender.cs index dd696e8abad99..b7bd818b93cbf 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/PrivateKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/PrivateKeywordRecommender.cs @@ -10,13 +10,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class PrivateKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class PrivateKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.PrivateKeyword) { - public PrivateKeywordRecommender() - : base(SyntaxKind.PrivateKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return @@ -40,7 +35,7 @@ private static bool IsValidContextForAccessor(CSharpSyntaxContext context) private static bool IsValidContextForMember(CSharpSyntaxContext context, CancellationToken cancellationToken) { if (context.SyntaxTree.IsGlobalMemberDeclarationContext(context.Position, SyntaxKindSet.AllGlobalMemberModifiers, cancellationToken) || - context.IsMemberDeclarationContext(validModifiers: SyntaxKindSet.AllMemberModifiers, validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, canBePartial: false, cancellationToken: cancellationToken)) + context.IsMemberDeclarationContext(validModifiers: SyntaxKindSet.AllMemberModifiers, validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, canBePartial: false, cancellationToken: cancellationToken)) { var modifiers = context.PrecedingModifiers; @@ -61,7 +56,7 @@ private static bool IsValidContextForMember(CSharpSyntaxContext context, Cancell private static bool IsValidContextForType(CSharpSyntaxContext context, CancellationToken cancellationToken) { - if (context.IsTypeDeclarationContext(validModifiers: SyntaxKindSet.AllTypeModifiers, validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, canBePartial: false, cancellationToken: cancellationToken)) + if (context.IsTypeDeclarationContext(validModifiers: SyntaxKindSet.AllTypeModifiers, validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, canBePartial: false, cancellationToken: cancellationToken)) { // private things can't be in namespaces. var typeDecl = context.ContainingTypeDeclaration; diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/PropertyKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/PropertyKeywordRecommender.cs index c7cb0e76054d4..494c9200c2e60 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/PropertyKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/PropertyKeywordRecommender.cs @@ -11,5 +11,5 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; internal sealed class PropertyKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.PropertyKeyword) { protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) - => context.IsMemberAttributeContext(SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, includingRecordParameters: true, cancellationToken); + => context.IsMemberAttributeContext(SyntaxKindSet.NonEnumTypeDeclarations, includingRecordParameters: true, cancellationToken); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ProtectedKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ProtectedKeywordRecommender.cs index 5241f912c44a8..8bbf2040af5d3 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ProtectedKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ProtectedKeywordRecommender.cs @@ -9,13 +9,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class ProtectedKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class ProtectedKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.ProtectedKeyword) { - public ProtectedKeywordRecommender() - : base(SyntaxKind.ProtectedKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/PublicKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/PublicKeywordRecommender.cs index 095a3289e7738..f8fa603c7c6a3 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/PublicKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/PublicKeywordRecommender.cs @@ -8,13 +8,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class PublicKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class PublicKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.PublicKeyword) { - public PublicKeywordRecommender() - : base(SyntaxKind.PublicKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return @@ -28,7 +23,7 @@ private static bool IsValidContextForMember(CSharpSyntaxContext context, Cancell if (context.SyntaxTree.IsGlobalMemberDeclarationContext(context.Position, SyntaxKindSet.AllGlobalMemberModifiers, cancellationToken) || context.IsMemberDeclarationContext( validModifiers: SyntaxKindSet.AllMemberModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, canBePartial: false, cancellationToken: cancellationToken)) { @@ -40,7 +35,7 @@ private static bool IsValidContextForMember(CSharpSyntaxContext context, Cancell private static bool IsValidContextForType(CSharpSyntaxContext context, CancellationToken cancellationToken) { - if (context.IsTypeDeclarationContext(validModifiers: SyntaxKindSet.AllTypeModifiers, validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, canBePartial: false, cancellationToken: cancellationToken)) + if (context.IsTypeDeclarationContext(validModifiers: SyntaxKindSet.AllTypeModifiers, validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, canBePartial: false, cancellationToken: cancellationToken)) { return CheckPreviousAccessibilityModifiers(context); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ReadOnlyKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ReadOnlyKeywordRecommender.cs index 074bcc4111aac..b6790f0fb13c3 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ReadOnlyKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ReadOnlyKeywordRecommender.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class ReadOnlyKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class ReadOnlyKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.ReadOnlyKeyword) { private static readonly ISet s_validMemberModifiers = new HashSet(SyntaxFacts.EqualityComparer) { @@ -23,11 +23,6 @@ internal class ReadOnlyKeywordRecommender : AbstractSyntacticSingleKeywordRecomm SyntaxKind.StaticKeyword, }; - public ReadOnlyKeywordRecommender() - : base(SyntaxKind.ReadOnlyKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RecordKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RecordKeywordRecommender.cs index e714ba81a1001..f3b6cb1d37916 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RecordKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RecordKeywordRecommender.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class RecordKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class RecordKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.RecordKeyword) { private static readonly ISet s_validModifiers = new HashSet(SyntaxFacts.EqualityComparer) { @@ -26,18 +26,13 @@ internal class RecordKeywordRecommender : AbstractSyntacticSingleKeywordRecommen SyntaxKind.FileKeyword, }; - public RecordKeywordRecommender() - : base(SyntaxKind.RecordKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return context.IsGlobalStatementContext || context.IsTypeDeclarationContext( validModifiers: s_validModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, canBePartial: true, cancellationToken: cancellationToken); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RefKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RefKeywordRecommender.cs index 73c48681ebb1d..4c938e9c00599 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RefKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RefKeywordRecommender.cs @@ -12,13 +12,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class RefKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class RefKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.RefKeyword) { - public RefKeywordRecommender() - : base(SyntaxKind.RefKeyword) - { - } - /// /// Same as with ref specific exclusions /// @@ -147,7 +142,7 @@ private static bool IsValidNewByRefContext(SyntaxTree syntaxTree, int position, syntaxTree.IsGlobalMemberDeclarationContext(position, syntaxTree.IsScript() ? RefGlobalMemberScriptModifiers : RefGlobalMemberModifiers, cancellationToken) || context.IsMemberDeclarationContext( validModifiers: RefMemberModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, canBePartial: true, cancellationToken: cancellationToken); } @@ -222,6 +217,6 @@ private static bool IsValidRefExpressionContext(CSharpSyntaxContext context) private static bool IsValidContextForType(CSharpSyntaxContext context, CancellationToken cancellationToken) { return context.IsTypeDeclarationContext(validModifiers: SyntaxKindSet.AllTypeModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, canBePartial: true, cancellationToken); + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, canBePartial: true, cancellationToken); } } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ReferenceKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ReferenceKeywordRecommender.cs index 08ee7bb6211c7..7fef0850b6520 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ReferenceKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ReferenceKeywordRecommender.cs @@ -8,13 +8,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class ReferenceKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class ReferenceKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.ReferenceKeyword, isValidInPreprocessorContext: true) { - public ReferenceKeywordRecommender() - : base(SyntaxKind.ReferenceKeyword, isValidInPreprocessorContext: true) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var syntaxTree = context.SyntaxTree; diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RegionKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RegionKeywordRecommender.cs index 82456ae718e0a..2c95fa7443db3 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RegionKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RegionKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class RegionKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class RegionKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.RegionKeyword, isValidInPreprocessorContext: true, shouldFormatOnCommit: true) { - public RegionKeywordRecommender() - : base(SyntaxKind.RegionKeyword, isValidInPreprocessorContext: true, shouldFormatOnCommit: true) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.IsPreProcessorKeywordContext; } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RemoveKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RemoveKeywordRecommender.cs index 05fad0d3880bd..769711c3b6c83 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RemoveKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RemoveKeywordRecommender.cs @@ -8,13 +8,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class RemoveKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class RemoveKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.RemoveKeyword) { - public RemoveKeywordRecommender() - : base(SyntaxKind.RemoveKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.TargetToken.IsAccessorDeclarationContext(position, SyntaxKind.RemoveKeyword); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RequiredKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RequiredKeywordRecommender.cs index e6e4ac276dc54..69302638b1dea 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RequiredKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RequiredKeywordRecommender.cs @@ -11,17 +11,12 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class RequiredKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class RequiredKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.RequiredKeyword) { private static readonly ISet s_validModifiers = SyntaxKindSet.AllMemberModifiers.Where(s => s is not (SyntaxKind.RequiredKeyword or SyntaxKind.StaticKeyword or SyntaxKind.ReadOnlyKeyword or SyntaxKind.ConstKeyword)).ToSet(); private static readonly ISet s_validTypeDeclarations = SyntaxKindSet.ClassStructRecordTypeDeclarations; - public RequiredKeywordRecommender() - : base(SyntaxKind.RequiredKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return context.IsMemberDeclarationContext(s_validModifiers, s_validTypeDeclarations, canBePartial: true, cancellationToken); diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RestoreKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RestoreKeywordRecommender.cs index d061038fa0b36..c34a11a74d73d 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RestoreKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RestoreKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class RestoreKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class RestoreKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.RestoreKeyword, isValidInPreprocessorContext: true) { - public RestoreKeywordRecommender() - : base(SyntaxKind.RestoreKeyword, isValidInPreprocessorContext: true) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var previousToken1 = context.TargetToken; diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ReturnKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ReturnKeywordRecommender.cs index 73026436d41e1..ede56a855f395 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ReturnKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ReturnKeywordRecommender.cs @@ -10,13 +10,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class ReturnKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class ReturnKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.ReturnKeyword) { - public ReturnKeywordRecommender() - : base(SyntaxKind.ReturnKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return @@ -29,7 +24,7 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context private static bool IsAttributeContext(CSharpSyntaxContext context, CancellationToken cancellationToken) { return - context.IsMemberAttributeContext(SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, includingRecordParameters: false, cancellationToken) || + context.IsMemberAttributeContext(SyntaxKindSet.NonEnumTypeDeclarations, includingRecordParameters: false, cancellationToken) || (context.SyntaxTree.IsScript() && context.IsTypeAttributeContext(cancellationToken)) || context.IsStatementAttributeContext() || IsAccessorAttributeContext(); diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SByteKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SByteKeywordRecommender.cs index 8ed9464600648..d72299b6e81c8 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SByteKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SByteKeywordRecommender.cs @@ -11,13 +11,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class SByteKeywordRecommender : AbstractSpecialTypePreselectingKeywordRecommender +internal sealed class SByteKeywordRecommender() : AbstractSpecialTypePreselectingKeywordRecommender(SyntaxKind.SByteKeyword) { - public SByteKeywordRecommender() - : base(SyntaxKind.SByteKeyword) - { - } - protected override bool IsValidContextWorker(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var syntaxTree = context.SyntaxTree; @@ -47,8 +42,8 @@ protected override bool IsValidContextWorker(int position, CSharpSyntaxContext c context.IsPossibleTupleContext || context.IsMemberDeclarationContext( validModifiers: SyntaxKindSet.AllMemberModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, - canBePartial: false, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, + canBePartial: true, cancellationToken: cancellationToken); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SealedKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SealedKeywordRecommender.cs index 47ea6d582d493..06f7427bd5e6a 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SealedKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SealedKeywordRecommender.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class SealedKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class SealedKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.SealedKeyword) { private static readonly ISet s_validNonInterfaceMemberModifiers = new HashSet(SyntaxFacts.EqualityComparer) { @@ -45,11 +45,6 @@ internal class SealedKeywordRecommender : AbstractSyntacticSingleKeywordRecommen SyntaxKind.FileKeyword, }; - public SealedKeywordRecommender() - : base(SyntaxKind.SealedKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SelectKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SelectKeywordRecommender.cs index 628dc12cd2a45..2cc550777ef3f 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SelectKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SelectKeywordRecommender.cs @@ -8,13 +8,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class SelectKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class SelectKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.SelectKeyword) { - public SelectKeywordRecommender() - : base(SyntaxKind.SelectKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var token = context.TargetToken; diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SetKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SetKeywordRecommender.cs index b814c8efe45b6..aafb4473eaaf0 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SetKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SetKeywordRecommender.cs @@ -8,13 +8,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class SetKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class SetKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.SetKeyword) { - public SetKeywordRecommender() - : base(SyntaxKind.SetKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ShortKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ShortKeywordRecommender.cs index ec64422318929..5b292a35e1635 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ShortKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ShortKeywordRecommender.cs @@ -11,13 +11,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class ShortKeywordRecommender : AbstractSpecialTypePreselectingKeywordRecommender +internal sealed class ShortKeywordRecommender() : AbstractSpecialTypePreselectingKeywordRecommender(SyntaxKind.ShortKeyword) { - public ShortKeywordRecommender() - : base(SyntaxKind.ShortKeyword) - { - } - protected override bool IsValidContextWorker(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var syntaxTree = context.SyntaxTree; @@ -47,8 +42,8 @@ protected override bool IsValidContextWorker(int position, CSharpSyntaxContext c context.IsPossibleTupleContext || context.IsMemberDeclarationContext( validModifiers: SyntaxKindSet.AllMemberModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, - canBePartial: false, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, + canBePartial: true, cancellationToken: cancellationToken); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SizeOfKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SizeOfKeywordRecommender.cs index 8118f88558edf..ab07ec1d945e0 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SizeOfKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SizeOfKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class SizeOfKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class SizeOfKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.SizeOfKeyword) { - public SizeOfKeywordRecommender() - : base(SyntaxKind.SizeOfKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/StackAllocKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/StackAllocKeywordRecommender.cs index 79e12b7bc40c7..32969cbf57c5b 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/StackAllocKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/StackAllocKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class StackAllocKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class StackAllocKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.StackAllocKeyword) { - public StackAllocKeywordRecommender() - : base(SyntaxKind.StackAllocKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { // Beginning with C# 8.0, stackalloc expression can be used inside other expressions diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/StaticKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/StaticKeywordRecommender.cs index 6ecd476970359..62694d71ce8c2 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/StaticKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/StaticKeywordRecommender.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class StaticKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class StaticKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.StaticKeyword) { private static readonly ISet s_validTypeModifiers = new HashSet(SyntaxFacts.EqualityComparer) { @@ -73,11 +73,6 @@ internal class StaticKeywordRecommender : AbstractSyntacticSingleKeywordRecommen SyntaxKind.UnsafeKeyword }; - public StaticKeywordRecommender() - : base(SyntaxKind.StaticKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return @@ -110,7 +105,7 @@ private static bool IsValidContextForType(CSharpSyntaxContext context, Cancellat { return context.IsTypeDeclarationContext( validModifiers: s_validTypeModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, canBePartial: false, cancellationToken: cancellationToken); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/StringKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/StringKeywordRecommender.cs index c249f8a4e6774..551d43ddc299a 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/StringKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/StringKeywordRecommender.cs @@ -11,13 +11,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal sealed class StringKeywordRecommender : AbstractSpecialTypePreselectingKeywordRecommender +internal sealed class StringKeywordRecommender() : AbstractSpecialTypePreselectingKeywordRecommender(SyntaxKind.StringKeyword) { - public StringKeywordRecommender() - : base(SyntaxKind.StringKeyword) - { - } - protected override SpecialType SpecialType => SpecialType.System_String; protected override bool IsValidContextWorker(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) @@ -47,8 +42,8 @@ protected override bool IsValidContextWorker(int position, CSharpSyntaxContext c context.IsPossibleTupleContext || context.IsMemberDeclarationContext( validModifiers: SyntaxKindSet.AllMemberModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, - canBePartial: false, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, + canBePartial: true, cancellationToken); } } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/StructKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/StructKeywordRecommender.cs index 65e0c9813d0eb..20e7d957579a7 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/StructKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/StructKeywordRecommender.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class StructKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class StructKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.StructKeyword) { private static readonly ISet s_validModifiers = new HashSet(SyntaxFacts.EqualityComparer) { @@ -24,18 +24,13 @@ internal class StructKeywordRecommender : AbstractSyntacticSingleKeywordRecommen SyntaxKind.FileKeyword, }; - public StructKeywordRecommender() - : base(SyntaxKind.StructKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return context.IsGlobalStatementContext || context.IsTypeDeclarationContext( validModifiers: s_validModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, canBePartial: true, cancellationToken: cancellationToken) || context.IsRecordDeclarationContext(s_validModifiers, cancellationToken) || diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SwitchKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SwitchKeywordRecommender.cs index 37dd1c2392afd..5ef72fc3605fe 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SwitchKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SwitchKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class SwitchKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class SwitchKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.SwitchKeyword) { - public SwitchKeywordRecommender() - : base(SyntaxKind.SwitchKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ThisKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ThisKeywordRecommender.cs index a6265c5f1f67e..771d543c67d29 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ThisKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ThisKeywordRecommender.cs @@ -10,13 +10,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class ThisKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class ThisKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.ThisKeyword) { - public ThisKeywordRecommender() - : base(SyntaxKind.ThisKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ThrowKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ThrowKeywordRecommender.cs index 9b5c3719e4a22..7731e70dbaf12 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ThrowKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ThrowKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class ThrowKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class ThrowKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.ThrowKeyword) { - public ThrowKeywordRecommender() - : base(SyntaxKind.ThrowKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { if (context.IsStatementContext || context.IsGlobalStatementContext) diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/TrueKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/TrueKeywordRecommender.cs index e54d946462601..fe2f15f668fcc 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/TrueKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/TrueKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class TrueKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class TrueKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.TrueKeyword, isValidInPreprocessorContext: true) { - public TrueKeywordRecommender() - : base(SyntaxKind.TrueKeyword, isValidInPreprocessorContext: true) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/TryKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/TryKeywordRecommender.cs index 61d43d87fb380..fd68d1c27327a 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/TryKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/TryKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class TryKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class TryKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.TryKeyword) { - public TryKeywordRecommender() - : base(SyntaxKind.TryKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.IsStatementContext || context.IsGlobalStatementContext; } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/TypeKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/TypeKeywordRecommender.cs index cbd7efb89671e..20568c3c43e18 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/TypeKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/TypeKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class TypeKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class TypeKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.TypeKeyword) { - public TypeKeywordRecommender() - : base(SyntaxKind.TypeKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.IsTypeAttributeContext(cancellationToken); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/TypeOfKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/TypeOfKeywordRecommender.cs index 84418bc497561..201a37d676ac0 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/TypeOfKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/TypeOfKeywordRecommender.cs @@ -9,13 +9,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class TypeOfKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class TypeOfKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.TypeOfKeyword) { - public TypeOfKeywordRecommender() - : base(SyntaxKind.TypeOfKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/TypeVarKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/TypeVarKeywordRecommender.cs index 50bbe50118d7c..573bbf764bb00 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/TypeVarKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/TypeVarKeywordRecommender.cs @@ -9,13 +9,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class TypeVarKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class TypeVarKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.TypeVarKeyword) { - public TypeVarKeywordRecommender() - : base(SyntaxKind.TypeVarKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var token = context.TargetToken; diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UIntKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UIntKeywordRecommender.cs index 4a65540388bfe..cbf50b8d07b38 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UIntKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UIntKeywordRecommender.cs @@ -11,13 +11,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class UIntKeywordRecommender : AbstractSpecialTypePreselectingKeywordRecommender +internal sealed class UIntKeywordRecommender() : AbstractSpecialTypePreselectingKeywordRecommender(SyntaxKind.UIntKeyword) { - public UIntKeywordRecommender() - : base(SyntaxKind.UIntKeyword) - { - } - protected override bool IsValidContextWorker(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var syntaxTree = context.SyntaxTree; @@ -47,8 +42,8 @@ protected override bool IsValidContextWorker(int position, CSharpSyntaxContext c context.IsPossibleTupleContext || context.IsMemberDeclarationContext( validModifiers: SyntaxKindSet.AllMemberModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, - canBePartial: false, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, + canBePartial: true, cancellationToken: cancellationToken); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ULongKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ULongKeywordRecommender.cs index 11b33880b5da6..9b49d37b359a5 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ULongKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ULongKeywordRecommender.cs @@ -11,13 +11,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class ULongKeywordRecommender : AbstractSpecialTypePreselectingKeywordRecommender +internal sealed class ULongKeywordRecommender() : AbstractSpecialTypePreselectingKeywordRecommender(SyntaxKind.ULongKeyword) { - public ULongKeywordRecommender() - : base(SyntaxKind.ULongKeyword) - { - } - protected override bool IsValidContextWorker(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var syntaxTree = context.SyntaxTree; @@ -47,8 +42,8 @@ protected override bool IsValidContextWorker(int position, CSharpSyntaxContext c context.IsPossibleTupleContext || context.IsMemberDeclarationContext( validModifiers: SyntaxKindSet.AllMemberModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, - canBePartial: false, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, + canBePartial: true, cancellationToken: cancellationToken); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UShortKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UShortKeywordRecommender.cs index d97ca289b7d34..0a03737b12dbe 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UShortKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UShortKeywordRecommender.cs @@ -12,13 +12,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class UShortKeywordRecommender : AbstractSpecialTypePreselectingKeywordRecommender +internal sealed class UShortKeywordRecommender() : AbstractSpecialTypePreselectingKeywordRecommender(SyntaxKind.UShortKeyword) { - public UShortKeywordRecommender() - : base(SyntaxKind.UShortKeyword) - { - } - /// /// We set the of this item less than the default value so that /// completion selects the keyword over it as the user starts typing. @@ -54,8 +49,8 @@ protected override bool IsValidContextWorker(int position, CSharpSyntaxContext c context.IsPossibleTupleContext || context.IsMemberDeclarationContext( validModifiers: SyntaxKindSet.AllMemberModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, - canBePartial: false, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, + canBePartial: true, cancellationToken: cancellationToken); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UncheckedKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UncheckedKeywordRecommender.cs index 9edcd2becf758..e191af2005769 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UncheckedKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UncheckedKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class UncheckedKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class UncheckedKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.UncheckedKeyword) { - public UncheckedKeywordRecommender() - : base(SyntaxKind.UncheckedKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UndefKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UndefKeywordRecommender.cs index 18aacb19c9812..821960d7e7328 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UndefKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UndefKeywordRecommender.cs @@ -8,13 +8,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class UndefKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class UndefKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.UndefKeyword, isValidInPreprocessorContext: true) { - public UndefKeywordRecommender() - : base(SyntaxKind.UndefKeyword, isValidInPreprocessorContext: true) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var syntaxTree = context.SyntaxTree; diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UnmanagedKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UnmanagedKeywordRecommender.cs index a1745d7c8f2e8..58a6e822f7732 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UnmanagedKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UnmanagedKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class UnmanagedKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class UnmanagedKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.UnmanagedKeyword) { - public UnmanagedKeywordRecommender() - : base(SyntaxKind.UnmanagedKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return context.SyntaxTree.IsTypeParameterConstraintContext(position, context.LeftToken) || diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UnsafeKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UnsafeKeywordRecommender.cs index df0bb5739fa09..9dea889f75b93 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UnsafeKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UnsafeKeywordRecommender.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class UnsafeKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class UnsafeKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.UnsafeKeyword) { private static readonly ISet s_validTypeModifiers = new HashSet(SyntaxFacts.EqualityComparer) { @@ -60,22 +60,17 @@ internal class UnsafeKeywordRecommender : AbstractSyntacticSingleKeywordRecommen SyntaxKind.AsyncKeyword }; - public UnsafeKeywordRecommender() - : base(SyntaxKind.UnsafeKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var syntaxTree = context.SyntaxTree; return context.IsStatementContext || context.IsGlobalStatementContext || - context.IsTypeDeclarationContext(validModifiers: s_validTypeModifiers, validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, canBePartial: false, cancellationToken: cancellationToken) || + context.IsTypeDeclarationContext(validModifiers: s_validTypeModifiers, validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, canBePartial: false, cancellationToken: cancellationToken) || syntaxTree.IsGlobalMemberDeclarationContext(position, s_validGlobalMemberModifiers, cancellationToken) || context.IsMemberDeclarationContext( validModifiers: s_validMemberModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, canBePartial: false, cancellationToken: cancellationToken) || syntaxTree.IsLocalFunctionDeclarationContext(position, s_validLocalFunctionModifiers, cancellationToken) || diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UsingKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UsingKeywordRecommender.cs index 4cdafe0a3aa7b..e3918c2f73bb5 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UsingKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UsingKeywordRecommender.cs @@ -9,13 +9,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class UsingKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class UsingKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.UsingKeyword) { - public UsingKeywordRecommender() - : base(SyntaxKind.UsingKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { // cases: diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VarKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VarKeywordRecommender.cs index 1fb8f1fc15076..23e82d602dddd 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VarKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VarKeywordRecommender.cs @@ -9,12 +9,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class VarKeywordRecommender : IKeywordRecommender +internal sealed class VarKeywordRecommender : IKeywordRecommender { - public VarKeywordRecommender() - { - } - private static bool IsValidContext(CSharpSyntaxContext context) { if (context.IsStatementContext || diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VirtualKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VirtualKeywordRecommender.cs index 10ffd1b011c64..60877128448d8 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VirtualKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VirtualKeywordRecommender.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class VirtualKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class VirtualKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.VirtualKeyword) { private static readonly ISet s_validNonInterfaceMemberModifiers = new HashSet(SyntaxFacts.EqualityComparer) { @@ -34,11 +34,6 @@ internal class VirtualKeywordRecommender : AbstractSyntacticSingleKeywordRecomme SyntaxKind.UnsafeKeyword, }; - public VirtualKeywordRecommender() - : base(SyntaxKind.VirtualKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { if (!context.IsMemberDeclarationContext( diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VoidKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VoidKeywordRecommender.cs index 199bf26b52b66..836b2a2a33a13 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VoidKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VoidKeywordRecommender.cs @@ -110,6 +110,6 @@ private static bool IsUnsafeUsingDirectiveContext(CSharpSyntaxContext context) private static bool IsMemberReturnTypeContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.SyntaxTree.IsGlobalMemberDeclarationContext(position, SyntaxKindSet.AllGlobalMemberModifiers, cancellationToken) || - context.IsMemberDeclarationContext(validModifiers: s_validClassInterfaceRecordModifiers, validTypeDeclarations: SyntaxKindSet.ClassInterfaceRecordTypeDeclarations, canBePartial: true, cancellationToken) || + context.IsMemberDeclarationContext(validModifiers: s_validClassInterfaceRecordModifiers, validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, canBePartial: true, cancellationToken) || context.IsMemberDeclarationContext(validModifiers: s_validStructModifiers, validTypeDeclarations: SyntaxKindSet.StructOnlyTypeDeclarations, canBePartial: false, cancellationToken); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VolatileKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VolatileKeywordRecommender.cs index 8267b48c2b984..14db9f64c8841 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VolatileKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VolatileKeywordRecommender.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class VolatileKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class VolatileKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.VolatileKeyword) { private static readonly ISet s_validMemberModifiers = new HashSet(SyntaxFacts.EqualityComparer) { @@ -22,11 +22,6 @@ internal class VolatileKeywordRecommender : AbstractSyntacticSingleKeywordRecomm SyntaxKind.StaticKeyword, }; - public VolatileKeywordRecommender() - : base(SyntaxKind.VolatileKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/WarningKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/WarningKeywordRecommender.cs index 3e762bf3e53f8..11c2b8d1ea9eb 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/WarningKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/WarningKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class WarningKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class WarningKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.WarningKeyword, isValidInPreprocessorContext: true) { - public WarningKeywordRecommender() - : base(SyntaxKind.WarningKeyword, isValidInPreprocessorContext: true) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { // # warning diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/WarningsKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/WarningsKeywordRecommender.cs index 7a142ef1080d8..a4dbf2fc7163b 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/WarningsKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/WarningsKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class WarningsKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class WarningsKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.WarningsKeyword, isValidInPreprocessorContext: true) { - public WarningsKeywordRecommender() - : base(SyntaxKind.WarningsKeyword, isValidInPreprocessorContext: true) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var previousToken1 = context.TargetToken; diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/WhenKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/WhenKeywordRecommender.cs index eaeebe9bed1c6..4b896f470d049 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/WhenKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/WhenKeywordRecommender.cs @@ -10,13 +10,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class WhenKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class WhenKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.WhenKeyword, isValidInPreprocessorContext: true) { - public WhenKeywordRecommender() - : base(SyntaxKind.WhenKeyword, isValidInPreprocessorContext: true) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return context.IsCatchFilterContext || diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/WhereKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/WhereKeywordRecommender.cs index 54e09fcf7e941..30164f90c309f 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/WhereKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/WhereKeywordRecommender.cs @@ -11,13 +11,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class WhereKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class WhereKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.WhereKeyword) { - public WhereKeywordRecommender() - : base(SyntaxKind.WhereKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { return diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/WhileKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/WhileKeywordRecommender.cs index b1fc429f226ba..e36db8cfae7c1 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/WhileKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/WhileKeywordRecommender.cs @@ -8,13 +8,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class WhileKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class WhileKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.WhileKeyword) { - public WhileKeywordRecommender() - : base(SyntaxKind.WhileKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { if (context.IsStatementContext || diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/WithKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/WithKeywordRecommender.cs index de122a95edc0c..4289f46d4156d 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/WithKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/WithKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class WithKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class WithKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.WithKeyword) { - public WithKeywordRecommender() - : base(SyntaxKind.WithKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => !context.IsInNonUserCode && context.IsIsOrAsOrSwitchOrWithExpressionContext; } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/YieldKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/YieldKeywordRecommender.cs index 8792b57a6e950..e3cd6e56af5e5 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/YieldKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/YieldKeywordRecommender.cs @@ -7,13 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class YieldKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class YieldKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.YieldKeyword) { - public YieldKeywordRecommender() - : base(SyntaxKind.YieldKeyword) - { - } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) => context.IsStatementContext; } diff --git a/src/Features/CSharp/Portable/ConvertAutoPropertyToFullProperty/CSharpConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertAutoPropertyToFullProperty/CSharpConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs index c238e4b2dd533..5cb11e73a8cf6 100644 --- a/src/Features/CSharp/Portable/ConvertAutoPropertyToFullProperty/CSharpConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ConvertAutoPropertyToFullProperty/CSharpConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs @@ -129,9 +129,7 @@ protected override SyntaxNode ConvertPropertyToExpressionBodyIfDesired( var preference = info.Options.PreferExpressionBodiedProperties.Value; if (preference == ExpressionBodyPreference.Never) - { - return propertyDeclaration.WithSemicolonToken(default); - } + return propertyDeclaration; // if there is a get accessors only, we can move the expression body to the property if (propertyDeclaration.AccessorList?.Accessors.Count == 1 && @@ -146,7 +144,7 @@ protected override SyntaxNode ConvertPropertyToExpressionBodyIfDesired( } } - return propertyDeclaration.WithSemicolonToken(default); + return propertyDeclaration; } protected override SyntaxNode GetTypeBlock(SyntaxNode syntaxNode) diff --git a/src/Features/CSharp/Portable/ConvertIfToSwitch/CSharpConvertIfToSwitchCodeRefactoringProvider.Rewriting.cs b/src/Features/CSharp/Portable/ConvertIfToSwitch/CSharpConvertIfToSwitchCodeRefactoringProvider.Rewriting.cs index cd1028b1bfe08..fbf6694b316ba 100644 --- a/src/Features/CSharp/Portable/ConvertIfToSwitch/CSharpConvertIfToSwitchCodeRefactoringProvider.Rewriting.cs +++ b/src/Features/CSharp/Portable/ConvertIfToSwitch/CSharpConvertIfToSwitchCodeRefactoringProvider.Rewriting.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.ConvertIfToSwitch; diff --git a/src/Features/CSharp/Portable/ConvertLinq/ConvertForEachToLinqQuery/AbstractToMethodConverter.cs b/src/Features/CSharp/Portable/ConvertLinq/ConvertForEachToLinqQuery/AbstractToMethodConverter.cs index 99e9b4143629d..1f71395c3a949 100644 --- a/src/Features/CSharp/Portable/ConvertLinq/ConvertForEachToLinqQuery/AbstractToMethodConverter.cs +++ b/src/Features/CSharp/Portable/ConvertLinq/ConvertForEachToLinqQuery/AbstractToMethodConverter.cs @@ -5,7 +5,6 @@ #nullable disable using System.Collections.Generic; -using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.ConvertLinq.ConvertForEachToLinqQuery; using Microsoft.CodeAnalysis.CSharp.Extensions; diff --git a/src/Features/CSharp/Portable/ConvertPrimaryToRegularConstructor/ConvertPrimaryToRegularConstructorCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertPrimaryToRegularConstructor/ConvertPrimaryToRegularConstructorCodeRefactoringProvider.cs index 072adadd49073..afbe366f62f9e 100644 --- a/src/Features/CSharp/Portable/ConvertPrimaryToRegularConstructor/ConvertPrimaryToRegularConstructorCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ConvertPrimaryToRegularConstructor/ConvertPrimaryToRegularConstructorCodeRefactoringProvider.cs @@ -51,6 +51,11 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte if (typeDeclaration is RecordDeclarationSyntax) return; + // Extensions use the .ParameterList to represent the parameters of the extension method. But this is not a + // constructor, and we cannot offer to convert it to have a regular constructor. + if (typeDeclaration is ExtensionDeclarationSyntax) + return; + var triggerSpan = TextSpan.FromBounds(typeDeclaration.SpanStart, typeDeclaration.ParameterList.FullSpan.End); if (!triggerSpan.Contains(span)) return; diff --git a/src/Features/CSharp/Portable/ConvertToExtension/ConvertToExtensionCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertToExtension/ConvertToExtensionCodeRefactoringProvider.cs new file mode 100644 index 0000000000000..45dd5e3112ac5 --- /dev/null +++ b/src/Features/CSharp/Portable/ConvertToExtension/ConvertToExtensionCodeRefactoringProvider.cs @@ -0,0 +1,353 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using System.Composition; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; +using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.CSharp.CodeGeneration; +using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.Shared.Extensions; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.ConvertToExtension; + +using static CSharpSyntaxTokens; +using static SyntaxFactory; + +/// +/// Refactoring to convert from classic extension methods to modern C# 14 extension types. Practically all classic +/// extension methods are supported except for those where the 'this' parameter references method type +/// parameters that are not the starting type parameters of the extension method. Those extension methods do not +/// have a 'modern' form as modern extensions have no way of lowering to that classic ABI shape. +/// +[ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = PredefinedCodeRefactoringProviderNames.ConvertToExtension), Shared] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed partial class ConvertToExtensionCodeRefactoringProvider() : CodeRefactoringProvider +{ + /// + /// Information about a class extension method we can convert to a modern extension. Extension methods with + /// 'identical' receiver parameters will compare/hash as equal. That way we can easily find and group all the + /// methods we want to move into a single extension together. + /// + private readonly record struct ExtensionMethodInfo( + ClassDeclarationSyntax ClassDeclaration, + MethodDeclarationSyntax ExtensionMethod, + IParameterSymbol FirstParameter, + ImmutableArray MethodTypeParameters) + { + public bool Equals(ExtensionMethodInfo info) + => ExtensionMethodEqualityComparer.Instance.Equals(this, info); + + public override int GetHashCode() + => ExtensionMethodEqualityComparer.Instance.GetHashCode(this); + } + + internal override FixAllProvider? GetFixAllProvider() + => new ConvertToExtensionFixAllProvider(); + + private static ExtensionMethodInfo? TryGetExtensionMethodInfo( + SemanticModel semanticModel, + MethodDeclarationSyntax methodDeclaration, + CancellationToken cancellationToken) + { + // For ease of processing, only operate on legal extension methods in a legal static class. e.g. + // + // static class S { static R M(this T t, ...) { } } + + if (methodDeclaration.ParameterList.Parameters is not [var firstParameter, ..]) + return null; + + if (!firstParameter.Modifiers.Any(SyntaxKind.ThisKeyword)) + return null; + + if (methodDeclaration.Parent is not ClassDeclarationSyntax classDeclaration) + return null; + + if (!methodDeclaration.Modifiers.Any(SyntaxKind.StaticKeyword)) + return null; + + if (!classDeclaration.Modifiers.Any(SyntaxKind.StaticKeyword)) + return null; + + // Has to be in a top level class. This also makes the fix-all provider easier to implement as we can just look + // for top level static classes to examine for extension methods. + if (classDeclaration.Parent is not BaseNamespaceDeclarationSyntax and not CompilationUnitSyntax) + return null; + + var firstParameterSymbol = semanticModel.GetRequiredDeclaredSymbol(firstParameter, cancellationToken); + + // Gather the referenced method type parameters (in their original method order) in the extension method 'this' + // parameter. If method type parameters are used in that parameter, they must be the a prefix of the type + // parameters of the method. + using var _ = ArrayBuilder.GetInstance(out var methodTypeParameters); + firstParameterSymbol.Type.AddReferencedMethodTypeParameters(methodTypeParameters); + + methodTypeParameters.Sort(static (t1, t2) => t1.Ordinal - t2.Ordinal); + for (var i = 0; i < methodTypeParameters.Count; i++) + { + var typeParameter = methodTypeParameters[i]; + if (typeParameter.Ordinal != i) + return null; + } + + return new(classDeclaration, methodDeclaration, firstParameterSymbol, methodTypeParameters.ToImmutableAndClear()); + } + + /// + /// Returns all the legal extension methods in grouped by their receiver + /// parameter. The groupings are only for receiver parameters that are considered identical, and thus could + /// be the extension parameter P in a new extension(P) declaration. This means they must have the same type, + /// name, ref-ness, constraints, attributes, etc. + /// + /// + /// Because the methods are processed in order within the , the arrays of grouped + /// extension methods in the dictionary will also be similarly ordered. + /// + private static ImmutableDictionary> GetAllExtensionMethods( + SemanticModel semanticModel, ClassDeclarationSyntax classDeclaration, CancellationToken cancellationToken) + { + var map = PooledDictionary>.GetInstance(); + + foreach (var member in classDeclaration.Members) + { + if (member is not MethodDeclarationSyntax methodDeclaration) + continue; + + var extensionInfo = TryGetExtensionMethodInfo(semanticModel, methodDeclaration, cancellationToken); + if (extensionInfo == null) + continue; + + map.MultiAdd(extensionInfo.Value, extensionInfo.Value); + } + + return map.ToImmutableMultiDictionaryAndFree(); + } + + public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) + { + var cancellationToken = context.CancellationToken; + + var document = context.Document; + + // Only offer if the user us on C# 14 or later where extension types are supported. + if (!document.Project.ParseOptions!.LanguageVersion().SupportsExtensions()) + return; + + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var methodDeclaration = await context.TryGetRelevantNodeAsync().ConfigureAwait(false); + + // If the user is on an extension method itself, offer to convert all the extension methods in the containing + // class with the same receiver parameter to an extension. + if (methodDeclaration != null) + { + var specificExtension = TryGetExtensionMethodInfo(semanticModel, methodDeclaration, cancellationToken); + if (specificExtension == null) + return; + + var allExtensionMethods = GetAllExtensionMethods( + semanticModel, specificExtension.Value.ClassDeclaration, cancellationToken); + + // Offer to change all the extension methods that match this particular parameter + context.RegisterRefactoring(CodeAction.Create( + string.Format(CSharpFeaturesResources.Convert_0_extension_methods_to_extension, specificExtension.Value.FirstParameter.Type.ToDisplayString()), + cancellationToken => ConvertToExtensionAsync( + document, specificExtension.Value.ClassDeclaration, allExtensionMethods, specificExtension, cancellationToken), + CSharpFeaturesResources.Convert_0_extension_methods_to_extension)); + } + else + { + // Otherwise, if they're on a static class, which contains extension methods, offer to convert all of them. + var classDeclaration = await context.TryGetRelevantNodeAsync().ConfigureAwait(false); + if (classDeclaration != null) + { + var allExtensionMethods = GetAllExtensionMethods( + semanticModel, classDeclaration, cancellationToken); + if (allExtensionMethods.IsEmpty) + return; + + context.RegisterRefactoring(CodeAction.Create( + string.Format(CSharpFeaturesResources.Convert_all_extension_methods_in_0_to_extension, classDeclaration.Identifier.ValueText), + cancellationToken => ConvertToExtensionAsync( + document, classDeclaration, allExtensionMethods, specificExtension: null, cancellationToken), + CSharpFeaturesResources.Convert_all_extension_methods_in_0_to_extension)); + } + } + } + + private static async Task ConvertToExtensionAsync( + Document document, + ClassDeclarationSyntax classDeclaration, + ImmutableDictionary> allExtensionMethods, + ExtensionMethodInfo? specificExtension, + CancellationToken cancellationToken) + { + Contract.ThrowIfTrue(allExtensionMethods.IsEmpty); + + var codeGenerationService = document.GetRequiredLanguageService(); + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + + var newDeclaration = ConvertToExtension( + codeGenerationService, classDeclaration, allExtensionMethods, specificExtension); + + var newRoot = root.ReplaceNode(classDeclaration, newDeclaration); + return document.WithSyntaxRoot(newRoot); + } + + /// + /// Core function that the normal fix and the fix-all-provider call into to fixup one class declaration and the set + /// of desired extension methods within that class declaration. When called on an extension method itself, this + /// will just be one extension method. When called on a class declaration, this will be all the extension methods + /// in that class. + /// + private static ClassDeclarationSyntax ConvertToExtension( + ICodeGenerationService codeGenerationService, + ClassDeclarationSyntax classDeclaration, + ImmutableDictionary> allExtensionMethods, + ExtensionMethodInfo? specificExtension) + { + Contract.ThrowIfTrue(allExtensionMethods.IsEmpty); + + var classDeclarationEditor = new SyntaxEditor(classDeclaration, CSharpSyntaxGenerator.Instance); + + if (specificExtension != null) + { + // If we were invoked on a specific extension, then only convert the extensions in this class with the same + // receiver parameter. + ConvertAndReplaceExtensions(allExtensionMethods[specificExtension.Value]); + } + else + { + // Otherwise, convert all the extension methods in this class. + foreach (var (_, matchingExtensions) in allExtensionMethods) + ConvertAndReplaceExtensions(matchingExtensions); + } + + return (ClassDeclarationSyntax)classDeclarationEditor.GetChangedRoot(); + + void ConvertAndReplaceExtensions(ImmutableArray extensionMethods) + { + // Replace the first extension method in the group (which will always be earliest in the class decl) with + // the new extension declaration itself. + classDeclarationEditor.ReplaceNode( + extensionMethods.First().ExtensionMethod, + CreateExtension(extensionMethods)); + + // Then remove the rest of the extensions in the group. + foreach (var siblingExtension in extensionMethods.Skip(1)) + classDeclarationEditor.RemoveNode(siblingExtension.ExtensionMethod); + } + + ExtensionDeclarationSyntax CreateExtension(ImmutableArray group) + { + Contract.ThrowIfTrue(group.IsEmpty); + + var codeGenerationInfo = new CSharpCodeGenerationContextInfo( + CodeGenerationContext.Default, + CSharpCodeGenerationOptions.Default, + (CSharpCodeGenerationService)codeGenerationService, + LanguageVersionExtensions.CSharpNext); + + var firstExtensionInfo = group[0]; + var typeParameters = firstExtensionInfo.MethodTypeParameters.CastArray(); + + // Create a disconnected parameter. This way when we look at it, we won't think of it as an extension method + // parameter any more. This will prevent us from undesirable things (like placing 'this' on it when adding to + // the extension declaration). + var firstParameter = CodeGenerationSymbolFactory.CreateParameterSymbol(firstExtensionInfo.FirstParameter); + + var extensionDeclaration = ExtensionDeclaration( + attributeLists: default, + modifiers: default, + ExtensionKeyword, + TypeParameterGenerator.GenerateTypeParameterList(typeParameters, codeGenerationInfo), + ParameterGenerator.GenerateParameterList([firstParameter], isExplicit: false, codeGenerationInfo), + typeParameters.GenerateConstraintClauses(), + OpenBraceToken, + [.. group.Select(ConvertExtensionMethod)], + CloseBraceToken, + semicolonToken: default); + + // Move the blank lines above the first extension method inside the extension to the extension itself. + firstExtensionInfo.ExtensionMethod.GetNodeWithoutLeadingBlankLines(out var leadingBlankLines); + return extensionDeclaration.WithLeadingTrivia(leadingBlankLines); + } + + MethodDeclarationSyntax ConvertExtensionMethod( + ExtensionMethodInfo extensionMethodInfo, int index) + { + var extensionMethod = extensionMethodInfo.ExtensionMethod; + var parameterList = extensionMethod.ParameterList; + + var converted = extensionMethodInfo.ExtensionMethod + // skip the first parameter, which is the 'this' parameter, and the comma that follows it. + .WithParameterList(parameterList.WithParameters(SeparatedList( + parameterList.Parameters.GetWithSeparators().Skip(2)))) + .WithTypeParameterList(ConvertTypeParameters(extensionMethodInfo)) + .WithConstraintClauses(ConvertConstraintClauses(extensionMethodInfo)); + + // remove 'static' from the classic extension method, now that it is in the extension declaration. it + // represents an 'instance' method in the new form. + converted = CSharpSyntaxGenerator.Instance.WithModifiers(converted, + CSharpSyntaxGenerator.Instance.GetModifiers(converted).WithIsStatic(false)); + + // If we're on the first extension method in the group, then remove its leading blank lines. Those will be + // moved to the extension declaration itself. + if (index == 0) + converted = converted.GetNodeWithoutLeadingBlankLines(); + + // Note: Formatting in this fashion is not desirable. Ideally we would use + // https://github.com/dotnet/roslyn/issues/59228 to just attach an indentation annotation to the extension + // method to indent it instead. + return converted.WithAdditionalAnnotations(Formatter.Annotation); + } + + static TypeParameterListSyntax? ConvertTypeParameters( + ExtensionMethodInfo extensionMethodInfo) + { + var extensionMethod = extensionMethodInfo.ExtensionMethod; + var movedTypeParameterCount = extensionMethodInfo.MethodTypeParameters.Length; + + // If the extension method wasn't generic, or we're not removing any type parameters, there's nothing to do. + if (extensionMethod.TypeParameterList is null || movedTypeParameterCount == 0) + return extensionMethod.TypeParameterList; + + // If we're removing all the type parameters, remove the type parameter list entirely. + if (extensionMethod.TypeParameterList.Parameters.Count == movedTypeParameterCount) + return null; + + // We want to remove the type parameter and the comma that follows it. So we multiple the count of type + // parameters we're removing by two to grab both. + return extensionMethod.TypeParameterList.WithParameters(SeparatedList( + extensionMethod.TypeParameterList.Parameters.GetWithSeparators().Skip(movedTypeParameterCount * 2))); + } + + static SyntaxList ConvertConstraintClauses( + ExtensionMethodInfo extensionMethodInfo) + { + var extensionMethod = extensionMethodInfo.ExtensionMethod; + var movedTypeParameterCount = extensionMethodInfo.MethodTypeParameters.Length; + + // If the extension method had no constraints, or we're not removing any type parameters, there's nothing to do. + if (extensionMethod.ConstraintClauses.Count == 0 || movedTypeParameterCount == 0) + return extensionMethod.ConstraintClauses; + + // Remove clauses referring to type parameters that are being moved to the extension method. + return [.. extensionMethod.ConstraintClauses.Where( + c => !extensionMethodInfo.MethodTypeParameters.Any(t => t.Name == c.Name.Identifier.ValueText))]; + } + } +} diff --git a/src/Features/CSharp/Portable/ConvertToExtension/ConvertToExtensionFixAllProvider.cs b/src/Features/CSharp/Portable/ConvertToExtension/ConvertToExtensionFixAllProvider.cs new file mode 100644 index 0000000000000..bf092c673fac6 --- /dev/null +++ b/src/Features/CSharp/Portable/ConvertToExtension/ConvertToExtensionFixAllProvider.cs @@ -0,0 +1,80 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeGeneration; +using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.CSharp.CodeGeneration; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.ConvertToExtension; + +using FixAllScope = CodeAnalysis.CodeFixes.FixAllScope; + +internal sealed partial class ConvertToExtensionCodeRefactoringProvider +{ + private sealed class ConvertToExtensionFixAllProvider() + : DocumentBasedFixAllProvider( + [FixAllScope.Document, FixAllScope.Project, FixAllScope.Solution, FixAllScope.ContainingType]) + { + protected override async Task FixAllAsync( + FixAllContext fixAllContext, + Document document, + Optional> fixAllSpans) + { + var cancellationToken = fixAllContext.CancellationToken; + + var codeGenerationService = (CSharpCodeGenerationService)document.GetRequiredLanguageService(); + + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + + var editor = new SyntaxEditor(root, document.Project.Solution.Services); + foreach (var declaration in GetTopLevelClassDeclarations(root, fixAllSpans)) + { + // We might hit partial parts that have no extension methods in them. Just skip those. + var extensionMethods = GetAllExtensionMethods(semanticModel, declaration, cancellationToken); + if (extensionMethods.IsEmpty) + continue; + + // For each class declaration we hit that has extension methods in it, convert all the extension methods + // to extensions and replace the old declaration with the new one. + var newDeclaration = ConvertToExtension( + codeGenerationService, declaration, extensionMethods, specificExtension: null); + editor.ReplaceNode(declaration, newDeclaration); + } + + var newRoot = editor.GetChangedRoot(); + return document.WithSyntaxRoot(newRoot); + } + + private static IEnumerable GetTopLevelClassDeclarations( + SyntaxNode root, Optional> fixAllSpans) + { + if (fixAllSpans.HasValue) + { + // User selected 'fix all in containing type'. Core code refactoring engine will return the spans of + // the containing class. Process each of those individually, converting all the extension methods in + // each partial part to extension declarations. + return fixAllSpans.Value + .Select(span => root.FindNode(span) as ClassDeclarationSyntax) + .WhereNotNull(); + } + else + { + // Processing the whole file. Return all top level classes in the file. + return root + .DescendantNodes(descendIntoChildren: n => n is CompilationUnitSyntax or BaseNamespaceDeclarationSyntax) + .OfType(); + } + } + } +} diff --git a/src/Features/CSharp/Portable/ConvertToExtension/ExtensionMethodEqualityComparer.cs b/src/Features/CSharp/Portable/ConvertToExtension/ExtensionMethodEqualityComparer.cs new file mode 100644 index 0000000000000..f7a5fbc065bf1 --- /dev/null +++ b/src/Features/CSharp/Portable/ConvertToExtension/ExtensionMethodEqualityComparer.cs @@ -0,0 +1,146 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Roslyn.Utilities; +using Microsoft.CodeAnalysis.Shared.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.ConvertToExtension; + +internal sealed partial class ConvertToExtensionCodeRefactoringProvider +{ + private sealed class ExtensionMethodEqualityComparer : + IEqualityComparer, + IEqualityComparer, + IEqualityComparer + { + public static readonly ExtensionMethodEqualityComparer Instance = new(); + + private static readonly SymbolEquivalenceComparer s_equivalenceComparer = new( + assemblyComparer: null, + distinguishRefFromOut: true, + // `void Goo(this (int x, int y) tuple)` doesn't match `void Goo(this (int a, int b) tuple) + tupleNamesMustMatch: true, + // `void Goo(this string? x)` doesn't matches `void Goo(this string x)` + ignoreNullableAnnotations: false, + // `void Goo(this object x)` doesn't matches `void Goo(this dynamic x)` + objectAndDynamicCompareEqually: false, + // `void Goo(this string[] x)` doesn't matches `void Goo(this Span x)` + arrayAndReadOnlySpanCompareEqually: false); + + #region IEqualityComparer + + private bool AttributesMatch(ImmutableArray attributes1, ImmutableArray attributes2) + => attributes1.SequenceEqual(attributes2, this); + + public bool Equals(AttributeData? x, AttributeData? y) + { + if (x == y) + return true; + + if (x is null || y is null) + return false; + + // Ensure the attributes reference the same attribute class, and have the same constructor/named-parameter + // values in the same order. + if (!Equals(x.AttributeClass, y.AttributeClass)) + return false; + + return x.ConstructorArguments.SequenceEqual(y.ConstructorArguments) && + x.NamedArguments.SequenceEqual(y.NamedArguments); + } + + // Not needed as we never group by attributes. We only SequenceEqual compare them. + public int GetHashCode([DisallowNull] AttributeData obj) + => throw ExceptionUtilities.Unreachable(); + + #endregion + + #region IEqualityComparer + + public bool Equals(ITypeParameterSymbol? x, ITypeParameterSymbol? y) + { + if (x == y) + return true; + + if (x is null || y is null) + return false; + + // Names must match as the code in the extension methods may reference the type parameters by name and has + // to continue working. + if (x.Name != y.Name) + return false; + + // Attributes have to match as we're moving these type parameters up to the extension itself. + if (!AttributesMatch(x.GetAttributes(), y.GetAttributes())) + return false; + + // Constraints have to match as we're moving these type parameters up to the extension itself. + if (x.HasConstructorConstraint != y.HasConstructorConstraint) + return false; + + if (x.HasNotNullConstraint != y.HasNotNullConstraint) + return false; + + if (x.HasReferenceTypeConstraint != y.HasReferenceTypeConstraint) + return false; + + if (x.HasUnmanagedTypeConstraint != y.HasUnmanagedTypeConstraint) + return false; + + if (x.HasValueTypeConstraint != y.HasValueTypeConstraint) + return false; + + // Constraints have to match as we're moving these type parameters up to the extension itself. We again use + // s_equivalenceComparer.SignatureTypeEquivalenceComparer here as we want method type parameters compared by + // ordinal so that if we constraints that reference the method type parameters, that we can tell they're + // equivalent across disparate methods. + if (!x.ConstraintTypes.SequenceEqual(y.ConstraintTypes, s_equivalenceComparer.SignatureTypeEquivalenceComparer)) + return false; + + return true; + } + + // Not needed as we never group by type parameters. We only SequenceEqual compare them. + public int GetHashCode([DisallowNull] ITypeParameterSymbol obj) + => throw ExceptionUtilities.Unreachable(); + + #endregion + + #region IEqualityComparer + + public bool Equals(ExtensionMethodInfo x, ExtensionMethodInfo y) + { + if (x.ExtensionMethod == y.ExtensionMethod) + return true; + + // For us to consider two extension methods to be equivalent, they must have a first parameter that we + // consider equal, any method type parameters they use must have the same constraints, and they must have + // the same attributes on them. + // + // Notes: s_equivalenceComparer.ParameterEquivalenceComparer will check the parameter name, type, ref kinds, + // custom modifiers. All things we want to match to merge extension methods into the same method. + // + // Note: The initial check will ensure that the same method-type-parameters are used in both methods *when + // compared by type parameter ordinal*. The MethodTypeParameterMatch will then check that the type + // parameters that we would lift to the extension method would be considered the same as well. + + return + s_equivalenceComparer.ParameterEquivalenceComparer.Equals(x.FirstParameter, y.FirstParameter, compareParameterName: true, isCaseSensitive: true) && + AttributesMatch(x.FirstParameter.GetAttributes(), y.FirstParameter.GetAttributes()) && + x.MethodTypeParameters.SequenceEqual(y.MethodTypeParameters, this); + } + + public int GetHashCode(ExtensionMethodInfo obj) + // Loosely match any extension methods if they have the same first parameter type (treating method type + // parameters by ordinal) and same name. We'll do a more full match in .Equals above. + => s_equivalenceComparer.ParameterEquivalenceComparer.GetHashCode(obj.FirstParameter) ^ obj.FirstParameter.Name.GetHashCode(); + + #endregion + } +} diff --git a/src/Features/CSharp/Portable/ConvertToInterpolatedString/CSharpConvertPlaceholderToInterpolatedStringRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertToInterpolatedString/CSharpConvertPlaceholderToInterpolatedStringRefactoringProvider.cs index 60a3d2ce75ce8..f28948a0c3fbc 100644 --- a/src/Features/CSharp/Portable/ConvertToInterpolatedString/CSharpConvertPlaceholderToInterpolatedStringRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ConvertToInterpolatedString/CSharpConvertPlaceholderToInterpolatedStringRefactoringProvider.cs @@ -11,7 +11,9 @@ namespace Microsoft.CodeAnalysis.CSharp.ConvertToInterpolatedString; [ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = PredefinedCodeRefactoringProviderNames.ConvertPlaceholderToInterpolatedString), Shared] -internal sealed partial class CSharpConvertPlaceholderToInterpolatedStringRefactoringProvider : +[method: ImportingConstructor] +[method: SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] +internal sealed partial class CSharpConvertPlaceholderToInterpolatedStringRefactoringProvider() : AbstractConvertPlaceholderToInterpolatedStringRefactoringProvider< ExpressionSyntax, LiteralExpressionSyntax, @@ -21,12 +23,6 @@ internal sealed partial class CSharpConvertPlaceholderToInterpolatedStringRefact ArgumentListSyntax, InterpolationSyntax> { - [ImportingConstructor] - [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] - public CSharpConvertPlaceholderToInterpolatedStringRefactoringProvider() - { - } - protected override ExpressionSyntax ParseExpression(string text) => SyntaxFactory.ParseExpression(text); } diff --git a/src/Features/CSharp/Portable/ConvertToRawString/ConvertRegularStringToRawStringCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertToRawString/ConvertRegularStringToRawStringCodeRefactoringProvider.cs index a92e0e476b5ea..211d6d3c05114 100644 --- a/src/Features/CSharp/Portable/ConvertToRawString/ConvertRegularStringToRawStringCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ConvertToRawString/ConvertRegularStringToRawStringCodeRefactoringProvider.cs @@ -13,7 +13,6 @@ using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.ConvertToRawString; diff --git a/src/Features/CSharp/Portable/ConvertToRawString/ConvertStringToRawStringCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertToRawString/ConvertStringToRawStringCodeRefactoringProvider.cs index 567aaf3eec6cc..f5ed7832fd664 100644 --- a/src/Features/CSharp/Portable/ConvertToRawString/ConvertStringToRawStringCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ConvertToRawString/ConvertStringToRawStringCodeRefactoringProvider.cs @@ -18,7 +18,6 @@ using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.ConvertToRawString; diff --git a/src/Features/CSharp/Portable/ConvertToRawString/IConvertStringProvider.cs b/src/Features/CSharp/Portable/ConvertToRawString/IConvertStringProvider.cs index 356e923e0c94f..e49147063f929 100644 --- a/src/Features/CSharp/Portable/ConvertToRawString/IConvertStringProvider.cs +++ b/src/Features/CSharp/Portable/ConvertToRawString/IConvertStringProvider.cs @@ -5,7 +5,6 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Formatting; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.ConvertToRawString; diff --git a/src/Features/CSharp/Portable/Copilot/CSharpImplementNotImplementedExceptionDiagnosticAnalyzer.cs b/src/Features/CSharp/Portable/Copilot/CSharpImplementNotImplementedExceptionDiagnosticAnalyzer.cs new file mode 100644 index 0000000000000..101645b2a7535 --- /dev/null +++ b/src/Features/CSharp/Portable/Copilot/CSharpImplementNotImplementedExceptionDiagnosticAnalyzer.cs @@ -0,0 +1,119 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Operations; + +namespace Microsoft.CodeAnalysis.CSharp.Copilot; + +[DiagnosticAnalyzer(LanguageNames.CSharp)] +internal sealed class CSharpImplementNotImplementedExceptionDiagnosticAnalyzer() + : AbstractBuiltInCodeStyleDiagnosticAnalyzer( + IDEDiagnosticIds.CopilotImplementNotImplementedExceptionDiagnosticId, + EnforceOnBuildValues.CopilotImplementNotImplementedException, + option: null, + new LocalizableResourceString( + nameof(CSharpAnalyzersResources.Implement_with_Copilot), CSharpAnalyzersResources.ResourceManager, typeof(CSharpAnalyzersResources)), + configurable: false) +{ + public override DiagnosticAnalyzerCategory GetAnalyzerCategory() + => DiagnosticAnalyzerCategory.SemanticSpanAnalysis; + + protected override void InitializeWorker(AnalysisContext context) + { + context.RegisterCompilationStartAction(context => + { + var notImplementedExceptionType = context.Compilation.GetTypeByMetadataName(typeof(NotImplementedException).FullName!); + if (notImplementedExceptionType is null) + return; + + context.RegisterOperationBlockAction(context => AnalyzeOperationBlock(context, notImplementedExceptionType)); + }); + } + + private void AnalyzeOperationBlock( + OperationBlockAnalysisContext context, + INamedTypeSymbol notImplementedExceptionType) + { + foreach (var block in context.OperationBlocks) + AnalyzeBlock(block); + + void AnalyzeBlock(IOperation block) + { + foreach (var operation in block.DescendantsAndSelf()) + { + if (operation is IThrowOperation + { + Exception: IConversionOperation + { + Operand: IObjectCreationOperation + { + Constructor.ContainingType: INamedTypeSymbol constructedType, + }, + }, + Syntax: var throwSyntax + } throwOperation && + notImplementedExceptionType.Equals(constructedType)) + { + // Report diagnostic for each throw operation + context.ReportDiagnostic(Diagnostic.Create( + Descriptor, + throwOperation.Syntax.GetLocation())); + + // If the throw is the top-level operation in the containing symbol, report a diagnostic on the + // symbol as well. Note: consider reporting on the entire symbol, instead of just the name. And in + // this case, do not report directly on the throw as well. + if (ShouldReportAsTopLevel(block, operation)) + { + foreach (var location in context.OwningSymbol.Locations) + { + if (location.SourceTree == context.FilterTree) + { + context.ReportDiagnostic(Diagnostic.Create( + Descriptor, + location)); + } + } + } + } + } + } + } + + private static bool ShouldReportAsTopLevel(IOperation block, IOperation operation) + { + if (block is IBlockOperation { Operations: [var child] }) + { + // Handle: { throw new NotImplementedException(); } + if (child == operation) + return true; + + // Handle: => throw new NotImplementedException(); + if (child is IReturnOperation + { + ReturnedValue: IConversionOperation + { + Operand: var operand + } + } && operand == operation && + // Excluding property declarations with expression bodies + // Because their location is an exact match with the throw operation + // and we don't want to report the same location twice + operation.Syntax.Parent is not ArrowExpressionClauseSyntax { Parent: PropertyDeclarationSyntax }) + { + // Include expression-bodied methods and get accessors + return true; + } + + // Handle expression-bodied set accessors + if (child is IExpressionStatementOperation { Operation: var throwOperation } && throwOperation == operation) + return true; + } + + return false; + } +} diff --git a/src/Features/CSharp/Portable/Copilot/CSharpImplementNotImplementedExceptionFixProvider.cs b/src/Features/CSharp/Portable/Copilot/CSharpImplementNotImplementedExceptionFixProvider.cs new file mode 100644 index 0000000000000..3e6c9caeed567 --- /dev/null +++ b/src/Features/CSharp/Portable/Copilot/CSharpImplementNotImplementedExceptionFixProvider.cs @@ -0,0 +1,154 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using System.Composition; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Copilot; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.FindSymbols; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Internal.Log; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Simplification; +using Roslyn.Utilities; +using static Microsoft.CodeAnalysis.CodeActions.CodeAction; + +namespace Microsoft.CodeAnalysis.CSharp.Copilot; + +[ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.CopilotImplementNotImplementedException), Shared] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class CSharpImplementNotImplementedExceptionFixProvider() : SyntaxEditorBasedCodeFixProvider +{ + private static SyntaxAnnotation WarningAnnotation { get; } + = CodeActions.WarningAnnotation.Create( + CSharpFeaturesResources.Warning_colon_AI_suggestions_might_be_inaccurate); + + public override ImmutableArray FixableDiagnosticIds { get; } + = [IDEDiagnosticIds.CopilotImplementNotImplementedExceptionDiagnosticId]; + + public override async Task RegisterCodeFixesAsync(CodeFixContext context) + { + var document = context.Document; + var cancellationToken = context.CancellationToken; + + // Checks for feature flag + if (document.GetLanguageService() is not { } optionsService || + await optionsService.IsImplementNotImplementedExceptionEnabledAsync().ConfigureAwait(false) is false) + { + return; + } + + // Checks for service availability + if (document.GetLanguageService() is not { } copilotService || + await copilotService.IsImplementNotImplementedExceptionsAvailableAsync(cancellationToken).ConfigureAwait(false) is false) + { + return; + } + + var diagnosticNode = context.Diagnostics[0].Location.FindNode(getInnermostNodeForTie: true, cancellationToken); + + // Preliminary analysis before registering fix + var methodOrProperty = diagnosticNode.FirstAncestorOrSelf(); + + if (methodOrProperty is BasePropertyDeclarationSyntax or BaseMethodDeclarationSyntax) + { + // Pull out the computation into a lazy computation here. That way if we compute (and thus cache) the + // result for the preview window, we'll produce the same value when the fix is actually applied. + var lazy = AsyncLazy.Create(GetDocumentUpdater(context)); + + context.RegisterCodeFix(Create( + title: CSharpAnalyzersResources.Implement_with_Copilot, + lazy.GetValueAsync, + equivalenceKey: nameof(CSharpAnalyzersResources.Implement_with_Copilot)), + context.Diagnostics); + + Logger.Log(FunctionId.Copilot_Implement_NotImplementedException_Fix_Registered, logLevel: LogLevel.Information); + } + } + + protected override async Task FixAllAsync( + Document document, ImmutableArray diagnostics, + SyntaxEditor editor, CancellationToken cancellationToken) + { + var memberReferencesBuilder = ImmutableDictionary.CreateBuilder>(); + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + + foreach (var diagnostic in diagnostics) + { + var diagnosticNode = diagnostic.Location.FindNode(getInnermostNodeForTie: true, cancellationToken); + var methodOrProperty = diagnosticNode.FirstAncestorOrSelf(); + + Contract.ThrowIfFalse(methodOrProperty is BasePropertyDeclarationSyntax or BaseMethodDeclarationSyntax); + + if (!memberReferencesBuilder.ContainsKey(methodOrProperty)) + { + var memberSymbol = semanticModel.GetRequiredDeclaredSymbol(methodOrProperty, cancellationToken); + + cancellationToken.ThrowIfCancellationRequested(); + var searchOptions = FindReferencesSearchOptions.GetFeatureOptionsForStartingSymbol(memberSymbol); + var references = await SymbolFinder.FindReferencesAsync(memberSymbol, document.Project.Solution, searchOptions, cancellationToken).ConfigureAwait(false); + memberReferencesBuilder.Add(methodOrProperty, references); + } + } + + var copilotService = document.GetRequiredLanguageService(); + var memberImplementationDetails = await copilotService.ImplementNotImplementedExceptionsAsync(document, memberReferencesBuilder.ToImmutable(), cancellationToken).ConfigureAwait(false); + + foreach (var node in memberReferencesBuilder.Keys) + { + var methodOrProperty = (MemberDeclarationSyntax)node; + + Contract.ThrowIfFalse(memberImplementationDetails.TryGetValue(methodOrProperty, out var implementationDetails)); + + var replacement = implementationDetails.ReplacementNode; + if (replacement is BasePropertyDeclarationSyntax or BaseMethodDeclarationSyntax) + { + replacement = replacement + .WithTriviaFrom(methodOrProperty) + .WithAdditionalAnnotations(Formatter.Annotation, WarningAnnotation, Simplifier.Annotation); + } + else + { + Contract.ThrowIfTrue(string.IsNullOrWhiteSpace(implementationDetails.Message)); + replacement = AddErrorComment(methodOrProperty, implementationDetails.Message); + } + + editor.ReplaceNode(methodOrProperty, replacement); + } + + editor.ReplaceNode(editor.OriginalRoot, editor.GetChangedRoot()); + Logger.Log(FunctionId.Copilot_Implement_NotImplementedException_Completed, logLevel: LogLevel.Information); + } + + private static MemberDeclarationSyntax AddErrorComment(MemberDeclarationSyntax member, string errorMessage) + { + Logger.Log(FunctionId.Copilot_Implement_NotImplementedException_Failed, errorMessage, logLevel: LogLevel.Error); + + var comment = SyntaxFactory.TriviaList( + SyntaxFactory.Comment($"/* {errorMessage} */"), + SyntaxFactory.CarriageReturnLineFeed); + var leadingTrivia = member.GetLeadingTrivia(); + + // Find the last EndOfLineTrivia + var syntaxTrivia = leadingTrivia.LastOrDefault(static trivia => trivia.IsKind(SyntaxKind.EndOfLineTrivia)); + var lastEndOfLineIndex = leadingTrivia.IndexOf(syntaxTrivia); + + // Insert the comment after the last EndOfLineTrivia or at the start if none found + var insertIndex = lastEndOfLineIndex >= 0 ? lastEndOfLineIndex + 1 : 0; + var newLeadingTrivia = leadingTrivia.InsertRange(insertIndex, comment); + + return member + .WithLeadingTrivia(newLeadingTrivia) + .WithAdditionalAnnotations(Formatter.Annotation, WarningAnnotation, Simplifier.Annotation); + } +} diff --git a/src/Features/CSharp/Portable/Diagnostics/LanguageServer/CSharpLspBuildOnlyDiagnostics.cs b/src/Features/CSharp/Portable/Diagnostics/LanguageServer/CSharpLspBuildOnlyDiagnostics.cs index 6bd117bf73410..c19cb644ff215 100644 --- a/src/Features/CSharp/Portable/Diagnostics/LanguageServer/CSharpLspBuildOnlyDiagnostics.cs +++ b/src/Features/CSharp/Portable/Diagnostics/LanguageServer/CSharpLspBuildOnlyDiagnostics.cs @@ -60,7 +60,8 @@ namespace Microsoft.CodeAnalysis.CSharp.LanguageServer; "CS9207", // ErrorCode.ERR_InterceptableMethodMustBeOrdinary "CS8419", // ErrorCode.ERR_PossibleAsyncIteratorWithoutYield "CS8420", // ErrorCode.ERR_PossibleAsyncIteratorWithoutYieldOrAwait - "CS9217" // ErrorCode.ERR_RefLocalAcrossAwait + "CS9217", // ErrorCode.ERR_RefLocalAcrossAwait + "CS9274" // ErrorCode.ERR_DataSectionStringLiteralHashCollision )] [Shared] internal sealed class CSharpLspBuildOnlyDiagnostics : ILspBuildOnlyDiagnostics diff --git a/src/Features/CSharp/Portable/DocumentationComments/CSharpDocumentationCommentSnippetService.cs b/src/Features/CSharp/Portable/DocumentationComments/CSharpDocumentationCommentSnippetService.cs index f2f2bf21fdb93..1c58cabad0796 100644 --- a/src/Features/CSharp/Portable/DocumentationComments/CSharpDocumentationCommentSnippetService.cs +++ b/src/Features/CSharp/Portable/DocumentationComments/CSharpDocumentationCommentSnippetService.cs @@ -15,6 +15,7 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; +using System.Collections.Immutable; namespace Microsoft.CodeAnalysis.CSharp.DocumentationComments; @@ -26,15 +27,6 @@ internal sealed class CSharpDocumentationCommentSnippetService : AbstractDocumen protected override bool AddIndent => true; protected override string ExteriorTriviaText => "///"; - private static readonly SymbolDisplayFormat s_format = - new( - globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Omitted, - typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypes, - genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, - miscellaneousOptions: - SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers | - SymbolDisplayMiscellaneousOptions.UseSpecialTypes); - [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public CSharpDocumentationCommentSnippetService() diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.Analyzer.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.Analyzer.cs index b2e054977d814..6278cd82325a4 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.Analyzer.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.Analyzer.cs @@ -3,8 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.ExtractMethod; diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.CallSiteContainerRewriter.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.CallSiteContainerRewriter.cs index f325648475da2..990bc6b6c9c6b 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.CallSiteContainerRewriter.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.CallSiteContainerRewriter.cs @@ -8,10 +8,8 @@ using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.ExtractMethod; diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.MultipleStatementsCodeGenerator.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.MultipleStatementsCodeGenerator.cs index acdeb4533ce4d..842a16f5c4305 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.MultipleStatementsCodeGenerator.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.MultipleStatementsCodeGenerator.cs @@ -12,7 +12,6 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.ExtractMethod; using Microsoft.CodeAnalysis.PooledObjects; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.ExtractMethod; diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.SingleStatementCodeGenerator.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.SingleStatementCodeGenerator.cs index aac178a6d1082..befaafb31ffc3 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.SingleStatementCodeGenerator.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.SingleStatementCodeGenerator.cs @@ -9,7 +9,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.ExtractMethod; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.ExtractMethod; diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs index 0cbdbe776212e..082e857e2a425 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs @@ -7,7 +7,6 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.TriviaResult.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.TriviaResult.cs index 4bd7d9d93f26a..10b0fc7d214d2 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.TriviaResult.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.TriviaResult.cs @@ -6,8 +6,6 @@ using System.Collections.Generic; using System.Linq; -using System.Threading; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.ExtractMethod; diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.cs index 5b494017fc1a3..c6d4375439b5f 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.cs @@ -4,7 +4,6 @@ #nullable disable -using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpSelectionResult.ExpressionResult.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpSelectionResult.ExpressionResult.cs index f7f13fd408ec5..bf67d178dc59f 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpSelectionResult.ExpressionResult.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpSelectionResult.ExpressionResult.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.ExtractMethod; diff --git a/src/Features/CSharp/Portable/Formatting/CSharpAccessibilityModifiersNewDocumentFormattingProvider.cs b/src/Features/CSharp/Portable/Formatting/CSharpAccessibilityModifiersNewDocumentFormattingProvider.cs index e43d6fbe50178..212256cebcce8 100644 --- a/src/Features/CSharp/Portable/Formatting/CSharpAccessibilityModifiersNewDocumentFormattingProvider.cs +++ b/src/Features/CSharp/Portable/Formatting/CSharpAccessibilityModifiersNewDocumentFormattingProvider.cs @@ -7,7 +7,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.AddAccessibilityModifiers; +using Microsoft.CodeAnalysis.AddOrRemoveAccessibilityModifiers; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.LanguageService; @@ -41,7 +41,7 @@ public async Task FormatNewDocumentAsync(Document document, Document? var typeDeclarations = root.DescendantNodes().Where(node => syntaxFacts.IsTypeDeclaration(node)); var editor = new SyntaxEditor(root, document.Project.Solution.Services); - var service = document.GetRequiredLanguageService(); + var service = document.GetRequiredLanguageService(); foreach (var declaration in typeDeclarations) { @@ -69,7 +69,7 @@ public async Task FormatNewDocumentAsync(Document document, Document? if (type == null) continue; - AddAccessibilityModifiersHelpers.UpdateDeclaration(editor, type, declaration); + AddOrRemoveAccessibilityModifiersHelpers.UpdateDeclaration(editor, type, declaration); } return document.WithSyntaxRoot(editor.GetChangedRoot()); diff --git a/src/Features/CSharp/Portable/GenerateType/CSharpGenerateTypeService.cs b/src/Features/CSharp/Portable/GenerateType/CSharpGenerateTypeService.cs index 6ec0d0a19f672..902a2fdbaeaab 100644 --- a/src/Features/CSharp/Portable/GenerateType/CSharpGenerateTypeService.cs +++ b/src/Features/CSharp/Portable/GenerateType/CSharpGenerateTypeService.cs @@ -24,7 +24,6 @@ using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Microsoft.CodeAnalysis.Utilities; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.GenerateType; diff --git a/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementImplicitlyCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementImplicitlyCodeRefactoringProvider.cs index 2927c9b9a107c..b31cd2819eb08 100644 --- a/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementImplicitlyCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementImplicitlyCodeRefactoringProvider.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.ImplementInterface; diff --git a/src/Features/CSharp/Portable/InitializeParameter/CSharpInitializeMemberFromParameterCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/InitializeParameter/CSharpInitializeMemberFromParameterCodeRefactoringProvider.cs index 74d1afc45fc16..cb4955e25a9fd 100644 --- a/src/Features/CSharp/Portable/InitializeParameter/CSharpInitializeMemberFromParameterCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/InitializeParameter/CSharpInitializeMemberFromParameterCodeRefactoringProvider.cs @@ -4,7 +4,6 @@ using System.Composition; using System.Diagnostics.CodeAnalysis; -using System.Threading; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.InitializeParameter; diff --git a/src/Features/CSharp/Portable/InitializeParameter/CSharpInitializeMemberFromPrimaryConstructorParameterCodeRefactoringProvider_Update.cs b/src/Features/CSharp/Portable/InitializeParameter/CSharpInitializeMemberFromPrimaryConstructorParameterCodeRefactoringProvider_Update.cs index d894e142d450c..1ed30878af5b1 100644 --- a/src/Features/CSharp/Portable/InitializeParameter/CSharpInitializeMemberFromPrimaryConstructorParameterCodeRefactoringProvider_Update.cs +++ b/src/Features/CSharp/Portable/InitializeParameter/CSharpInitializeMemberFromPrimaryConstructorParameterCodeRefactoringProvider_Update.cs @@ -12,7 +12,6 @@ using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.InitializeParameter; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.InitializeParameter; diff --git a/src/Features/CSharp/Portable/InlineHints/CSharpInlineTypeHintsService.cs b/src/Features/CSharp/Portable/InlineHints/CSharpInlineTypeHintsService.cs index bf41eeb2ad2d8..637a5ecff3a2b 100644 --- a/src/Features/CSharp/Portable/InlineHints/CSharpInlineTypeHintsService.cs +++ b/src/Features/CSharp/Portable/InlineHints/CSharpInlineTypeHintsService.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.InlineHints; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.InlineHints; diff --git a/src/Features/CSharp/Portable/IntroduceUsingStatement/CSharpIntroduceUsingStatementCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/IntroduceUsingStatement/CSharpIntroduceUsingStatementCodeRefactoringProvider.cs index 9786dffe0f8e2..36c6cecd19d91 100644 --- a/src/Features/CSharp/Portable/IntroduceUsingStatement/CSharpIntroduceUsingStatementCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/IntroduceUsingStatement/CSharpIntroduceUsingStatementCodeRefactoringProvider.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.IntroduceUsingStatement; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.IntroduceUsingStatement; @@ -40,7 +39,7 @@ protected override (SyntaxList tryStatements, SyntaxList (tryStatement.Block.Statements, tryStatement.Finally?.Block.Statements ?? default); protected override bool CanRefactorToContainBlockStatements(SyntaxNode parent) - => parent is BlockSyntax || parent is SwitchSectionSyntax || parent.IsEmbeddedStatementOwner(); + => parent is BlockSyntax or SwitchSectionSyntax || parent.IsEmbeddedStatementOwner(); protected override SyntaxList GetSurroundingStatements(StatementSyntax statement) => statement.GetRequiredParent() switch diff --git a/src/Features/CSharp/Portable/IntroduceVariable/CSharpIntroduceLocalForExpressionCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/IntroduceVariable/CSharpIntroduceLocalForExpressionCodeRefactoringProvider.cs index 7d96adc036d07..065d9126858a2 100644 --- a/src/Features/CSharp/Portable/IntroduceVariable/CSharpIntroduceLocalForExpressionCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/IntroduceVariable/CSharpIntroduceLocalForExpressionCodeRefactoringProvider.cs @@ -7,7 +7,6 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.CSharp.CodeStyle.TypeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; diff --git a/src/Features/CSharp/Portable/IntroduceVariable/CSharpIntroduceVariableService_IntroduceLocal.cs b/src/Features/CSharp/Portable/IntroduceVariable/CSharpIntroduceVariableService_IntroduceLocal.cs index 3121368ae6fa1..5ee7dda238bbb 100644 --- a/src/Features/CSharp/Portable/IntroduceVariable/CSharpIntroduceVariableService_IntroduceLocal.cs +++ b/src/Features/CSharp/Portable/IntroduceVariable/CSharpIntroduceVariableService_IntroduceLocal.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; @@ -53,12 +51,18 @@ protected override Document IntroduceLocal( var updatedExpression = expression.WithoutTrivia(); var simplifierOptions = (CSharpSimplifierOptions)options.SimplifierOptions; - // If the target-type new syntax is preferred and "var" is not preferred under any circumstance, then we use the target-type new syntax. - // The approach is not exhaustive. We aim to support codebases that rely strictly on the target-type new syntax (i.e., no "var"). - if (simplifierOptions.ImplicitObjectCreationWhenTypeIsApparent.Value && simplifierOptions.GetUseVarPreference() == UseVarPreference.None - && updatedExpression is ObjectCreationExpressionSyntax objectCreationExpression) + // If the implicit-object-creation is preferred and "var" is not preferred under any circumstance, then we use + // the implicit creation form when it it available. + if (simplifierOptions.ImplicitObjectCreationWhenTypeIsApparent.Value && + simplifierOptions.GetUseVarPreference() == UseVarPreference.None && + updatedExpression is ObjectCreationExpressionSyntax objectCreationExpression && + document.Root.SyntaxTree.Options.LanguageVersion() >= LanguageVersion.CSharp9) { - updatedExpression = ImplicitObjectCreationExpression(objectCreationExpression.ArgumentList, objectCreationExpression.Initializer); + var (newKeyword, argumentList) = objectCreationExpression.ArgumentList is null + ? (objectCreationExpression.NewKeyword.WithoutTrailingTrivia(), ArgumentList().WithoutLeadingTrivia().WithTrailingTrivia(objectCreationExpression.NewKeyword.TrailingTrivia)) + : (objectCreationExpression.NewKeyword, objectCreationExpression.ArgumentList); + updatedExpression = ImplicitObjectCreationExpression( + newKeyword, argumentList, objectCreationExpression.Initializer); } var declarationStatement = LocalDeclarationStatement( @@ -83,7 +87,7 @@ protected override Document IntroduceLocal( case ArrowExpressionClauseSyntax arrowExpression: // this will be null for expression-bodied properties & indexer (not for individual getters & setters, those do have a symbol), // both of which are a shorthand for the getter and always return a value - var method = document.SemanticModel.GetDeclaredSymbol(arrowExpression.Parent, cancellationToken) as IMethodSymbol; + var method = document.SemanticModel.GetDeclaredSymbol(arrowExpression.GetRequiredParent(), cancellationToken) as IMethodSymbol; var createReturnStatement = true; if (method is not null) @@ -235,7 +239,7 @@ private Document RewriteExpressionBodiedMemberAndIntroduceLocalDeclaration( CancellationToken cancellationToken) { var oldBody = arrowExpression; - var oldParentingNode = oldBody.Parent; + var oldParentingNode = oldBody.GetRequiredParent(); var leadingTrivia = oldBody.GetLeadingTrivia() .AddRange(oldBody.ArrowToken.TrailingTrivia); @@ -320,7 +324,7 @@ scope is ICompilationUnitSyntax if (scope is BlockSyntax block) { - var firstAffectedStatement = block.Statements.Single(s => firstAffectedExpression.GetAncestorOrThis().Contains(s)); + var firstAffectedStatement = block.Statements.Single(s => firstAffectedExpression.GetAncestorOrThis()!.Contains(s)); var firstAffectedStatementIndex = block.Statements.IndexOf(firstAffectedStatement); editor.ReplaceNode( block, @@ -333,7 +337,7 @@ scope is ICompilationUnitSyntax } else { - var firstAffectedGlobalStatement = compilationUnit.Members.OfType().Single(s => firstAffectedExpression.GetAncestorOrThis().Contains(s)); + var firstAffectedGlobalStatement = compilationUnit.Members.OfType().Single(s => firstAffectedExpression.GetAncestorOrThis()!.Contains(s)); var firstAffectedGlobalStatementIndex = compilationUnit.Members.IndexOf(firstAffectedGlobalStatement); editor.ReplaceNode( compilationUnit, @@ -348,6 +352,8 @@ scope is ICompilationUnitSyntax return document.Document.WithSyntaxRoot(editor.GetChangedRoot()); } +#nullable disable + private Document IntroduceLocalDeclarationIntoBlock( SemanticDocument document, BlockSyntax block, @@ -371,12 +377,6 @@ private Document IntroduceLocalDeclarationIntoBlock( var matches = FindMatches(document, expression, document, [scope], allOccurrences, cancellationToken); Debug.Assert(matches.Contains(expression)); - //(document, matches) = await ComplexifyParentingStatementsAsync(document, matches, cancellationToken).ConfigureAwait(false); - - //// Our original expression should have been one of the matches, which were tracked as part - //// of complexification, so we can retrieve the latest version of the expression here. - //expression = document.Root.GetCurrentNode(expression); - var root = document.Root; ISet allAffectedStatements = new HashSet(matches.SelectMany(expr => GetApplicableStatementAncestors(expr))); @@ -421,6 +421,8 @@ private Document IntroduceLocalDeclarationIntoBlock( return document.Document.WithSyntaxRoot(newRoot); } +#nullable restore + private static IEnumerable GetApplicableStatementAncestors(ExpressionSyntax expr) { foreach (var statement in expr.GetAncestorsOrThis()) @@ -454,10 +456,11 @@ private static int GetFirstStatementAffectedIndex(SyntaxNode innermostCommonBloc var localFunctionIdentifiers = localFunctions.Select(node => ((LocalFunctionStatementSyntax)node).Identifier.ValueText); // Find all calls to the applicable local functions within the scope. - var localFunctionCalls = innermostCommonBlock.DescendantNodes().Where(node => node is InvocationExpressionSyntax invocationExpression && - invocationExpression.Expression.GetRightmostName() != null && - !invocationExpression.Expression.IsKind(SyntaxKind.SimpleMemberAccessExpression) && - localFunctionIdentifiers.Contains(invocationExpression.Expression.GetRightmostName().Identifier.ValueText)); + var localFunctionCalls = innermostCommonBlock.DescendantNodes().Where( + node => node is InvocationExpressionSyntax invocationExpression && + invocationExpression.Expression.GetRightmostName() is { } rightmostName && + !invocationExpression.Expression.IsKind(SyntaxKind.SimpleMemberAccessExpression) && + localFunctionIdentifiers.Contains(rightmostName.Identifier.ValueText)); if (localFunctionCalls.IsEmpty()) { diff --git a/src/Features/CSharp/Portable/IntroduceVariable/CSharpIntroduceVariableService_IntroduceQueryLocal.cs b/src/Features/CSharp/Portable/IntroduceVariable/CSharpIntroduceVariableService_IntroduceQueryLocal.cs index c67f104c08359..1e2a3fa381f95 100644 --- a/src/Features/CSharp/Portable/IntroduceVariable/CSharpIntroduceVariableService_IntroduceQueryLocal.cs +++ b/src/Features/CSharp/Portable/IntroduceVariable/CSharpIntroduceVariableService_IntroduceQueryLocal.cs @@ -7,7 +7,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CSharp.Extensions; diff --git a/src/Features/CSharp/Portable/LineSeparators/CSharpLineSeparatorService.cs b/src/Features/CSharp/Portable/LineSeparators/CSharpLineSeparatorService.cs index 3c50392862f8f..d90427127b991 100644 --- a/src/Features/CSharp/Portable/LineSeparators/CSharpLineSeparatorService.cs +++ b/src/Features/CSharp/Portable/LineSeparators/CSharpLineSeparatorService.cs @@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.LineSeparators; diff --git a/src/Features/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.Features.csproj b/src/Features/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.Features.csproj index 700525f239a5b..29bad84922417 100644 --- a/src/Features/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.Features.csproj +++ b/src/Features/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.Features.csproj @@ -36,6 +36,7 @@ + diff --git a/src/Features/CSharp/Portable/MoveToNamespace/CSharpMoveToNamespaceService.cs b/src/Features/CSharp/Portable/MoveToNamespace/CSharpMoveToNamespaceService.cs index 80b69757880ca..d1bbe22782f97 100644 --- a/src/Features/CSharp/Portable/MoveToNamespace/CSharpMoveToNamespaceService.cs +++ b/src/Features/CSharp/Portable/MoveToNamespace/CSharpMoveToNamespaceService.cs @@ -7,7 +7,6 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.MoveToNamespace; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.MoveToNamespace; @@ -18,6 +17,14 @@ internal class CSharpMoveToNamespaceService( [Import(AllowDefault = true)] IMoveToNamespaceOptionsService optionsService) : AbstractMoveToNamespaceService(optionsService) { + protected override BaseTypeDeclarationSyntax? GetNamedTypeDeclarationSyntax(SyntaxNode node) + => node switch + { + BaseTypeDeclarationSyntax namedTypeDeclaration => namedTypeDeclaration, + ParameterListSyntax parameterList => parameterList.Parent as BaseTypeDeclarationSyntax, + _ => null + }; + protected override string GetNamespaceName(SyntaxNode container) => container switch { diff --git a/src/Features/CSharp/Portable/NavigateTo/CSharpNavigateToSearchService.cs b/src/Features/CSharp/Portable/NavigateTo/CSharpNavigateToSearchService.cs index 1ba731b48c9ce..bece1c625bb40 100644 --- a/src/Features/CSharp/Portable/NavigateTo/CSharpNavigateToSearchService.cs +++ b/src/Features/CSharp/Portable/NavigateTo/CSharpNavigateToSearchService.cs @@ -12,6 +12,4 @@ namespace Microsoft.CodeAnalysis.CSharp.NavigateTo; [ExportLanguageService(typeof(INavigateToSearchService), LanguageNames.CSharp), Shared] [method: ImportingConstructor] [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] -internal class CSharpNavigateToSearchService() : AbstractNavigateToSearchService -{ -} +internal sealed class CSharpNavigateToSearchService() : AbstractNavigateToSearchService; diff --git a/src/Features/CSharp/Portable/NavigationBar/CSharpNavigationBarItemService.cs b/src/Features/CSharp/Portable/NavigationBar/CSharpNavigationBarItemService.cs index bd8d73f27781c..2a05c1b82d185 100644 --- a/src/Features/CSharp/Portable/NavigationBar/CSharpNavigationBarItemService.cs +++ b/src/Features/CSharp/Portable/NavigationBar/CSharpNavigationBarItemService.cs @@ -21,7 +21,9 @@ namespace Microsoft.CodeAnalysis.CSharp.NavigationBar; [ExportLanguageService(typeof(INavigationBarItemService), LanguageNames.CSharp), Shared] -internal class CSharpNavigationBarItemService : AbstractNavigationBarItemService +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class CSharpNavigationBarItemService() : AbstractNavigationBarItemService { private static readonly SymbolDisplayFormat s_typeFormat = SymbolDisplayFormat.CSharpErrorMessageFormat.AddGenericsOptions(SymbolDisplayGenericsOptions.IncludeVariance); @@ -39,22 +41,21 @@ internal class CSharpNavigationBarItemService : AbstractNavigationBarItemService SymbolDisplayMiscellaneousOptions.AllowDefaultLiteral | SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier); - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpNavigationBarItemService() - { - } - protected override async Task> GetItemsInCurrentProcessAsync( Document document, bool supportsCodeGeneration, CancellationToken cancellationToken) { - var typesInFile = await GetTypesInFileAsync(document, cancellationToken).ConfigureAwait(false); - var tree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); - return GetMembersInTypes(document.Project.Solution, tree, typesInFile, cancellationToken); + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + using var _ = PooledHashSet.GetInstance(out var typesInFile); + + AddTypesInFile(semanticModel, typesInFile, cancellationToken); + if (cancellationToken.IsCancellationRequested) + return []; + + return GetMembersInTypes(document.Project.Solution, semanticModel.SyntaxTree, typesInFile, cancellationToken); } private static ImmutableArray GetMembersInTypes( - Solution solution, SyntaxTree tree, IEnumerable types, CancellationToken cancellationToken) + Solution solution, SyntaxTree tree, HashSet types, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.NavigationBar_ItemService_GetMembersInTypes_CSharp, cancellationToken)) { @@ -83,10 +84,15 @@ private static ImmutableArray GetMembersInTypes( memberItems.AddIfNotNull(CreateItemForMember(solution, propertySymbol, tree, cancellationToken)); memberItems.AddIfNotNull(CreateItemForMember(solution, propertySymbol.PartialImplementationPart, tree, cancellationToken)); } - else if (member is IMethodSymbol or IPropertySymbol) + else if (member is IEventSymbol { PartialImplementationPart: { } } eventSymbol) + { + memberItems.AddIfNotNull(CreateItemForMember(solution, eventSymbol, tree, cancellationToken)); + memberItems.AddIfNotNull(CreateItemForMember(solution, eventSymbol.PartialImplementationPart, tree, cancellationToken)); + } + else if (member is IMethodSymbol or IPropertySymbol or IEventSymbol) { - Debug.Assert(member is IMethodSymbol { PartialDefinitionPart: null } or IPropertySymbol { PartialDefinitionPart: null }, - $"NavBar expected GetMembers to return partial method/property definition parts but the implementation part was returned."); + Debug.Assert(member is IMethodSymbol { PartialDefinitionPart: null } or IPropertySymbol { PartialDefinitionPart: null } or IEventSymbol { PartialDefinitionPart: null }, + $"NavBar expected GetMembers to return partial method/property/event definition parts but the implementation part was returned."); memberItems.AddIfNotNull(CreateItemForMember(solution, member, tree, cancellationToken)); } @@ -120,18 +126,11 @@ private static ImmutableArray GetMembersInTypes( } } - private static async Task> GetTypesInFileAsync(Document document, CancellationToken cancellationToken) - { - var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - - return GetTypesInFile(semanticModel, cancellationToken); - } - - private static IEnumerable GetTypesInFile(SemanticModel semanticModel, CancellationToken cancellationToken) + private static void AddTypesInFile( + SemanticModel semanticModel, HashSet types, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.NavigationBar_ItemService_GetTypesInFile_CSharp, cancellationToken)) { - var types = new HashSet(); using var _ = ArrayBuilder.GetInstance(out var nodesToVisit); nodesToVisit.Push(semanticModel.SyntaxTree.GetRoot(cancellationToken)); @@ -139,36 +138,27 @@ private static IEnumerable GetTypesInFile(SemanticModel semant while (nodesToVisit.TryPop(out var node)) { if (cancellationToken.IsCancellationRequested) - return []; + return; - var type = GetType(semanticModel, node, cancellationToken); - - if (type != null) - { - types.Add((INamedTypeSymbol)type); - } + types.AddIfNotNull(GetType(semanticModel, node, cancellationToken)); if (node is BaseMethodDeclarationSyntax or - BasePropertyDeclarationSyntax or - BaseFieldDeclarationSyntax or - StatementSyntax or - ExpressionSyntax) + BasePropertyDeclarationSyntax or + BaseFieldDeclarationSyntax or + StatementSyntax or + ExpressionSyntax) { // quick bail out to prevent us from creating every nodes exist in current file continue; } foreach (var child in node.ChildNodes()) - { nodesToVisit.Push(child); - } } - - return types; } } - private static ISymbol? GetType(SemanticModel semanticModel, SyntaxNode node, CancellationToken cancellationToken) + private static INamedTypeSymbol? GetType(SemanticModel semanticModel, SyntaxNode node, CancellationToken cancellationToken) => node switch { BaseTypeDeclarationSyntax t => semanticModel.GetDeclaredSymbol(t, cancellationToken), @@ -188,7 +178,7 @@ private static bool IsAccessor(ISymbol member) return false; } - private static RoslynNavigationBarItem? CreateItemForMember( + private static SymbolItem? CreateItemForMember( Solution solution, ISymbol member, SyntaxTree tree, CancellationToken cancellationToken) { var location = GetSymbolLocation(solution, member, tree, cancellationToken); diff --git a/src/Features/CSharp/Portable/QuickInfo/CSharpSemanticQuickInfoProvider.cs b/src/Features/CSharp/Portable/QuickInfo/CSharpSemanticQuickInfoProvider.cs index 81fd490ab6f3e..96b38b78d4825 100644 --- a/src/Features/CSharp/Portable/QuickInfo/CSharpSemanticQuickInfoProvider.cs +++ b/src/Features/CSharp/Portable/QuickInfo/CSharpSemanticQuickInfoProvider.cs @@ -193,14 +193,21 @@ protected override NullableFlowState GetNullabilityAnalysis(SemanticModel semant } } - var maxLength = 1000; - var symbolStrings = symbol.DeclaringSyntaxReferences.Select(reference => + var solution = document.Project.Solution; + var declarationCode = symbol.DeclaringSyntaxReferences.Select(reference => { var span = reference.Span; - var sourceText = reference.SyntaxTree.GetText(cancellationToken); - return sourceText.GetSubText(new Text.TextSpan(span.Start, Math.Min(maxLength, span.Length))).ToString(); + var syntaxReferenceDocument = solution.GetDocument(reference.SyntaxTree); + if (syntaxReferenceDocument is not null) + { + return new OnTheFlyDocsRelevantFileInfo(syntaxReferenceDocument, span); + } + + return null; }).ToImmutableArray(); - return new OnTheFlyDocsInfo(symbol.ToDisplayString(), symbolStrings, symbol.Language, hasContentExcluded); + var additionalContext = OnTheFlyDocsUtilities.GetAdditionalOnTheFlyDocsContext(solution, symbol); + + return new OnTheFlyDocsInfo(symbol.ToDisplayString(), declarationCode, symbol.Language, hasContentExcluded, additionalContext); } } diff --git a/src/Features/CSharp/Portable/QuickInfo/OnTheFlyDocsUtilities.cs b/src/Features/CSharp/Portable/QuickInfo/OnTheFlyDocsUtilities.cs new file mode 100644 index 0000000000000..74779aebf1546 --- /dev/null +++ b/src/Features/CSharp/Portable/QuickInfo/OnTheFlyDocsUtilities.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.Collections.Immutable; +using System.Linq; +using Microsoft.CodeAnalysis.QuickInfo; +using Microsoft.CodeAnalysis.Shared.Extensions; + +namespace Microsoft.CodeAnalysis.CSharp.QuickInfo; + +internal static class OnTheFlyDocsUtilities +{ + public static ImmutableArray GetAdditionalOnTheFlyDocsContext(Solution solution, ISymbol symbol) + { + var parameters = symbol.GetParameters(); + var typeArguments = symbol.GetTypeArguments(); + + var parameterStrings = parameters.Select(parameter => + { + var typeSymbol = parameter.Type; + return GetOnTheFlyDocsRelevantFileInfo(typeSymbol); + + }).ToImmutableArray(); + + var typeArgumentStrings = typeArguments.Select(typeArgument => + { + return GetOnTheFlyDocsRelevantFileInfo(typeArgument); + + }).ToImmutableArray(); + + return parameterStrings.AddRange(typeArgumentStrings); + + OnTheFlyDocsRelevantFileInfo? GetOnTheFlyDocsRelevantFileInfo(ITypeSymbol typeSymbol) + { + var typeSyntaxReference = typeSymbol.DeclaringSyntaxReferences.FirstOrDefault(); + if (typeSyntaxReference is not null) + { + var typeSpan = typeSyntaxReference.Span; + var syntaxReferenceDocument = solution.GetDocument(typeSyntaxReference.SyntaxTree); + if (syntaxReferenceDocument is not null) + { + return new OnTheFlyDocsRelevantFileInfo(syntaxReferenceDocument, typeSpan); + } + } + + return null; + } + } +} diff --git a/src/Features/CSharp/Portable/ReplacePropertyWithMethods/CSharpReplacePropertyWithMethodsService.cs b/src/Features/CSharp/Portable/ReplacePropertyWithMethods/CSharpReplacePropertyWithMethodsService.cs index 34132c1690b07..d88cd6af1630b 100644 --- a/src/Features/CSharp/Portable/ReplacePropertyWithMethods/CSharpReplacePropertyWithMethodsService.cs +++ b/src/Features/CSharp/Portable/ReplacePropertyWithMethods/CSharpReplacePropertyWithMethodsService.cs @@ -19,7 +19,6 @@ using Microsoft.CodeAnalysis.ReplacePropertyWithMethods; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.ReplacePropertyWithMethods; @@ -36,7 +35,7 @@ public override async Task> GetReplacementMembersAsyn Document document, IPropertySymbol property, SyntaxNode propertyDeclarationNode, - IFieldSymbol propertyBackingField, + IFieldSymbol? propertyBackingField, string desiredGetMethodName, string desiredSetMethodName, CancellationToken cancellationToken) diff --git a/src/Features/CSharp/Portable/ReverseForStatement/CSharpReverseForStatementCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ReverseForStatement/CSharpReverseForStatementCodeRefactoringProvider.cs index 72870319d2bf2..058bfde4a0fe5 100644 --- a/src/Features/CSharp/Portable/ReverseForStatement/CSharpReverseForStatementCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ReverseForStatement/CSharpReverseForStatementCodeRefactoringProvider.cs @@ -15,7 +15,6 @@ using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.ReverseForStatement; diff --git a/src/Features/CSharp/Portable/SemanticSearch/CSharpSemanticSearchUtilities.cs b/src/Features/CSharp/Portable/SemanticSearch/CSharpSemanticSearchUtilities.cs index 77c6da34af215..bb4e2d8d84df3 100644 --- a/src/Features/CSharp/Portable/SemanticSearch/CSharpSemanticSearchUtilities.cs +++ b/src/Features/CSharp/Portable/SemanticSearch/CSharpSemanticSearchUtilities.cs @@ -17,7 +17,7 @@ internal sealed class CSharpSemanticSearchUtilities Query = """ static IEnumerable Find(Compilation compilation) { - return compilation.GlobalNamespace.GetMembers("C"); + return compilation.Assembly.GlobalNamespace.GetMembers("C"); } """, GlobalUsings = """ diff --git a/src/Features/CSharp/Portable/SignatureHelp/AttributeSignatureHelpProvider.cs b/src/Features/CSharp/Portable/SignatureHelp/AttributeSignatureHelpProvider.cs index edce4c3f60b11..e0b7d7707f28b 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/AttributeSignatureHelpProvider.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/AttributeSignatureHelpProvider.cs @@ -15,7 +15,6 @@ using Microsoft.CodeAnalysis.DocumentationComments; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageService; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SignatureHelp; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/CSharp/Portable/SignatureHelp/ElementAccessExpressionSignatureHelpProvider.cs b/src/Features/CSharp/Portable/SignatureHelp/ElementAccessExpressionSignatureHelpProvider.cs index 3012605327bd2..326004f333195 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/ElementAccessExpressionSignatureHelpProvider.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/ElementAccessExpressionSignatureHelpProvider.cs @@ -295,7 +295,7 @@ internal static bool IsArgumentListToken(ElementAccessExpressionSyntax expressio internal static TextSpan GetTextSpan(SyntaxToken openBracket) { Contract.ThrowIfFalse(openBracket.Parent is BracketedArgumentListSyntax && - (openBracket.Parent.Parent is ElementAccessExpressionSyntax || openBracket.Parent.Parent is ElementBindingExpressionSyntax)); + openBracket.Parent.Parent is ElementAccessExpressionSyntax or ElementBindingExpressionSyntax); return SignatureHelpUtilities.GetSignatureHelpSpan((BracketedArgumentListSyntax)openBracket.Parent); } diff --git a/src/Features/CSharp/Portable/SignatureHelp/GenericNamePartiallyWrittenSignatureHelpProvider.cs b/src/Features/CSharp/Portable/SignatureHelp/GenericNamePartiallyWrittenSignatureHelpProvider.cs index c9dea3cc7a383..3fb298ef18f9c 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/GenericNamePartiallyWrittenSignatureHelpProvider.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/GenericNamePartiallyWrittenSignatureHelpProvider.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.SignatureHelp; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.SignatureHelp; diff --git a/src/Features/CSharp/Portable/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.cs b/src/Features/CSharp/Portable/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.cs index b209718dc4d27..85709fb5dcd1d 100644 --- a/src/Features/CSharp/Portable/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.cs @@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.SimplifyTypeNames; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.SimplifyTypeNames; diff --git a/src/Features/CSharp/Portable/Snippets/CSharpSnippetIdentifiers.cs b/src/Features/CSharp/Portable/Snippets/CSharpSnippetIdentifiers.cs index 406a380e2ca8a..0631779f5892a 100644 --- a/src/Features/CSharp/Portable/Snippets/CSharpSnippetIdentifiers.cs +++ b/src/Features/CSharp/Portable/Snippets/CSharpSnippetIdentifiers.cs @@ -25,5 +25,6 @@ internal static class CSharpSnippetIdentifiers public const string StaticIntMain = "sim"; public const string Struct = "struct"; public const string StaticVoidMain = "svm"; + public const string Using = "using"; public const string While = "while"; } diff --git a/src/Features/CSharp/Portable/Snippets/CSharpUsingSnippetProvider.cs b/src/Features/CSharp/Portable/Snippets/CSharpUsingSnippetProvider.cs new file mode 100644 index 0000000000000..65f148c6f587e --- /dev/null +++ b/src/Features/CSharp/Portable/Snippets/CSharpUsingSnippetProvider.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using System.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.LanguageService; +using Microsoft.CodeAnalysis.Snippets; +using Microsoft.CodeAnalysis.Snippets.SnippetProviders; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.CSharp.Snippets; + +[ExportSnippetProvider(nameof(ISnippetProvider), LanguageNames.CSharp), Shared] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class CSharpUsingSnippetProvider() : AbstractUsingSnippetProvider +{ + public override string Identifier => CSharpSnippetIdentifiers.Using; + + public override string Description => CSharpFeaturesResources.using_statement; + + protected override ImmutableArray GetPlaceHolderLocationsList(UsingStatementSyntax node, ISyntaxFacts syntaxFacts, CancellationToken cancellationToken) + { + var expression = node.Expression!; + return [new SnippetPlaceholder(expression.ToString(), expression.SpanStart)]; + } + + protected override int GetTargetCaretPosition(UsingStatementSyntax usingStatement, SourceText sourceText) + => CSharpSnippetHelpers.GetTargetCaretPositionInBlock( + usingStatement, + static s => (BlockSyntax)s.Statement, + sourceText); + + protected override Task AddIndentationToDocumentAsync(Document document, UsingStatementSyntax usingStatement, CancellationToken cancellationToken) + => CSharpSnippetHelpers.AddBlockIndentationToDocumentAsync( + document, + usingStatement, + static s => (BlockSyntax)s.Statement, + cancellationToken); +} diff --git a/src/Features/CSharp/Portable/SolutionCrawler/CSharpDocumentDifferenceService.cs b/src/Features/CSharp/Portable/SolutionCrawler/CSharpDocumentDifferenceService.cs index 27d621f018b42..f1192c2ae8574 100644 --- a/src/Features/CSharp/Portable/SolutionCrawler/CSharpDocumentDifferenceService.cs +++ b/src/Features/CSharp/Portable/SolutionCrawler/CSharpDocumentDifferenceService.cs @@ -2,21 +2,40 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Composition; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.SolutionCrawler; +using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.CSharp.SolutionCrawler; [ExportLanguageService(typeof(IDocumentDifferenceService), LanguageNames.CSharp), Shared] -internal class CSharpDocumentDifferenceService : AbstractDocumentDifferenceService +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class CSharpDocumentDifferenceService() : AbstractDocumentDifferenceService { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpDocumentDifferenceService() + protected override bool IsContainedInMemberBody(SyntaxNode node, TextSpan span) { + switch (node) + { + case ConstructorDeclarationSyntax constructor: + return (constructor.Body != null && GetBlockBodySpan(constructor.Body).Contains(span)) || + (constructor.Initializer != null && constructor.Initializer.Span.Contains(span)); + case BaseMethodDeclarationSyntax method: + return method.Body != null && GetBlockBodySpan(method.Body).Contains(span); + case BasePropertyDeclarationSyntax property: + return property.AccessorList != null && property.AccessorList.Span.Contains(span); + case EnumMemberDeclarationSyntax @enum: + return @enum.EqualsValue != null && @enum.EqualsValue.Span.Contains(span); + case BaseFieldDeclarationSyntax field: + return field.Declaration != null && field.Declaration.Span.Contains(span); + } + + return false; } + + private static TextSpan GetBlockBodySpan(BlockSyntax body) + => TextSpan.FromBounds(body.OpenBraceToken.Span.End, body.CloseBraceToken.SpanStart); } diff --git a/src/Features/CSharp/Portable/Structure/CSharpStructureHelpers.cs b/src/Features/CSharp/Portable/Structure/CSharpStructureHelpers.cs index f32d1420cf2c7..c1d92b080d7de 100644 --- a/src/Features/CSharp/Portable/Structure/CSharpStructureHelpers.cs +++ b/src/Features/CSharp/Portable/Structure/CSharpStructureHelpers.cs @@ -8,7 +8,6 @@ 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; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/CSharp/Portable/Structure/Providers/DisabledTextTriviaStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/DisabledTextTriviaStructureProvider.cs index eaba300c303c9..ddcfbf14429c5 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/DisabledTextTriviaStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/DisabledTextTriviaStructureProvider.cs @@ -6,7 +6,6 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Structure; diff --git a/src/Features/CSharp/Portable/TaskList/CSharpTaskListService.cs b/src/Features/CSharp/Portable/TaskList/CSharpTaskListService.cs index a2489176cb857..72bd4966bbb92 100644 --- a/src/Features/CSharp/Portable/TaskList/CSharpTaskListService.cs +++ b/src/Features/CSharp/Portable/TaskList/CSharpTaskListService.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.TaskList; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.TaskList; diff --git a/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeRefactoringProvider.cs index 5edbf8a0f3448..c34dbb872552c 100644 --- a/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeRefactoringProvider.cs @@ -58,12 +58,10 @@ internal sealed class UseExpressionBodyCodeRefactoringProvider() : SyntaxEditorB public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var (document, textSpan, cancellationToken) = context; - if (textSpan.Length > 0) - return; var position = textSpan.Start; var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var node = root.FindToken(position).Parent!; + var node = root.FindNode(textSpan); var containingLambda = node.FirstAncestorOrSelf(); if (containingLambda != null && diff --git a/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeRefactoringProvider.cs index 6732298aab63c..fdca9437eb188 100644 --- a/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeRefactoringProvider.cs @@ -17,7 +17,6 @@ using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.UseExpressionBodyForLambda; diff --git a/src/Features/CSharp/Portable/Wrapping/CSharpSyntaxWrappingOptions.cs b/src/Features/CSharp/Portable/Wrapping/CSharpSyntaxWrappingOptions.cs index ad87123375a11..a5d72f246bdba 100644 --- a/src/Features/CSharp/Portable/Wrapping/CSharpSyntaxWrappingOptions.cs +++ b/src/Features/CSharp/Portable/Wrapping/CSharpSyntaxWrappingOptions.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 Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.Options; diff --git a/src/Features/CSharp/Portable/Wrapping/CSharpWrappingCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/Wrapping/CSharpWrappingCodeRefactoringProvider.cs index feaabfa4ff44d..0ea27a49fb7f7 100644 --- a/src/Features/CSharp/Portable/Wrapping/CSharpWrappingCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/Wrapping/CSharpWrappingCodeRefactoringProvider.cs @@ -5,7 +5,6 @@ using System.Collections.Immutable; using System.Composition; using System.Diagnostics.CodeAnalysis; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.CSharp.Wrapping.BinaryExpression; using Microsoft.CodeAnalysis.CSharp.Wrapping.ChainedExpression; diff --git a/src/Features/CSharp/Portable/Wrapping/SeparatedSyntaxList/CSharpCollectionExpressionWrapper.cs b/src/Features/CSharp/Portable/Wrapping/SeparatedSyntaxList/CSharpCollectionExpressionWrapper.cs index 8af4080e9b32a..e6bdc4a290f4f 100644 --- a/src/Features/CSharp/Portable/Wrapping/SeparatedSyntaxList/CSharpCollectionExpressionWrapper.cs +++ b/src/Features/CSharp/Portable/Wrapping/SeparatedSyntaxList/CSharpCollectionExpressionWrapper.cs @@ -4,7 +4,6 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Wrapping; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Wrapping.SeparatedSyntaxList; diff --git a/src/Features/CSharp/Portable/Wrapping/SeparatedSyntaxList/CSharpInitializerExpressionWrapper.cs b/src/Features/CSharp/Portable/Wrapping/SeparatedSyntaxList/CSharpInitializerExpressionWrapper.cs index 1ca87e5cf30e0..b0da25e9dafe1 100644 --- a/src/Features/CSharp/Portable/Wrapping/SeparatedSyntaxList/CSharpInitializerExpressionWrapper.cs +++ b/src/Features/CSharp/Portable/Wrapping/SeparatedSyntaxList/CSharpInitializerExpressionWrapper.cs @@ -4,7 +4,6 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Wrapping; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Wrapping.SeparatedSyntaxList; diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf index ac6530d1e2827..9afef3157d0e5 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf @@ -142,11 +142,21 @@ Změnit na přetypování + + Convert '{0}' extension methods to extension + Convert '{0}' extension methods to extension + + Convert '{0}' to record Převést {0} na záznam(record) {Locked="record"} "record" is a C# keyword and should not be localized. + + Convert all extension methods in '{0}' to extension + Convert all extension methods in '{0}' to extension + + Convert to method Převést na metodu @@ -399,7 +409,7 @@ required property - required property + požadovaná vlastnost diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf index aae32d98257c1..b896d14b72616 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf @@ -142,11 +142,21 @@ In "cast" ändern + + Convert '{0}' extension methods to extension + Convert '{0}' extension methods to extension + + Convert '{0}' to record „{0}“ in record konvertieren {Locked="record"} "record" is a C# keyword and should not be localized. + + Convert all extension methods in '{0}' to extension + Convert all extension methods in '{0}' to extension + + Convert to method In Methode konvertieren @@ -399,7 +409,7 @@ required property - required property + Erforderliche Eigenschaft diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf index fe14d989b72a2..417202d3a6169 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf @@ -142,11 +142,21 @@ Cambiar a cast + + Convert '{0}' extension methods to extension + Convert '{0}' extension methods to extension + + Convert '{0}' to record Convertir "{0}" a record {Locked="record"} "record" is a C# keyword and should not be localized. + + Convert all extension methods in '{0}' to extension + Convert all extension methods in '{0}' to extension + + Convert to method Convertir al método @@ -399,7 +409,7 @@ required property - required property + propiedad obligatoria diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf index f8d1e09858cb0..6700d2de14180 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf @@ -142,11 +142,21 @@ Changer en cast + + Convert '{0}' extension methods to extension + Convert '{0}' extension methods to extension + + Convert '{0}' to record Convertir '{0}' en record {Locked="record"} "record" is a C# keyword and should not be localized. + + Convert all extension methods in '{0}' to extension + Convert all extension methods in '{0}' to extension + + Convert to method Convertir en méthode @@ -399,7 +409,7 @@ required property - required property + propriété requise diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf index f3a49d115eb0c..6ceb62dd4c22e 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf @@ -142,11 +142,21 @@ Cambia in cast + + Convert '{0}' extension methods to extension + Convert '{0}' extension methods to extension + + Convert '{0}' to record Convertire '{0}' in record {Locked="record"} "record" is a C# keyword and should not be localized. + + Convert all extension methods in '{0}' to extension + Convert all extension methods in '{0}' to extension + + Convert to method Converti in metodo @@ -399,7 +409,7 @@ required property - required property + proprietà obbligatoria diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf index 573011e7c6c91..dab287445e7e0 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf @@ -142,11 +142,21 @@ キャストに変更 + + Convert '{0}' extension methods to extension + Convert '{0}' extension methods to extension + + Convert '{0}' to record '{0}' を record に変換 {Locked="record"} "record" is a C# keyword and should not be localized. + + Convert all extension methods in '{0}' to extension + Convert all extension methods in '{0}' to extension + + Convert to method メソッドに変換 @@ -399,7 +409,7 @@ required property - required property + 必須プロパティ diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf index ade477529e3f7..5bf806f5ab1a5 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf @@ -142,11 +142,21 @@ 캐스트로 변경 + + Convert '{0}' extension methods to extension + Convert '{0}' extension methods to extension + + Convert '{0}' to record '{0}'을(를) record로 변환 {Locked="record"} "record" is a C# keyword and should not be localized. + + Convert all extension methods in '{0}' to extension + Convert all extension methods in '{0}' to extension + + Convert to method 메서드로 변환 @@ -399,7 +409,7 @@ required property - required property + 필수 속성 diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf index 2b69c53302241..b1f1772f41097 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf @@ -142,11 +142,21 @@ Zmień na rzutowanie + + Convert '{0}' extension methods to extension + Convert '{0}' extension methods to extension + + Convert '{0}' to record Konwertuj „{0}” do record {Locked="record"} "record" is a C# keyword and should not be localized. + + Convert all extension methods in '{0}' to extension + Convert all extension methods in '{0}' to extension + + Convert to method Konwertuj na metodę @@ -399,7 +409,7 @@ required property - required property + wymagana właściwość diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf index 9ea35d3b6d8f4..ee22f0b01c7b9 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf @@ -142,11 +142,21 @@ Alterar para conversão + + Convert '{0}' extension methods to extension + Convert '{0}' extension methods to extension + + Convert '{0}' to record Converter '{0}' em record {Locked="record"} "record" is a C# keyword and should not be localized. + + Convert all extension methods in '{0}' to extension + Convert all extension methods in '{0}' to extension + + Convert to method Converter em método @@ -399,7 +409,7 @@ required property - required property + propriedade obrigatória diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf index 4b0fdd2bf1c9e..3cb08f55240d6 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf @@ -142,11 +142,21 @@ Изменить на приведение + + Convert '{0}' extension methods to extension + Convert '{0}' extension methods to extension + + Convert '{0}' to record Преобразовать "{0}" в record {Locked="record"} "record" is a C# keyword and should not be localized. + + Convert all extension methods in '{0}' to extension + Convert all extension methods in '{0}' to extension + + Convert to method Преобразовать в метод @@ -399,7 +409,7 @@ required property - required property + обязательное свойство diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf index 3a6fd3dc9de2c..05ba26db3652a 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf @@ -142,11 +142,21 @@ Tür dönüştürme olarak değiştir + + Convert '{0}' extension methods to extension + Convert '{0}' extension methods to extension + + Convert '{0}' to record '{0}'i record’a dönüştür {Locked="record"} "record" is a C# keyword and should not be localized. + + Convert all extension methods in '{0}' to extension + Convert all extension methods in '{0}' to extension + + Convert to method Yönteme dönüştür @@ -399,7 +409,7 @@ required property - required property + gerekli özellik diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf index 23eb24bf84ce9..a41c02a6819be 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf @@ -142,11 +142,21 @@ 更改为强制转换 + + Convert '{0}' extension methods to extension + Convert '{0}' extension methods to extension + + Convert '{0}' to record 将“{0}”转换为 record {Locked="record"} "record" is a C# keyword and should not be localized. + + Convert all extension methods in '{0}' to extension + Convert all extension methods in '{0}' to extension + + Convert to method 转换为方法 @@ -399,7 +409,7 @@ required property - required property + 必需属性 diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf index 0e86fa0ef137f..cec850afe8c1c 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf @@ -142,11 +142,21 @@ 變更為 'cast' + + Convert '{0}' extension methods to extension + Convert '{0}' extension methods to extension + + Convert '{0}' to record 將 '{0}' 轉換為 record {Locked="record"} "record" is a C# keyword and should not be localized. + + Convert all extension methods in '{0}' to extension + Convert all extension methods in '{0}' to extension + + Convert to method 轉換為方法 @@ -399,7 +409,7 @@ required property - required property + 必要屬性 diff --git a/src/Features/CSharpTest/ConvertAutoPropertyToFullProperty/ConvertAutoPropertyToFullPropertyTests.cs b/src/Features/CSharpTest/ConvertAutoPropertyToFullProperty/ConvertAutoPropertyToFullPropertyTests.cs index 111cea0267bfa..1884ab2379f76 100644 --- a/src/Features/CSharpTest/ConvertAutoPropertyToFullProperty/ConvertAutoPropertyToFullPropertyTests.cs +++ b/src/Features/CSharpTest/ConvertAutoPropertyToFullProperty/ConvertAutoPropertyToFullPropertyTests.cs @@ -1444,4 +1444,34 @@ public int Goo """; await TestInRegularAndScriptAsync(text, expected, options: DoNotPreferExpressionBodiedAccessors, index: 1, parseOptions: CSharp14); } + + [Theory] + [InlineData("set"), InlineData("init")] + [WorkItem("https://github.com/dotnet/roslyn/issues/76992")] + public async Task ProduceFieldBackedProperty2(string setter) + { + var text = $$""" + class TestClass + { + public int G[||]oo { get; {{setter}}; } = 0; + } + """; + var expected = $$""" + class TestClass + { + public int Goo + { + get + { + return field; + } + {{setter}} + { + field = value; + } + } = 0; + } + """; + await TestInRegularAndScriptAsync(text, expected, options: DoNotPreferExpressionBodiedAccessors, index: 1, parseOptions: CSharp14); + } } diff --git a/src/Features/CSharpTest/ConvertAutoPropertyToFullProperty/ConvertAutoPropertyToFullPropertyTests_OptionSets.cs b/src/Features/CSharpTest/ConvertAutoPropertyToFullProperty/ConvertAutoPropertyToFullPropertyTests_OptionSets.cs index 02bef89e5260f..9a986b7cd4c31 100644 --- a/src/Features/CSharpTest/ConvertAutoPropertyToFullProperty/ConvertAutoPropertyToFullPropertyTests_OptionSets.cs +++ b/src/Features/CSharpTest/ConvertAutoPropertyToFullProperty/ConvertAutoPropertyToFullPropertyTests_OptionSets.cs @@ -5,7 +5,6 @@ #nullable disable using System; -using System.Collections.Immutable; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Formatting; diff --git a/src/Features/CSharpTest/ConvertIfToSwitch/ConvertIfToSwitchTests.cs b/src/Features/CSharpTest/ConvertIfToSwitch/ConvertIfToSwitchTests.cs index 38deae0651b3c..b6740d8190d2b 100644 --- a/src/Features/CSharpTest/ConvertIfToSwitch/ConvertIfToSwitchTests.cs +++ b/src/Features/CSharpTest/ConvertIfToSwitch/ConvertIfToSwitchTests.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Testing; using Roslyn.Test.Utilities; -using Roslyn.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeActions.ConvertIfToSwitch; diff --git a/src/Features/CSharpTest/ConvertPrimaryToRegularConstructor/ConvertPrimaryToRegularConstructorTests.cs b/src/Features/CSharpTest/ConvertPrimaryToRegularConstructor/ConvertPrimaryToRegularConstructorTests.cs index 05bd85be44986..ef3e74f1460b7 100644 --- a/src/Features/CSharpTest/ConvertPrimaryToRegularConstructor/ConvertPrimaryToRegularConstructorTests.cs +++ b/src/Features/CSharpTest/ConvertPrimaryToRegularConstructor/ConvertPrimaryToRegularConstructorTests.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.ConvertPrimaryToRegularConstructor; +using Microsoft.CodeAnalysis.CSharp.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Testing; @@ -2738,4 +2739,22 @@ public Class1() LanguageVersion = LanguageVersion.CSharp12, }.RunAsync(); } + + [Fact] + public async Task TestNotOnExtension() + { + await new VerifyCS.Test + { + TestCode = """ + static class Class1 + { + [|extension(string s)|] + { + public void Goo() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } } diff --git a/src/Features/CSharpTest/ConvertToExtension/ConvertToExtensionTests.cs b/src/Features/CSharpTest/ConvertToExtension/ConvertToExtensionTests.cs new file mode 100644 index 0000000000000..694afec21e6ab --- /dev/null +++ b/src/Features/CSharpTest/ConvertToExtension/ConvertToExtensionTests.cs @@ -0,0 +1,1984 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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.ConvertToExtension; +using Microsoft.CodeAnalysis.CSharp.Shared.Extensions; +using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Testing; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.ConvertToExtension; + +using VerifyCS = CSharpCodeRefactoringVerifier; + +[UseExportProvider] +[Trait(Traits.Feature, Traits.Features.CodeActionsConvertToExtension)] +public sealed class ConvertToExtensionTests +{ + [Fact] + public async Task TestBaseCase() + { + await new VerifyCS.Test + { + TestCode = """ + static class C + { + [||]public static void M(this int i) { } + } + """, + FixedCode = """ + static class C + { + extension(int i) + { + public void M() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestRefReceiver() + { + await new VerifyCS.Test + { + TestCode = """ + static class C + { + [||]public static void M(this ref int i) { } + } + """, + FixedCode = """ + static class C + { + extension(ref int i) + { + public void M() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestInReceiver() + { + await new VerifyCS.Test + { + TestCode = """ + static class C + { + [||]public static void M(this in int i) { } + } + """, + FixedCode = """ + static class C + { + extension(in int i) + { + public void M() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestRefReadonlyReceiver() + { + await new VerifyCS.Test + { + TestCode = """ + static class C + { + [||]public static void M(this ref readonly int i) { } + } + """, + FixedCode = """ + static class C + { + extension(ref readonly int i) + { + public void M() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestNotOnCSharp13() + { + await new VerifyCS.Test + { + TestCode = """ + static class C + { + [||]public static void M(this int i) { } + } + """, + LanguageVersion = LanguageVersion.CSharp13, + }.RunAsync(); + } + + [Fact] + public async Task TestWithMultipleParameters() + { + await new VerifyCS.Test + { + TestCode = """ + static class C + { + [||]public static void M(this int i, string j) { } + } + """, + FixedCode = """ + static class C + { + extension(int i) + { + public void M(string j) { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestInsideNamespace1() + { + await new VerifyCS.Test + { + TestCode = """ + namespace N + { + static class C + { + [||]public static void M(this int i, string j) { } + } + } + """, + FixedCode = """ + namespace N + { + static class C + { + extension(int i) + { + public void M(string j) { } + } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestInsideNamespace2() + { + await new VerifyCS.Test + { + TestCode = """ + namespace N; + + static class C + { + [||]public static void M(this int i, string j) { } + } + """, + FixedCode = """ + namespace N; + + static class C + { + extension(int i) + { + public void M(string j) { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestNotWithNoParameters() + { + await new VerifyCS.Test + { + TestCode = """ + static class C + { + [||]public static void M() { } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestNotInsideStruct() + { + await new VerifyCS.Test + { + TestCode = """ + struct C + { + [||]public static void M(this int i) { } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + TestState = + { + ExpectedDiagnostics = + { + // /0/Test0.cs(1,8): error CS1106: Extension method must be defined in a non-generic static class + DiagnosticResult.CompilerError("CS1106").WithSpan(1, 8, 1, 9), + } + } + }.RunAsync(); + } + + [Fact] + public async Task TestNotInsideInstanceClass() + { + await new VerifyCS.Test + { + TestCode = """ + class C + { + [||]public static void M(this int i) { } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + TestState = + { + ExpectedDiagnostics = + { + // /0/Test0.cs(1,7): error CS1106: Extension method must be defined in a non-generic static class + DiagnosticResult.CompilerError("CS1106").WithSpan(1, 7, 1, 8), + } + } + }.RunAsync(); + } + + [Fact] + public async Task TestNotForInstanceMethod() + { + await new VerifyCS.Test + { + TestCode = """ + static class C + { + [||]public void M(this int i) { } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + TestState = + { + ExpectedDiagnostics = + { + // /0/Test0.cs(3,17): error CS0708: 'M': cannot declare instance members in a static class + DiagnosticResult.CompilerError("CS0708").WithSpan(3, 17, 3, 18).WithArguments("M"), + // /0/Test0.cs(3,17): error CS1105: Extension method must be static + DiagnosticResult.CompilerError("CS1105").WithSpan(3, 17, 3, 18), + } + } + }.RunAsync(); + } + + [Fact] + public async Task TestNotForNestedClass() + { + await new VerifyCS.Test + { + TestCode = """ + static class Outer + { + static class C + { + [||]public void M(this int i) { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + TestState = + { + ExpectedDiagnostics = + { + // /0/Test0.cs(5,21): error CS0708: 'M': cannot declare instance members in a static class + DiagnosticResult.CompilerError("CS0708").WithSpan(5, 21, 5, 22).WithArguments("M"), + // /0/Test0.cs(5,21): error CS1109: Extension methods must be defined in a top level static class; C is a nested class + DiagnosticResult.CompilerError("CS1109").WithSpan(5, 21, 5, 22).WithArguments("C"), + } + } + }.RunAsync(); + } + + [Fact] + public async Task TestWithReferencedTypeParameterInOrder1() + { + await new VerifyCS.Test + { + TestCode = """ + using System.Collections.Generic; + + static class C + { + [||]public static void M(this IList list) { } + } + """, + FixedCode = """ + using System.Collections.Generic; + + static class C + { + extension(IList list) + { + public void M() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestWithReferencedTypeParameterInOrder2() + { + await new VerifyCS.Test + { + TestCode = """ + using System.Collections.Generic; + + static class C + { + [||]public static void M(this IDictionary map) { } + } + """, + FixedCode = """ + using System.Collections.Generic; + + static class C + { + extension(IDictionary map) + { + public void M() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestWithReferencedTypeParameterInOrder3() + { + await new VerifyCS.Test + { + TestCode = """ + using System.Collections.Generic; + + static class C + { + [||]public static void M(this IDictionary map) { } + } + """, + FixedCode = """ + using System.Collections.Generic; + + static class C + { + extension(IDictionary map) + { + public void M() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestWithReferencedTypeParameterInOrder4() + { + await new VerifyCS.Test + { + TestCode = """ + using System.Collections.Generic; + + static class C + { + [||]public static void M(this IList list) { } + } + """, + FixedCode = """ + using System.Collections.Generic; + + static class C + { + extension(IList list) + { + public void M() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestWithReferencedTypeParameterNotInOrder1() + { + await new VerifyCS.Test + { + TestCode = """ + using System.Collections.Generic; + + static class C + { + [||]public static void M(this IList list) { } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping1() + { + await new VerifyCS.Test + { + TestCode = """ + static class C + { + [||]public static void M(this int i) { } + public static void N(this int i) { } + } + """, + FixedCode = """ + static class C + { + extension(int i) + { + public void M() { } + public void N() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping1_A() + { + await new VerifyCS.Test + { + TestCode = """ + static class C + { + public static void M(this int i) { } + [||]public static void N(this int i) { } + } + """, + FixedCode = """ + static class C + { + extension(int i) + { + public void M() { } + public void N() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping2() + { + await new VerifyCS.Test + { + TestCode = """ + static class C + { + [||]public static void M(this int i) { } + public static void N(this int i, string s) { } + } + """, + FixedCode = """ + static class C + { + extension(int i) + { + public void M() { } + public void N(string s) { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping2_A() + { + await new VerifyCS.Test + { + TestCode = """ + static class C + { + public static void M(this int i) { } + [||]public static void N(this int i, string s) { } + } + """, + FixedCode = """ + static class C + { + extension(int i) + { + public void M() { } + public void N(string s) { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_MatchingAttributes1() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + + class XAttribute : Attribute { } + + static class C + { + public static void M([X] this int i) { } + [||]public static void N([X] this int i) { } + } + """, + FixedCode = """ + using System; + + class XAttribute : Attribute { } + + static class C + { + extension([X] int i) + { + public void M() { } + public void N() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_MatchingAttributes2() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + + class XAttribute : Attribute { } + + static class C + { + public static void M([X] this int i) { } + [||]public static void N([XAttribute] this int i) { } + } + """, + FixedCode = """ + using System; + + class XAttribute : Attribute { } + + static class C + { + extension([X] int i) + { + public void M() { } + public void N() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_MatchingAttributes3() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + + class XAttribute : Attribute + { + public XAttribute(int i) { } + } + + static class C + { + public static void M([X(0)] this int i) { } + [||]public static void N([X(0)] this int i) { } + } + """, + FixedCode = """ + using System; + + class XAttribute : Attribute + { + public XAttribute(int i) { } + } + + static class C + { + extension([X(0)] int i) + { + public void M() { } + public void N() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_MatchingAttributes4() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + + class XAttribute : Attribute + { + public int I; + } + + static class C + { + public static void M([X(I=1)] this int i) { } + [||]public static void N([X(I=1)] this int i) { } + } + """, + FixedCode = """ + using System; + + class XAttribute : Attribute + { + public int I; + } + + static class C + { + extension([X(I = 1)] int i) + { + public void M() { } + public void N() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_NonMatchingAttributes1() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + + class XAttribute : Attribute { } + + static class C + { + public static void M([X] this int i) { } + [||]public static void N(this int i) { } + } + """, + FixedCode = """ + using System; + + class XAttribute : Attribute { } + + static class C + { + public static void M([X] this int i) { } + extension(int i) + { + public void N() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_NonMatchingAttributes2() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + + class XAttribute : Attribute { } + class YAttribute : Attribute { } + + static class C + { + public static void M([X] this int i) { } + [||]public static void N([Y] this int i) { } + } + """, + FixedCode = """ + using System; + + class XAttribute : Attribute { } + class YAttribute : Attribute { } + + static class C + { + public static void M([X] this int i) { } + extension([Y] int i) + { + public void N() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_NonMatchingAttributes3() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + + class XAttribute : Attribute + { + public XAttribute(int i) { } + } + + static class C + { + public static void M([X(0)] this int i) { } + [||]public static void N([X(1)] this int i) { } + } + """, + FixedCode = """ + using System; + + class XAttribute : Attribute + { + public XAttribute(int i) { } + } + + static class C + { + public static void M([X(0)] this int i) { } + extension([X(1)] int i) + { + public void N() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_NonMatchingAttributes4() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + + class XAttribute : Attribute + { + public int I; + } + + static class C + { + public static void M([X(I=1)] this int i) { } + [||]public static void N([X(I=2)] this int i) { } + } + """, + FixedCode = """ + using System; + + class XAttribute : Attribute + { + public int I; + } + + static class C + { + public static void M([X(I=1)] this int i) { } + extension([X(I = 2)] int i) + { + public void N() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_UnrelatedAttributes() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + + class XAttribute : Attribute { } + class YAttribute : Attribute { } + + static class C + { + public static void M(this int i, [X] string s) { } + [||]public static void N(this int i, [Y] string s) { } + } + """, + FixedCode = """ + using System; + + class XAttribute : Attribute { } + class YAttribute : Attribute { } + + static class C + { + extension(int i) + { + public void M([X] string s) { } + public void N([Y] string s) { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_TypeParameters1() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + using System.Collections.Generic; + + class XAttribute : Attribute { } + class YAttribute : Attribute { } + + static class C + { + [||]public static void M(this IList list) { } + public static void N(this IList list) { } + } + """, + FixedCode = """ + using System; + using System.Collections.Generic; + + class XAttribute : Attribute { } + class YAttribute : Attribute { } + + static class C + { + extension(IList list) + { + public void M() { } + public void N() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_TypeParameters_DifferentName() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + using System.Collections.Generic; + + class XAttribute : Attribute { } + class YAttribute : Attribute { } + + static class C + { + [||]public static void M(this IList list) { } + public static void N(this IList list) { } + } + """, + FixedCode = """ + using System; + using System.Collections.Generic; + + class XAttribute : Attribute { } + class YAttribute : Attribute { } + + static class C + { + extension(IList list) + { + public void M() { } + } + + public static void N(this IList list) { } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_TypeParameters_SameAttributes() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + using System.Collections.Generic; + + class XAttribute : Attribute { } + class YAttribute : Attribute { } + + static class C + { + [||]public static void M([X] this IList list) { } + public static void N([X] this IList list) { } + } + """, + FixedCode = """ + using System; + using System.Collections.Generic; + + class XAttribute : Attribute { } + class YAttribute : Attribute { } + + static class C + { + extension([X] IList list) + { + public void M() { } + public void N() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_TypeParameters_DifferentAttributes() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + using System.Collections.Generic; + + class XAttribute : Attribute { } + class YAttribute : Attribute { } + + static class C + { + [||]public static void M([X] this IList list) { } + public static void N([Y] this IList list) { } + } + """, + FixedCode = """ + using System; + using System.Collections.Generic; + + class XAttribute : Attribute { } + class YAttribute : Attribute { } + + static class C + { + extension([X] IList list) + { + public void M() { } + } + + public static void N([Y] this IList list) { } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_TypeParameters_SameConstructorConstraint() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + using System.Collections.Generic; + + static class C + { + [||]public static void M(this IList list) where T : new() { } + public static void N(this IList list) where T : new() { } + } + """, + FixedCode = """ + using System; + using System.Collections.Generic; + + static class C + { + extension(IList list) where T : new() + { + public void M() { } + public void N() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_TypeParameters_DifferentConstructorConstraint() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + using System.Collections.Generic; + + static class C + { + [||]public static void M(this IList list) where T : new() { } + public static void N(this IList list) { } + } + """, + FixedCode = """ + using System; + using System.Collections.Generic; + + static class C + { + extension(IList list) where T : new() + { + public void M() { } + } + + public static void N(this IList list) { } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_TypeParameters_SameClassConstraint() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + using System.Collections.Generic; + + static class C + { + [||]public static void M(this IList list) where T : class { } + public static void N(this IList list) where T : class { } + } + """, + FixedCode = """ + using System; + using System.Collections.Generic; + + static class C + { + extension(IList list) where T : class + { + public void M() { } + public void N() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_TypeParameters_DifferentClassConstraint() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + using System.Collections.Generic; + + static class C + { + [||]public static void M(this IList list) where T : class { } + public static void N(this IList list) { } + } + """, + FixedCode = """ + using System; + using System.Collections.Generic; + + static class C + { + extension(IList list) where T : class + { + public void M() { } + } + + public static void N(this IList list) { } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_TypeParameters_SameTypeConstraint() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + using System.Collections.Generic; + + static class C + { + [||]public static void M(this IList list) where T : IList { } + public static void N(this IList list) where T : IList { } + } + """, + FixedCode = """ + using System; + using System.Collections.Generic; + + static class C + { + extension(IList list) where T : IList + { + public void M() { } + public void N() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_TypeParameters_DifferentTypeConstraint() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + using System.Collections.Generic; + + static class C + { + [||]public static void M(this IList list) where T : IList { } + public static void N(this IList list) { } + } + """, + FixedCode = """ + using System; + using System.Collections.Generic; + + static class C + { + extension(IList list) where T : IList + { + public void M() { } + } + + public static void N(this IList list) { } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_Parameters_SameParameterRef() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + using System.Collections.Generic; + + static class C + { + [||]public static void M(this ref int i) { } + public static void N(this ref int i) { } + } + """, + FixedCode = """ + using System; + using System.Collections.Generic; + + static class C + { + extension(ref int i) + { + public void M() { } + public void N() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_Parameters_DifferentParameterRef() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + using System.Collections.Generic; + + static class C + { + [||]public static void M(this ref int i) { } + public static void N(this int i) { } + } + """, + FixedCode = """ + using System; + using System.Collections.Generic; + + static class C + { + extension(ref int i) + { + public void M() { } + } + + public static void N(this int i) { } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_Parameters_SameParameterName() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + using System.Collections.Generic; + + static class C + { + [||]public static void M(this int i) { } + public static void N(this int i) { } + } + """, + FixedCode = """ + using System; + using System.Collections.Generic; + + static class C + { + extension(int i) + { + public void M() { } + public void N() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_Parameters_DifferentParameterName() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + using System.Collections.Generic; + + static class C + { + [||]public static void M(this int i) { } + public static void N(this int j) { } + } + """, + FixedCode = """ + using System; + using System.Collections.Generic; + + static class C + { + extension(int i) + { + public void M() { } + } + + public static void N(this int j) { } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_Parameters_SameParameterTupleNames() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + using System.Collections.Generic; + + static class C + { + [||]public static void M(this (int i, int j) i) { } + public static void N(this (int i, int j) i) { } + } + """, + FixedCode = """ + using System; + using System.Collections.Generic; + + static class C + { + extension((int i, int j) i) + { + public void M() { } + public void N() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_Parameters_DifferentParameterTupleNames() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + using System.Collections.Generic; + + static class C + { + [||]public static void M(this (int i, int j) i) { } + public static void N(this (int k, int l) i) { } + } + """, + FixedCode = """ + using System; + using System.Collections.Generic; + + static class C + { + extension((int i, int j) i) + { + public void M() { } + } + + public static void N(this (int k, int l) i) { } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_Parameters_SameParameterNullability() + { + await new VerifyCS.Test + { + TestCode = """ + #nullable enable + + using System; + using System.Collections.Generic; + + static class C + { + [||]public static void M(this string? i) { } + public static void N(this string? i) { } + } + """, + FixedCode = """ + #nullable enable + + using System; + using System.Collections.Generic; + + static class C + { + extension(string? i) + { + public void M() { } + public void N() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_Parameters_DifferentParameterNullability() + { + await new VerifyCS.Test + { + TestCode = """ + #nullable enable + + using System; + using System.Collections.Generic; + + static class C + { + [||]public static void M(this string? i) { } + public static void N(this string i) { } + } + """, + FixedCode = """ + #nullable enable + + using System; + using System.Collections.Generic; + + static class C + { + extension(string? i) + { + public void M() { } + } + + public static void N(this string i) { } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_Parameters_SameParameterDynamic() + { + await new VerifyCS.Test + { + TestCode = """ + #nullable enable + + using System; + using System.Collections.Generic; + + static class C + { + [||]public static void M(this {|CS1103:dynamic|} i) { } + public static void N(this {|CS1103:dynamic|} i) { } + } + """, + FixedCode = """ + #nullable enable + + using System; + using System.Collections.Generic; + + static class C + { + extension(dynamic i) + { + public void M() { } + public void N() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestSimpleGrouping_Parameters_DifferentDynamic() + { + await new VerifyCS.Test + { + TestCode = """ + #nullable enable + + using System; + using System.Collections.Generic; + + static class C + { + [||]public static void M(this {|CS1103:dynamic|} i) { } + public static void N(this object i) { } + } + """, + FixedCode = """ + #nullable enable + + using System; + using System.Collections.Generic; + + static class C + { + extension(dynamic i) + { + public void M() { } + } + + public static void N(this object i) { } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestTriviaMove1() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + using System.Collections.Generic; + + static class C + { + public static void M(this int i) { } + + [||]public static void N(this int j) { } + } + """, + FixedCode = """ + using System; + using System.Collections.Generic; + + static class C + { + public static void M(this int i) { } + + extension(int j) + { + public void N() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestTriviaMove2() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + using System.Collections.Generic; + + static class C + { + public static void M(this int i) { } + + /// + [||]public static void N(this int j) { } + } + """, + FixedCode = """ + using System; + using System.Collections.Generic; + + static class C + { + public static void M(this int i) { } + + extension(int j) + { + /// + public void N() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestGroupingWithNonExtension1() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + using System.Collections.Generic; + + static class C + { + public static void O() { } + + public static void M(this int i) { } + + [||]public static void N(this int i) { } + } + """, + FixedCode = """ + using System; + using System.Collections.Generic; + + static class C + { + public static void O() { } + + extension(int i) + { + public void M() { } + + public void N() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestGroupingWithNonExtension2() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + using System.Collections.Generic; + + static class C + { + public static void M(this int i) { } + + public static void O() { } + + [||]public static void N(this int i) { } + } + """, + FixedCode = """ + using System; + using System.Collections.Generic; + + static class C + { + extension(int i) + { + public void M() { } + + public void N() { } + } + + public static void O() { } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestGroupingWithNonExtension3() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + using System.Collections.Generic; + + static class C + { + public static void M(this int i) { } + + [||]public static void N(this int i) { } + + public static void O() { } + } + """, + FixedCode = """ + using System; + using System.Collections.Generic; + + static class C + { + extension(int i) + { + public void M() { } + + public void N() { } + } + + public static void O() { } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestFixClass1() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + using System.Collections.Generic; + + [||]static class C + { + public static void M(this int i) { } + + public static void N(this int i) { } + + public static void O(this int j) { } + + public static void P(this int j) { } + } + """, + FixedCode = """ + using System; + using System.Collections.Generic; + + static class C + { + extension(int i) + { + public void M() { } + + public void N() { } + } + + extension(int j) + { + public void O() { } + + public void P() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestFixClass2() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + using System.Collections.Generic; + + [||]static class C + { + public static void M(this int i) { } + + public static void O(this int j) { } + + public static void N(this int i) { } + + public static void P(this int j) { } + } + """, + FixedCode = """ + using System; + using System.Collections.Generic; + + static class C + { + extension(int i) + { + public void M() { } + + public void N() { } + } + + extension(int j) + { + public void O() { } + + public void P() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestCodeBody1() + { + await new VerifyCS.Test + { + TestCode = """ + static class C + { + [||]public static void M(this int i) + { + return; + } + } + """, + FixedCode = """ + static class C + { + extension(int i) + { + public void M() + { + return; + } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestCodeBody2() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + + static class C + { + [||]public static DateTime M(this int i) + { + return new() + { + }; + } + } + """, + FixedCode = """ + using System; + + static class C + { + extension(int i) + { + public DateTime M() + { + return new() + { + }; + } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestMultipleConstraints1() + { + await new VerifyCS.Test + { + TestCode = """ + using System.Collections.Generic; + + static class C + { + [||]public static void M(this IDictionary map) where K : struct where V : class { } + } + """, + FixedCode = """ + using System.Collections.Generic; + + static class C + { + extension(IDictionary map) + where K : struct + where V : class + { + public void M() { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } + + [Fact] + public async Task TestMultipleConstraints2() + { + await new VerifyCS.Test + { + TestCode = """ + using System.Collections.Generic; + + static class C + { + [||]public static void M(this IList map) where K : struct where V : class { } + } + """, + FixedCode = """ + using System.Collections.Generic; + + static class C + { + extension(IList map) where K : struct + { + public void M() where V : class { } + } + } + """, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + }.RunAsync(); + } +} diff --git a/src/Features/CSharpTest/ConvertToInterpolatedString/ConvertPlaceholderToInterpolatedStringTests.cs b/src/Features/CSharpTest/ConvertToInterpolatedString/ConvertPlaceholderToInterpolatedStringTests.cs index f91442f8ca011..394d5834bb4e9 100644 --- a/src/Features/CSharpTest/ConvertToInterpolatedString/ConvertPlaceholderToInterpolatedStringTests.cs +++ b/src/Features/CSharpTest/ConvertToInterpolatedString/ConvertPlaceholderToInterpolatedStringTests.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeRefactorings; @@ -15,12 +16,12 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ConvertToInterpolatedString; [Trait(Traits.Feature, Traits.Features.CodeActionsConvertToInterpolatedString)] -public class ConvertPlaceholderToInterpolatedStringTests : AbstractCSharpCodeActionTest_NoEditor +public sealed class ConvertPlaceholderToInterpolatedStringTests : AbstractCSharpCodeActionTest_NoEditor { protected override CodeRefactoringProvider CreateCodeRefactoringProvider(TestWorkspace workspace, TestParameters parameters) => new CSharpConvertPlaceholderToInterpolatedStringRefactoringProvider(); - private static readonly string[] CompositeFormattedMethods = + private static readonly ImmutableArray CompositeFormattedMethods = [ "Console.Write", "Console.WriteLine", @@ -81,8 +82,7 @@ static string MakeFormattedParameters(int numberOfParameters) } } - [Theory] - [MemberData(nameof(InvocationData))] + [Theory, MemberData(nameof(InvocationData))] public async Task TestInvocationSubstitution(string before, string after) { await TestInRegularAndScriptAsync( @@ -1187,4 +1187,37 @@ void M() } """); } + + [Theory, MemberData(nameof(InvocationData))] + [WorkItem("https://github.com/dotnet/roslyn/issues/68469")] + public async Task TestInvocationSubstitution_FixAll(string before, string after) + { + await TestInRegularAndScriptAsync( + $$""" + using System; + using System.Diagnostics; + + class T + { + void M() + { + {|FixAllInDocument:{{before}}|}; + {{before}}; + } + } + """, + $$""" + using System; + using System.Diagnostics; + + class T + { + void M() + { + {{after}}; + {{after}}; + } + } + """); + } } diff --git a/src/Features/CSharpTest/ConvertTupleToStruct/ConvertTupleToStructTests.cs b/src/Features/CSharpTest/ConvertTupleToStruct/ConvertTupleToStructTests.cs index 1740fbf5968e0..b86e7d85ac73d 100644 --- a/src/Features/CSharpTest/ConvertTupleToStruct/ConvertTupleToStructTests.cs +++ b/src/Features/CSharpTest/ConvertTupleToStruct/ConvertTupleToStructTests.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Immutable; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.ConvertTupleToStruct; diff --git a/src/Features/CSharpTest/Copilot/CSharpImplementNotImplementedExceptionDiagnosticAnalyzerTests.cs b/src/Features/CSharpTest/Copilot/CSharpImplementNotImplementedExceptionDiagnosticAnalyzerTests.cs new file mode 100644 index 0000000000000..6874fc59461ca --- /dev/null +++ b/src/Features/CSharpTest/Copilot/CSharpImplementNotImplementedExceptionDiagnosticAnalyzerTests.cs @@ -0,0 +1,455 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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.Editor.UnitTests.CodeActions; +using Microsoft.CodeAnalysis.Testing; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.Copilot.UnitTests; + +using VerifyCS = CSharpCodeFixVerifier< + CSharpImplementNotImplementedExceptionDiagnosticAnalyzer, + EmptyCodeFixProvider>; + +public sealed class CSharpImplementNotImplementedExceptionDiagnosticAnalyzerTests +{ + [Fact] + public async Task TestThrowNotImplementedExceptionInStatement() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + + class C + { + void {|IDE3000:M|}() + { + {|IDE3000:throw new NotImplementedException();|} + } + } + """, + LanguageVersion = LanguageVersion.CSharp11, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, + }.RunAsync(); + } + + [Fact] + public async Task TestThrowNotImplementedExceptionInExpression() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + + class C + { + int P => {|IDE3000:throw new NotImplementedException()|}; + } + """, + LanguageVersion = LanguageVersion.CSharp11, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, + }.RunAsync(); + } + + [Fact] + public async Task TestThrowNotImplementedExceptionInConstructor() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + + class C + { + public {|IDE3000:C|}() + { + {|IDE3000:throw new NotImplementedException();|} + } + } + """, + LanguageVersion = LanguageVersion.CSharp11, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, + }.RunAsync(); + } + + [Fact] + public async Task TestThrowNotImplementedExceptionInDestructor() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + + class C + { + ~{|IDE3000:C|}() + { + {|IDE3000:throw new NotImplementedException();|} + } + } + """, + LanguageVersion = LanguageVersion.CSharp11, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, + }.RunAsync(); + } + + [Fact] + public async Task TestThrowNotImplementedExceptionInIndexer() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + + class C + { + public int this[int index] + { + {|IDE3000:get|} { {|IDE3000:throw new NotImplementedException();|} } + {|IDE3000:set|} { {|IDE3000:throw new NotImplementedException();|} } + } + } + """, + LanguageVersion = LanguageVersion.CSharp11, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, + }.RunAsync(); + } + + [Fact] + public async Task TestThrowNotImplementedExceptionInEvent() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + + class C + { + public event EventHandler MyEvent + { + {|IDE3000:add|} { {|IDE3000:throw new NotImplementedException();|} } + {|IDE3000:remove|} { {|IDE3000:throw new NotImplementedException();|} } + } + } + """, + LanguageVersion = LanguageVersion.CSharp11, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, + }.RunAsync(); + } + + [Fact] + public async Task TestThrowNotImplementedExceptionInOperator() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + + class C + { + public static C operator {|IDE3000:+|}(C a, C b) + { + {|IDE3000:throw new NotImplementedException();|} + } + } + """, + LanguageVersion = LanguageVersion.CSharp11, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, + }.RunAsync(); + } + + [Fact] + public async Task TestDifferentFlavorsOfThrowNotImplementedException() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + + class C + { + void {|IDE3000:M1|}() + { + {|IDE3000:throw new NotImplementedException("Not implemented");|} + } + + void {|IDE3000:M1WithComment|}() + { + // Some comment + {|IDE3000:throw new NotImplementedException("Not implemented");|} + } + + void {|IDE3000:M2|}() + { + {|IDE3000:throw new NotImplementedException("Not implemented");|} + } + + int P1 + { + {|IDE3000:get|} { {|IDE3000:throw new NotImplementedException();|} } + } + + int P2 + { + {|IDE3000:get|} { {|IDE3000:throw new NotImplementedException();|} } + {|IDE3000:set|} { {|IDE3000:throw new NotImplementedException();|} } + } + + int this[int index] + { + {|IDE3000:get|} { {|IDE3000:throw new NotImplementedException();|} } + {|IDE3000:set|} { {|IDE3000:throw new NotImplementedException();|} } + } + + int P11 + { + {|IDE3000:get|} { {|IDE3000:throw new NotImplementedException();|} /*I am a comment*/ } + } + + void {|IDE3000:M6|}() + { + {|IDE3000:throw new NotImplementedException();|} + } + + void {|IDE3000:M7|}() + { + {|IDE3000:throw new NotImplementedException("Not implemented");|} + } + + public double {|IDE3000:CalculateSquareRoot|}(double number) => {|IDE3000:throw new NotImplementedException("CalculateSquareRoot method not implemented")|}; + + internal void ThrowOnAllStatements(bool condition) + { + {|IDE3000:throw new NotImplementedException("Not implemented");|} + {|IDE3000:throw new NotImplementedException("Not implemented");|} + } + } + """, + LanguageVersion = LanguageVersion.CSharp11, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, + }.RunAsync(); + } + + [Fact] + public async Task WhenShouldNotReportOnMember() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + class C + { + private string _name; + public string Name + { + get => _name; + set => _name = value ?? {|IDE3000:throw new NotImplementedException()|}; + } + + void LambdaThrowWithFunc() + { + Func func = () => {|IDE3000:throw new NotImplementedException()|}; + func(); + } + + void LambdaThrow() + { + Action action = () => {|IDE3000:throw new NotImplementedException()|}; + action(); + } + + void AnonymousMethodThrow() + { + Action action = delegate + { + {|IDE3000:throw new NotImplementedException();|} + }; + action(); + } + + void LocalFunctionThrow() + { + void Local() + { + {|IDE3000:throw new NotImplementedException();|} + } + + Local(); + } + + void NestedBlockThrow() + { + if (true) + { + {|IDE3000:throw new NotImplementedException();|} + } + } + + void LoopThrow() + { + for (int i = 0; i < 10; i++) + { + {|IDE3000:throw new NotImplementedException();|} + } + } + + public int GetValue(string type) => + type switch + { + "A" => 1, + "B" => 2, + _ => {|IDE3000:throw new NotImplementedException($"Type '{type}' not implemented")|} + }; + + void UsingThrow() + { + using (var resource = new System.IO.MemoryStream()) + { + {|IDE3000:throw new NotImplementedException();|} + } + } + + void TryCatchThrow() + { + try + { + // Some code + } + catch (Exception) + { + {|IDE3000:throw new NotImplementedException();|} + } + } + + void LockThrow() + { + lock (new object()) + { + {|IDE3000:throw new NotImplementedException();|} + } + } + + void TernaryThrow(bool condition) + { + var result = condition ? 1 : {|IDE3000:throw new NotImplementedException()|}; + } + + void AnonymousTypeWithLambdaThrow() + { + var result = new { Value = (Func)(() => {|IDE3000:throw new NotImplementedException()|}) }; + } + + void LinqThrow() + { + var result = new[] { 1, 2, 3 }.Select(x => x > 0 ? x : {|IDE3000:throw new NotImplementedException()|}); + } + + public int[] ComplexQuery() + { + return new[] { 1, 2, 3 } + .Where(x => x > 0) + .Select(x => x * 2) + .Where(x => x > 0 ? true : {|IDE3000:throw new NotImplementedException()|}) + .ToArray(); + } + + public void ProcessData(List data) + { + var result = data.Select(item => item switch + { + string s => s.ToUpper(), + int i => i.ToString(), + DateTime d => d.ToShortDateString(), + _ => {|IDE3000:throw new NotImplementedException("Unsupported data type")|} + }); + } + + internal Person CreatePerson(string name, int age) + { + return new Person + { + Name = name ?? {|IDE3000:throw new NotImplementedException("Name cannot be null")|}, + Age = age < 0 ? {|IDE3000:throw new NotImplementedException("Age must be positive")|} : age, + Skills = new() { "C#", "F#" } + }; + } + + public void ProcessWithLocalMethod(string input) + { + string ParseInput(string text) + { + return text?.Length > 5 ? text : {|IDE3000:throw new NotImplementedException("Input too short")|}; + } + } + + public Func GetCalculator(string operation) + { + return operation switch + { + "square" => x => x * x, + "double" => x => x * 2, + _ => {|IDE3000:throw new NotImplementedException($"Operation {operation} not implemented")|} + }; + } + + public void ProcessWithNestedDelegates() + { + Func> createOperation = x => + y => x > 0 ? x + y : {|IDE3000:throw new NotImplementedException("Negative values not implemented")|}; + } + + public async Task GetPersonAsync(int id) + { + var supervisor = id > 100 + ? new Person { Name = "Manager" } + : {|IDE3000:throw new NotImplementedException("Non-manager employees not implemented")|}; + + return supervisor; + } + + void SwitchThrow(int value) + { + switch (value) + { + case 1: + {|IDE3000:throw new NotImplementedException();|} + } + } + + internal void WontReportOnMemberWhenThrowIsNotDirect(bool condition) + { + var result = condition ? 1 : {|IDE3000:throw new NotImplementedException()|}; + + {|IDE3000:throw new NotImplementedException("Not implemented");|} + } + + internal void WontReportOnMemberWhenNonThrowStatementsExist(bool condition) + { + Console.WriteLine(condition ? 1 : 0); + + {|IDE3000:throw new NotImplementedException("Not implemented");|} + } + + internal class Person + { + public string Name { get; set; } + public int Age { get; set; } + public List Skills { get; set; } + public Person Supervisor { get; set; } + } + } + """, + LanguageVersion = LanguageVersion.CSharp11, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, + }.RunAsync(); + } +} diff --git a/src/Features/CSharpTest/Copilot/CSharpImplementNotImplementedExceptionFixProviderTests.CodeBlockSuggestions.cs b/src/Features/CSharpTest/Copilot/CSharpImplementNotImplementedExceptionFixProviderTests.CodeBlockSuggestions.cs new file mode 100644 index 0000000000000..b88a61aba1639 --- /dev/null +++ b/src/Features/CSharpTest/Copilot/CSharpImplementNotImplementedExceptionFixProviderTests.CodeBlockSuggestions.cs @@ -0,0 +1,189 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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 Microsoft.CodeAnalysis.Testing; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.Copilot.UnitTests; + +[Trait(Traits.Feature, Traits.Features.CopilotImplementNotImplementedException)] +public sealed partial class CSharpImplementNotImplementedExceptionFixProviderTests +{ + public static IEnumerable TestMethodCodeBlockSuggestions() + { + foreach (var kvp in s_codeBlockSuggestions) + { + var notImplementedMember = kvp.Key; + var codeBlocks = kvp.Value; + foreach (var codeBlock in codeBlocks) + { + yield return new object[] { notImplementedMember, codeBlock }; + } + } + } + + [Theory] + [MemberData(nameof(TestMethodCodeBlockSuggestions))] + public async Task FixerResponse_ReplacesCodeBlockCorrectly(string notImplementedCodeBlock, string replacementCodeBlock) + { + await new CustomCompositionCSharpTest + { + CodeFixTestBehaviors = CodeFixTestBehaviors.FixOne | CodeFixTestBehaviors.SkipLocalDiagnosticCheck, + TestCode = $$""" +using System; +using System.Threading.Tasks; + +public class TestService +{ + {{notImplementedCodeBlock}} +} +""", + FixedCode = $$""" +using System; +using System.Threading.Tasks; + +public class TestService +{ + {{replacementCodeBlock}} +} +""", + LanguageVersion = LanguageVersion.CSharp11, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, + } + .WithMockCopilotService(copilotService => + { + copilotService.PrepareUsingSingleFakeResult = new() + { + ReplacementNode = SyntaxFactory.ParseMemberDeclaration(replacementCodeBlock), + }; + }) + .RunAsync(); + } + + private static readonly Dictionary s_codeBlockSuggestions = new() + { + // Single statement with NotImplementedException + [ + @"public void {|IDE3000:TestMethod|}() + { + {|IDE3000:throw new NotImplementedException();|} + }" + ] = + [ + @"public void TestMethod() => Console.WriteLine(""Hello, World!"");", + @"public void TestMethod() + { + Console.WriteLine(""This is a single statement""); + }", + @"public void TestMethod() + { + int x = 10; + int y = 20; + Console.WriteLine(x + y); + }", + @"public void TestMethod() + { + /* Comment before */ + Console.WriteLine(""First line""); + /* Comment after */ + Console.WriteLine(""Second line""); + }", + @"public void TestMethod() + { + // Initialize variables + int a = 5; + int b = 10; + // Perform calculation + int result = a + b; + Console.WriteLine(result); + }", + @"public void TestMethod() + { + var list = new int[] { 1, 2, 3, 4, 5 }; + foreach (var item in list) + { + Console.WriteLine(item); + } + }", + @"public void TestMethod() + { + try + { + // Try block + Console.WriteLine(""This is a test method.""); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + }", + @"public void TestMethod() + { + if (DateTime.Now.DayOfWeek == DayOfWeek.Friday) + { + Console.WriteLine(""It's Friday!""); + } + else + { + Console.WriteLine(""It's not Friday.""); + } + }", + @"public void TestMethod() + { + Console.WriteLine(""Start""); // Comment at the end + }", + @"public void TestMethod() + { + /* Multi-line comment at the beginning */ + Console.WriteLine(""Middle""); + }", + @"public void TestMethod() + { + Console.WriteLine(""End""); /* Multi-line comment at the end */ + }", + @"public void TestMethod() + { + // Single-line comment at the beginning + Console.WriteLine(""Middle""); + }", + @"public void TestMethod() + { + Console.WriteLine(""End""); // Single-line comment at the end + }", + @"public void TestMethod() + { + Console.WriteLine(""Hi""); + throw new InvalidOperationException(); + }" + ], + // Async method with NotImplementedException + [ + @"public async Task {|IDE3000:TestMethodAsync|}() + { + {|IDE3000:throw new NotImplementedException();|} + }" + ] = + [ + @"public async Task TestMethodAsync() + { + await Task.Delay(1000); + Console.WriteLine(""Async operation completed""); + }", + @"public async Task TestMethodAsync() + => await Task.Run(() => Console.WriteLine(""Running async task""));" + ], + // Property with NotImplementedException in expression-bodied member + [ + @"public int TestProperty => {|IDE3000:throw new NotImplementedException()|};" + ] = + [ + @"public int TestProperty => 42;", + @"public int TestProperty + => DateTime.Now.Year;" + ] + }; +} diff --git a/src/Features/CSharpTest/Copilot/CSharpImplementNotImplementedExceptionFixProviderTests.cs b/src/Features/CSharpTest/Copilot/CSharpImplementNotImplementedExceptionFixProviderTests.cs new file mode 100644 index 0000000000000..5dbab97724c98 --- /dev/null +++ b/src/Features/CSharpTest/Copilot/CSharpImplementNotImplementedExceptionFixProviderTests.cs @@ -0,0 +1,718 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation 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.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Copilot; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.DocumentationComments; +using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; +using Microsoft.CodeAnalysis.FindSymbols; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.QuickInfo; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis.Text; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.Copilot.UnitTests; + +using VerifyCS = CSharpCodeFixVerifier< + CSharpImplementNotImplementedExceptionDiagnosticAnalyzer, + CSharpImplementNotImplementedExceptionFixProvider>; + +[UseExportProvider] +[Trait(Traits.Feature, Traits.Features.CopilotImplementNotImplementedException)] +public sealed partial class CSharpImplementNotImplementedExceptionFixProviderTests +{ + [Fact] + public async Task FixAll_ParseSuccessfully() + { + await new CustomCompositionCSharpTest + { + CodeFixTestBehaviors = CodeFixTestBehaviors.SkipLocalDiagnosticCheck, + TestCode = """ + using System; + using System.Threading.Tasks; + using System.Linq; + + public class MathService : IMathService + { + public int {|IDE3000:Add|}(int a, int b) + { + {|IDE3000:throw new NotImplementedException("Add method not implemented");|} + } + + public int {|IDE3000:Subtract|}(int a, int b) => {|IDE3000:throw new NotImplementedException("Subtract method not implemented")|}; + + public int {|IDE3000:Multiply|}(int a, int b) { + {|IDE3000:throw new NotImplementedException("Multiply method not implemented");|} + } + + public double {|IDE3000:Divide|}(int a, int b) + { + {|IDE3000:throw new NotImplementedException("Divide method not implemented");|} + } + + public double {|IDE3000:CalculateSquareRoot|}(double number) => {|IDE3000:throw new NotImplementedException("CalculateSquareRoot method not implemented")|}; + + public int {|IDE3000:Factorial|}(int number) + { + {|IDE3000:throw new NotImplementedException("Factorial method not implemented");|} + } + + public int ConstantValue => {|IDE3000:throw new NotImplementedException("Property not implemented")|}; + + public {|IDE3000:MathService|}() + { + {|IDE3000:throw new NotImplementedException("Constructor not implemented");|} + } + + ~{|IDE3000:MathService|}() + { + {|IDE3000:throw new NotImplementedException("Destructor not implemented");|} + } + + public event EventHandler MyEvent + { + {|IDE3000:add|} { {|IDE3000:throw new NotImplementedException("Event add not implemented");|} } + {|IDE3000:remove|} { {|IDE3000:throw new NotImplementedException("Event remove not implemented");|} } + } + + public static MathService operator {|IDE3000:+|}(MathService a, MathService b) + { + {|IDE3000:throw new NotImplementedException("Operator not implemented");|} + } + } + + public interface IMathService + { + int Add(int a, int b); + int Subtract(int a, int b); + int Multiply(int a, int b); + double Divide(int a, int b); + double CalculateSquareRoot(double number); + int Factorial(int number); + int ConstantValue { get; } + event EventHandler MyEvent; + } + """, + FixedCode = """ + using System; + using System.Threading.Tasks; + using System.Linq; + + public class MathService : IMathService + { + public int Add(int a, int b) + { + return a + b; + } + + public int Subtract(int a, int b) => a - b; + + public int Multiply(int a, int b) + { + return a * b; + } + + public double Divide(int a, int b) + { + if (b == 0) throw new DivideByZeroException("Division by zero is not allowed"); + return (double)a / b; + } + + public double CalculateSquareRoot(double number) => Math.Sqrt(number); + + public int Factorial(int number) + { + if (number < 0) throw new ArgumentException("Number must be non-negative", nameof(number)); + return number == 0 ? 1 : number * Factorial(number - 1); + } + + public int ConstantValue => 42; + + public MathService() + { + // Constructor implementation + } + + ~MathService() + { + // Destructor implementation + } + + public event EventHandler MyEvent + { + add { /* Event add implementation */ } + remove { /* Event remove implementation */ } + } + + public static MathService operator +(MathService a, MathService b) + { + return new MathService(); // Operator implementation + } + } + + public interface IMathService + { + int Add(int a, int b); + int Subtract(int a, int b); + int Multiply(int a, int b); + double Divide(int a, int b); + double CalculateSquareRoot(double number); + int Factorial(int number); + int ConstantValue { get; } + event EventHandler MyEvent; + } + """, + LanguageVersion = LanguageVersion.CSharp11, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, + } + .WithMockCopilotService(copilotService => + { + copilotService.SetupFixAll = (Document document, ImmutableDictionary> memberReferences, CancellationToken cancellationToken) => + { + // Create a map of method/property implementations + var implementationMap = new Dictionary + { + ["Add"] = "public int Add(int a, int b)\n{\n return a + b;\n}\n", + ["Subtract"] = "public int Subtract(int a, int b) => a - b;\n", + ["Multiply"] = "public int Multiply(int a, int b)\n{\n return a * b;\n}\n", + ["Divide"] = "public double Divide(int a, int b)\n{\n if (b == 0) throw new DivideByZeroException(\"Division by zero is not allowed\");\n return (double)a / b;\n}\n", + ["CalculateSquareRoot"] = "public double CalculateSquareRoot(double number) => Math.Sqrt(number);\n", + ["Factorial"] = "public int Factorial(int number)\n{\n if (number < 0) throw new ArgumentException(\"Number must be non-negative\", nameof(number));\n return number == 0 ? 1 : number * Factorial(number - 1);\n}\n", + ["ConstantValue"] = "public int ConstantValue => 42;\n", + ["MathService"] = "public MathService()\n{\n // Constructor implementation\n}\n", + ["~MathService"] = "~MathService()\n{\n // Destructor implementation\n}\n", + ["MyEvent"] = "public event EventHandler MyEvent\n{\n add { /* Event add implementation */ }\n remove { /* Event remove implementation */ }\n}\n", + ["operator +"] = "public static MathService operator +(MathService a, MathService b)\n{\n return new MathService(); // Operator implementation\n}\n", + }; + return BuildResult(memberReferences, implementationMap); + }; + }) + .RunAsync(); + } + + [Theory] + [InlineData("Failed to receive implementation from Copilot service")] + [InlineData("Generated implementation doesn't match the original method signature.")] + [InlineData("The generated implementation isn't a valid method or property.")] + public async Task NullReplacementNode_MethodHasCommentsInVariousForms_PrintsMessageAsComment(string copilotErrorMessage) + { + await new CustomCompositionCSharpTest + { + CodeFixTestBehaviors = CodeFixTestBehaviors.FixOne | CodeFixTestBehaviors.SkipLocalDiagnosticCheck, + TestCode = """ + using System; + using System.Threading.Tasks; + + public class DataService : IDataService + { + public void {|IDE3000:AddData|}(string data) + { + {|IDE3000:throw new NotImplementedException("AddData method not implemented");|} + } + + public string {|IDE3000:GetData|}(int id) => {|IDE3000:throw new NotImplementedException()|}; + + /* Updates the data for a given ID */ + public void UpdateData(int id, string data) + { + if (id <= 0) throw new ArgumentException("ID must be greater than zero", nameof(id)); + {|IDE3000:throw new NotImplementedException("UpdateData method not implemented");|} + } + + // Deletes data by ID + public void DeleteData(int id) + { + if (id <= 0) throw new ArgumentException("ID must be greater than zero", nameof(id)); + {|IDE3000:throw new NotImplementedException();|} + } + + /// + /// Saves changes asynchronously + /// + /// A task representing the save operation + public Task {|IDE3000:SaveChangesAsync|}() + { + {|IDE3000:throw new NotImplementedException("SaveChangesAsync method not implemented");|} + } + + public int DataCount => {|IDE3000:throw new NotImplementedException("Property not implemented")|}; + } + + public interface IDataService + { + void AddData(string data); + string GetData(int id); + void UpdateData(int id, string data); + void DeleteData(int id); + Task SaveChangesAsync(); + int DataCount { get; } + } + """, + FixedCode = $$""" + using System; + using System.Threading.Tasks; + + public class DataService : IDataService + { + /* {{copilotErrorMessage}} */ + public void {|IDE3000:AddData|}(string data) + { + {|IDE3000:throw new NotImplementedException("AddData method not implemented");|} + } + + public string {|IDE3000:GetData|}(int id) => {|IDE3000:throw new NotImplementedException()|}; + + /* Updates the data for a given ID */ + public void UpdateData(int id, string data) + { + if (id <= 0) throw new ArgumentException("ID must be greater than zero", nameof(id)); + {|IDE3000:throw new NotImplementedException("UpdateData method not implemented");|} + } + + // Deletes data by ID + public void DeleteData(int id) + { + if (id <= 0) throw new ArgumentException("ID must be greater than zero", nameof(id)); + {|IDE3000:throw new NotImplementedException();|} + } + + /// + /// Saves changes asynchronously + /// + /// A task representing the save operation + public Task {|IDE3000:SaveChangesAsync|}() + { + {|IDE3000:throw new NotImplementedException("SaveChangesAsync method not implemented");|} + } + + public int DataCount => {|IDE3000:throw new NotImplementedException("Property not implemented")|}; + } + + public interface IDataService + { + void AddData(string data); + string GetData(int id); + void UpdateData(int id, string data); + void DeleteData(int id); + Task SaveChangesAsync(); + int DataCount { get; } + } + """, + BatchFixedCode = $$""" + using System; + using System.Threading.Tasks; + + public class DataService : IDataService + { + /* {{copilotErrorMessage}} */ + public void {|IDE3000:AddData|}(string data) + { + {|IDE3000:throw new NotImplementedException("AddData method not implemented");|} + } + + /* {{copilotErrorMessage}} */ + public string {|IDE3000:GetData|}(int id) => {|IDE3000:throw new NotImplementedException()|}; + + /* Updates the data for a given ID */ + /* {{copilotErrorMessage}} */ + public void UpdateData(int id, string data) + { + if (id <= 0) throw new ArgumentException("ID must be greater than zero", nameof(id)); + {|IDE3000:throw new NotImplementedException("UpdateData method not implemented");|} + } + + // Deletes data by ID + /* {{copilotErrorMessage}} */ + public void DeleteData(int id) + { + if (id <= 0) throw new ArgumentException("ID must be greater than zero", nameof(id)); + {|IDE3000:throw new NotImplementedException();|} + } + + /* {{copilotErrorMessage}} */ + /// + /// Saves changes asynchronously + /// + /// A task representing the save operation + public Task {|IDE3000:SaveChangesAsync|}() + { + {|IDE3000:throw new NotImplementedException("SaveChangesAsync method not implemented");|} + } + + /* {{copilotErrorMessage}} */ + public int DataCount => {|IDE3000:throw new NotImplementedException("Property not implemented")|}; + } + + public interface IDataService + { + void AddData(string data); + string GetData(int id); + void UpdateData(int id, string data); + void DeleteData(int id); + Task SaveChangesAsync(); + int DataCount { get; } + } + """, + FixedState = + { + MarkupHandling = MarkupMode.Allow, + }, + BatchFixedState = + { + MarkupHandling = MarkupMode.Allow, + }, + LanguageVersion = LanguageVersion.CSharp11, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, + } + .WithMockCopilotService(copilotService => + { + copilotService.PrepareUsingSingleFakeResult = new() + { + ReplacementNode = null, + Message = copilotErrorMessage, + }; + }) + .RunAsync(); + } + + [Fact] + public async Task HandleInvalidCode_SuggestsAsComment() + { + await new CustomCompositionCSharpTest + { + CodeFixTestBehaviors = CodeFixTestBehaviors.FixOne | CodeFixTestBehaviors.SkipLocalDiagnosticCheck, + TestCode = """ + using System; + + class C + { + void {|IDE3000:M|}() + { + {|IDE3000:throw new NotImplementedException();|} + } + } + """, + FixedCode = """ + using System; + + class C + { + /* The generated implementation isn't a valid method or property: + using System; + class C + { + void M() + { + throw new NotImplementedException(); + } + } */ + void {|IDE3000:M|}() + { + {|IDE3000:throw new NotImplementedException();|} + } + } + """, + FixedState = + { + MarkupHandling = MarkupMode.Allow, + }, + LanguageVersion = LanguageVersion.CSharp11, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, + } + .WithMockCopilotService(copilotService => + { + var replacement = """ + using System; + class C + { + void M() + { + throw new NotImplementedException(); + } + } + """; + copilotService.PrepareUsingSingleFakeResult = new() + { + ReplacementNode = SyntaxFactory.ParseCompilationUnit(replacement), + Message = $"The generated implementation isn't a valid method or property:{Environment.NewLine}{replacement}", + }; + }) + .RunAsync(); + } + + [Fact] + public async Task ReplacementNode_Null_NotifiesWithComment() + { + await TestHandlesInvalidReplacementNode( + new() + { + ReplacementNode = null, + Message = "Custom Error Message", + }); + } + + [Theory] + [InlineData("class MyClass { }", typeof(ClassDeclarationSyntax))] + [InlineData("struct MyStruct { }", typeof(StructDeclarationSyntax))] + [InlineData("interface IMyInterface { }", typeof(InterfaceDeclarationSyntax))] + [InlineData("enum MyEnum { Value1, Value2 }", typeof(EnumDeclarationSyntax))] + [InlineData("delegate void MyDelegate();", typeof(DelegateDeclarationSyntax))] + [InlineData("int myField;", typeof(FieldDeclarationSyntax))] + [InlineData("event EventHandler MyEvent;", typeof(EventFieldDeclarationSyntax))] + [InlineData("record MyRecord { }", typeof(RecordDeclarationSyntax))] + public async Task TestInvalidNodeReplacement(string syntax, Type type) + { + await TestHandlesInvalidReplacementNode( + new() + { + ReplacementNode = SyntaxFactory.ParseMemberDeclaration(syntax), + Message = $"Copilot response is of type {type}, but expected method or property", + }) + .ConfigureAwait(false); + } + + [Theory] + [InlineData(" ")] + [InlineData("")] + public async Task TestHandlesEmptyReplacementNode(string emptyReplacement) + { + await TestHandlesInvalidReplacementNode( + new() + { + ReplacementNode = SyntaxFactory.ParseMemberDeclaration(emptyReplacement), + Message = "Custom Error Message", + }) + .ConfigureAwait(false); + } + + private static async Task TestHandlesInvalidReplacementNode(ImplementationDetails implementationDetails) + { + Assumes.False(string.IsNullOrWhiteSpace(implementationDetails.Message)); + await new CustomCompositionCSharpTest + { + CodeFixTestBehaviors = CodeFixTestBehaviors.FixOne | CodeFixTestBehaviors.SkipLocalDiagnosticCheck, + TestCode = """ + using System; + + class C + { + void {|IDE3000:M|}() + { + {|IDE3000:throw new NotImplementedException();|} + } + } + """, + FixedCode = $$""" + using System; + + class C + { + /* {{implementationDetails.Message}} */ + void {|IDE3000:M|}() + { + {|IDE3000:throw new NotImplementedException();|} + } + } + """, + FixedState = + { + MarkupHandling = MarkupMode.Allow, + }, + LanguageVersion = LanguageVersion.CSharp11, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, + } + .WithMockCopilotService(copilotService => + { + copilotService.PrepareUsingSingleFakeResult = implementationDetails; + }) + .RunAsync(); + } + + private static ImmutableDictionary BuildResult(ImmutableDictionary> memberReferences, Dictionary implementationMap) + { + // Process each member reference and create implementation details + var resultsBuilder = ImmutableDictionary.CreateBuilder(); + foreach (var memberReference in memberReferences) + { + var memberNode = memberReference.Key; + + // Get the identifier based on node type + var identifier = memberNode switch + { + MethodDeclarationSyntax method => method.Identifier.Text, + PropertyDeclarationSyntax property => property.Identifier.Text, + ConstructorDeclarationSyntax constructor => constructor.Identifier.Text, + DestructorDeclarationSyntax destructor => destructor.TildeToken.Text + destructor.Identifier.Text, + EventDeclarationSyntax @event => @event.Identifier.Text, + OperatorDeclarationSyntax @operator => "operator " + @operator.OperatorToken.Text, + _ => string.Empty + }; + + // Look up implementation in our map + Assumes.True(implementationMap.TryGetValue(identifier, out var implementation)); + resultsBuilder.Add( + memberNode, + new ImplementationDetails + { + ReplacementNode = SyntaxFactory.ParseMemberDeclaration(implementation), + }); + } + + return resultsBuilder.ToImmutable(); + } + + private class CustomCompositionCSharpTest : VerifyCS.Test + { + private TestComposition? _testComposition; + private TestWorkspace? _testWorkspace; + private Action? _copilotServiceSetupAction; + + protected override Task CreateWorkspaceImplAsync() + { + _testComposition = FeaturesTestCompositions.Features + .AddParts([typeof(TestCopilotOptionsService), typeof(TestCopilotCodeAnalysisService)]); + _testWorkspace = new TestWorkspace(_testComposition); + + // Trigger the action if it's set + _copilotServiceSetupAction?.Invoke(GetCopilotService(_testWorkspace)); + return Task.FromResult(_testWorkspace); + } + + public CustomCompositionCSharpTest WithMockCopilotService(Action setup) + { + _copilotServiceSetupAction = setup; + + // If _testWorkspace is already set, trigger the action immediately + if (_testWorkspace != null) + { + setup(GetCopilotService(_testWorkspace)); + } + + return this; + } + + private static TestCopilotCodeAnalysisService GetCopilotService(TestWorkspace testWorkspace) + { + var copilotService = testWorkspace.Services.GetLanguageServices(LanguageNames.CSharp) + .GetRequiredService() as TestCopilotCodeAnalysisService; + Assert.NotNull(copilotService); + return copilotService; + } + } + + [ExportLanguageService(typeof(ICopilotOptionsService), LanguageNames.CSharp), Shared, PartNotDiscoverable] + private sealed class TestCopilotOptionsService : ICopilotOptionsService + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public TestCopilotOptionsService() { } + + public Task IsRefineOptionEnabledAsync() + => Task.FromResult(true); + + public Task IsCodeAnalysisOptionEnabledAsync() + => Task.FromResult(true); + + public Task IsOnTheFlyDocsOptionEnabledAsync() + => Task.FromResult(true); + + public Task IsGenerateDocumentationCommentOptionEnabledAsync() + => Task.FromResult(true); + + public Task IsImplementNotImplementedExceptionEnabledAsync() + => Task.FromResult(true); + } + + [ExportLanguageService(typeof(ICopilotCodeAnalysisService), LanguageNames.CSharp), Shared, PartNotDiscoverable] + private sealed class TestCopilotCodeAnalysisService : ICopilotCodeAnalysisService + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public TestCopilotCodeAnalysisService() + { + } + + public Func>, CancellationToken, ImmutableDictionary>? SetupFixAll { get; internal set; } + + public ImplementationDetails? PrepareUsingSingleFakeResult { get; internal set; } + + public Task AnalyzeDocumentAsync(Document document, TextSpan? span, string promptTitle, CancellationToken cancellationToken) + => throw new NotImplementedException(); + + public Task> GetAvailablePromptTitlesAsync(Document document, CancellationToken cancellationToken) + => throw new NotImplementedException(); + + public Task> GetCachedDocumentDiagnosticsAsync(Document document, TextSpan? span, ImmutableArray promptTitles, CancellationToken cancellationToken) + => throw new NotImplementedException(); + + public Task<(string responseString, bool isQuotaExceeded)> GetOnTheFlyDocsAsync(string symbolSignature, ImmutableArray declarationCode, string language, CancellationToken cancellationToken) + => throw new NotImplementedException(); + + public Task IsAvailableAsync(CancellationToken cancellationToken) + => Task.FromResult(true); + + public Task IsFileExcludedAsync(string filePath, CancellationToken cancellationToken) + => throw new NotImplementedException(); + + public Task StartRefinementSessionAsync(Document oldDocument, Document newDocument, Diagnostic? primaryDiagnostic, CancellationToken cancellationToken) + => throw new NotImplementedException(); + + Task<(Dictionary? responseDictionary, bool isQuotaExceeded)> ICopilotCodeAnalysisService.GetDocumentationCommentAsync(DocumentationCommentProposal proposal, CancellationToken cancellationToken) + => throw new NotImplementedException(); + + public Task> ImplementNotImplementedExceptionsAsync( + Document document, + ImmutableDictionary> methodOrProperties, + CancellationToken cancellationToken) + { + if (SetupFixAll != null) + { + return Task.FromResult(SetupFixAll.Invoke(document, methodOrProperties, cancellationToken)); + } + + if (PrepareUsingSingleFakeResult != null) + { + return Task.FromResult(CreateSingleNodeResult(methodOrProperties, PrepareUsingSingleFakeResult)); + } + + return Task.FromResult(ImmutableDictionary.Empty); + } + + private static ImmutableDictionary CreateSingleNodeResult( + ImmutableDictionary> methodOrProperties, + ImplementationDetails implementationDetails) + { + var resultsBuilder = ImmutableDictionary.CreateBuilder(); + foreach (var methodOrProperty in methodOrProperties) + { + resultsBuilder.Add(methodOrProperty.Key, implementationDetails); + } + + return resultsBuilder.ToImmutable(); + } + + public Task IsImplementNotImplementedExceptionsAvailableAsync(CancellationToken cancellationToken) + { + return Task.FromResult(true); + } + + public Task GetOnTheFlyDocsPromptAsync(OnTheFlyDocsInfo onTheFlyDocsInfo, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task<(string responseString, bool isQuotaExceeded)> GetOnTheFlyDocsResponseAsync(string prompt, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Features/CSharpTest/Diagnostics/Suppression/SuppressionTests.cs b/src/Features/CSharpTest/Diagnostics/Suppression/SuppressionTests.cs index 7d9906343d41b..10a161b802860 100644 --- a/src/Features/CSharpTest/Diagnostics/Suppression/SuppressionTests.cs +++ b/src/Features/CSharpTest/Diagnostics/Suppression/SuppressionTests.cs @@ -446,8 +446,7 @@ void Method() var analyzerReference = new AnalyzerImageReference([new CSharpCompilerDiagnosticAnalyzer()]); workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); - var diagnosticService = Assert.IsType(workspace.ExportProvider.GetExportedValue()); - var incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace); + var diagnosticService = workspace.ExportProvider.GetExportedValue(); var suppressionProvider = CreateDiagnosticProviderAndFixer(workspace).Item2; var suppressionProviderFactory = new Lazy(() => suppressionProvider, new CodeChangeProviderMetadata("SuppressionProvider", languages: [LanguageNames.CSharp])); diff --git a/src/Features/CSharpTest/EditAndContinue/Helpers/EditingTestBase.cs b/src/Features/CSharpTest/EditAndContinue/Helpers/EditingTestBase.cs index 778bff54e0d09..8bacb6566843e 100644 --- a/src/Features/CSharpTest/EditAndContinue/Helpers/EditingTestBase.cs +++ b/src/Features/CSharpTest/EditAndContinue/Helpers/EditingTestBase.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using Microsoft.CodeAnalysis.Contracts.EditAndContinue; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; @@ -14,10 +13,8 @@ using Microsoft.CodeAnalysis.EditAndContinue; using Microsoft.CodeAnalysis.EditAndContinue.UnitTests; using Microsoft.CodeAnalysis.Emit; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.EditAndContinue.UnitTests; diff --git a/src/Features/CSharpTest/EditAndContinue/LineEditTests.cs b/src/Features/CSharpTest/EditAndContinue/LineEditTests.cs index df93a862ec0f0..30fed39210f06 100644 --- a/src/Features/CSharpTest/EditAndContinue/LineEditTests.cs +++ b/src/Features/CSharpTest/EditAndContinue/LineEditTests.cs @@ -6,7 +6,6 @@ #pragma warning disable IDE0055 // Collection expression formatting using System; -using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis.CSharp.UnitTests; using Microsoft.CodeAnalysis.EditAndContinue; diff --git a/src/Features/CSharpTest/EditAndContinue/SyntaxComparerTests.cs b/src/Features/CSharpTest/EditAndContinue/SyntaxComparerTests.cs index 2be0c587ea5d7..7be8051114b13 100644 --- a/src/Features/CSharpTest/EditAndContinue/SyntaxComparerTests.cs +++ b/src/Features/CSharpTest/EditAndContinue/SyntaxComparerTests.cs @@ -5,7 +5,6 @@ #nullable disable using System; -using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis.Differencing; using Microsoft.CodeAnalysis.Test.Utilities; diff --git a/src/Features/CSharpTest/EditAndContinue/TopLevelEditingTests.cs b/src/Features/CSharpTest/EditAndContinue/TopLevelEditingTests.cs index c71f29a688aa4..ee295a7dc131d 100644 --- a/src/Features/CSharpTest/EditAndContinue/TopLevelEditingTests.cs +++ b/src/Features/CSharpTest/EditAndContinue/TopLevelEditingTests.cs @@ -10257,6 +10257,17 @@ public void Method_Partial_DeleteImplementation() ]); } + [Fact] + public void Method_Partial_DeleteDefinition() + { + var src1 = "partial class C { partial void F(); }"; + var src2 = "partial class C { }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifySemantics(); + } + [Fact] public void Method_Partial_DeleteBoth() { @@ -10269,8 +10280,7 @@ public void Method_Partial_DeleteBoth() EditAndContinueValidation.VerifySemantics( [GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2)], [ - DocumentResults( - semanticEdits: [SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.F").PartialImplementationPart, deletedSymbolContainerProvider: c => c.GetMember("C"), partialType: "C")]), + DocumentResults(), DocumentResults( semanticEdits: [SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.F").PartialImplementationPart, deletedSymbolContainerProvider: c => c.GetMember("C"), partialType: "C")]), ]); @@ -11830,11 +11840,7 @@ public void Constructor_Parameter_Insert_Primary_Record_WithCustomDeconstructor_ SemanticEdit(SemanticEditKind.Delete, c => c.GetPrimaryConstructor("C"), deletedSymbolContainerProvider: c => c.GetMember("C")), SemanticEdit(SemanticEditKind.Insert, c => c.GetPrimaryConstructor("C")), ]), - DocumentResults( - semanticEdits: - [ - SemanticEdit(SemanticEditKind.Delete, c => c.GetPrimaryDeconstructor("C").PartialImplementationPart, deletedSymbolContainerProvider: c => c.GetMember("C"), partialType: "C"), - ]), + DocumentResults(), ], capabilities: EditAndContinueCapabilities.AddMethodToExistingType | EditAndContinueCapabilities.AddInstanceFieldToExistingType); } @@ -19301,12 +19307,7 @@ public void Property_Partial_DeleteBoth() 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(), DocumentResults( semanticEdits: [ diff --git a/src/Features/CSharpTest/FullyQualify/FullyQualifyTests.cs b/src/Features/CSharpTest/FullyQualify/FullyQualifyTests.cs index 0f78f87fde8ce..8439430ace568 100644 --- a/src/Features/CSharpTest/FullyQualify/FullyQualifyTests.cs +++ b/src/Features/CSharpTest/FullyQualify/FullyQualifyTests.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.CSharp.CodeFixes.FullyQualify; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Remote.Testing; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; diff --git a/src/Features/CSharpTest/IntroduceVariable/IntroduceVariableTests.cs b/src/Features/CSharpTest/IntroduceVariable/IntroduceVariableTests.cs index d373fe07a0bfb..da2c5e4fc8822 100644 --- a/src/Features/CSharpTest/IntroduceVariable/IntroduceVariableTests.cs +++ b/src/Features/CSharpTest/IntroduceVariable/IntroduceVariableTests.cs @@ -4334,7 +4334,7 @@ public T this[int i] } [Fact] - public async Task TestIntroduceLocalWithTargetTypedNew() + public async Task TestIntroduceLocalWithTargetTypedNew1() { var code = """ @@ -4375,12 +4375,103 @@ private class Numbers {} } """; - OptionsCollection optionsCollection = new(GetLanguage()) + await TestInRegularAndScriptAsync(code, expected, options: new(GetLanguage()) { { CSharpCodeStyleOptions.ImplicitObjectCreationWhenTypeIsApparent, new CodeStyleOption2(true, NotificationOption2.Warning) }, - }; + }); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/77276")] + public async Task TestIntroduceLocalWithTargetTypedNew2() + { + var code = + """ + public static class Demo + { + public static void Test() + { + Console.WriteLine([|new Class1 { Value = 123 }|]); + } + } + + public sealed class Class1 + { + public int Value { get; set; } + } + """; + + var expected = + """ + public static class Demo + { + public static void Test() + { + Class1 {|Rename:class1|} = new() { Value = 123 }; + Console.WriteLine(class1); + } + } + + public sealed class Class1 + { + public int Value { get; set; } + } + """; + + await TestInRegularAndScriptAsync(code, expected, options: new(GetLanguage()) + { + { CSharpCodeStyleOptions.ImplicitObjectCreationWhenTypeIsApparent, new CodeStyleOption2(true, NotificationOption2.Warning) }, + }); + } - await TestInRegularAndScriptAsync(code, expected, options: optionsCollection); + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/77428")] + public async Task TestIntroduceLocalWithTargetTypedNew1_CSharp8() + { + var code = + """ + using System; + class SampleType + { + public SampleType() + { + int sum = Sum([|new Numbers()|]); + } + + private int Sum(Numbers numbers) + { + return 42; + } + + private class Numbers {} + } + """; + + var expected = + """ + using System; + class SampleType + { + public SampleType() + { + Numbers {|Rename:numbers|} = new Numbers(); + int sum = Sum(numbers); + } + + private int Sum(Numbers numbers) + { + return 42; + } + + private class Numbers {} + } + """; + + await TestInRegularAndScriptAsync( + code, expected, + parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp8), + options: new(GetLanguage()) + { + { CSharpCodeStyleOptions.ImplicitObjectCreationWhenTypeIsApparent, new CodeStyleOption2(true, NotificationOption2.Warning) }, + }); } [Fact] diff --git a/src/Features/CSharpTest/SemanticSearch/CSharpSemanticSearchServiceTests.cs b/src/Features/CSharpTest/SemanticSearch/CSharpSemanticSearchServiceTests.cs index 20eb7b1fecda7..3765e7675d292 100644 --- a/src/Features/CSharpTest/SemanticSearch/CSharpSemanticSearchServiceTests.cs +++ b/src/Features/CSharpTest/SemanticSearch/CSharpSemanticSearchServiceTests.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.IO; using System.Linq; +using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Classification; @@ -42,24 +43,31 @@ private static string InspectLine(int position, string text) private static string Inspect(UserCodeExceptionInfo info, string query) => $"{info.ProjectDisplayName}: {info.Span} '{InspectLine(info.Span.Start, query)}': {info.TypeName.JoinText()}: '{info.Message}'"; - [ConditionalFact(typeof(CoreClrOnly))] - public async Task SimpleQuery() - { - using var workspace = TestWorkspace.Create(""" - - - - namespace N + private static string DefaultWorkspaceXml => """ + + + + using System; + + namespace N + { + public class C { - public partial class C - { - public void VisibleMethod() { } - } + public int F = 1; + public void VisibleMethod(int param) { } + public int P { get; } + public event Action E; } - - - - """, composition: FeaturesTestCompositions.Features); + } + + + + """; + + [ConditionalFact(typeof(CoreClrOnly))] + public async Task CompilationQuery() + { + using var workspace = TestWorkspace.Create(DefaultWorkspaceXml, composition: FeaturesTestCompositions.Features); var solution = workspace.CurrentSolution; @@ -83,20 +91,183 @@ static IEnumerable Find(Compilation compilation) AssertEx.Equal(["namespace N"], results.Select(Inspect)); } + [ConditionalFact(typeof(CoreClrOnly))] + public async Task NamespaceQuery() + { + using var workspace = TestWorkspace.Create(DefaultWorkspaceXml, composition: FeaturesTestCompositions.Features); + + var solution = workspace.CurrentSolution; + + var service = solution.Services.GetRequiredLanguageService(LanguageNames.CSharp); + + var query = """ + static IEnumerable Find(INamespaceSymbol n) + { + return n.GetMembers("C"); + } + """; + + var results = new List(); + var observer = new MockSemanticSearchResultsObserver() { OnDefinitionFoundImpl = results.Add }; + var traceSource = new TraceSource("test"); + + var options = workspace.GlobalOptions.GetClassificationOptionsProvider(); + var result = await service.ExecuteQueryAsync(solution, query, s_referenceAssembliesDir, observer, options, traceSource, CancellationToken.None); + + Assert.Null(result.ErrorMessage); + AssertEx.Equal(["class C"], results.Select(Inspect)); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public async Task NamedTypeQuery() + { + using var workspace = TestWorkspace.Create(DefaultWorkspaceXml, composition: FeaturesTestCompositions.Features); + + var solution = workspace.CurrentSolution; + + var service = solution.Services.GetRequiredLanguageService(LanguageNames.CSharp); + + var query = """ + static IEnumerable Find(INamedTypeSymbol type) + { + return type.GetMembers("F"); + } + """; + + var results = new List(); + var observer = new MockSemanticSearchResultsObserver() { OnDefinitionFoundImpl = results.Add }; + var traceSource = new TraceSource("test"); + + var options = workspace.GlobalOptions.GetClassificationOptionsProvider(); + var result = await service.ExecuteQueryAsync(solution, query, s_referenceAssembliesDir, observer, options, traceSource, CancellationToken.None); + + Assert.Null(result.ErrorMessage); + AssertEx.Equal(["int C.F"], results.Select(Inspect)); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public async Task MethodQuery() + { + using var workspace = TestWorkspace.Create(DefaultWorkspaceXml, composition: FeaturesTestCompositions.Features); + + var solution = workspace.CurrentSolution; + + var service = solution.Services.GetRequiredLanguageService(LanguageNames.CSharp); + + var query = """ + static IEnumerable Find(IMethodSymbol method) + { + return [method]; + } + """; + + var results = new List(); + var observer = new MockSemanticSearchResultsObserver() { OnDefinitionFoundImpl = results.Add }; + var traceSource = new TraceSource("test"); + + var options = workspace.GlobalOptions.GetClassificationOptionsProvider(); + var result = await service.ExecuteQueryAsync(solution, query, s_referenceAssembliesDir, observer, options, traceSource, CancellationToken.None); + + Assert.Null(result.ErrorMessage); + AssertEx.Equal( + [ + "C.C()", + "int C.P.get", + "void C.E.add", + "void C.E.remove", + "void C.VisibleMethod(int)", + ], results.Select(Inspect).OrderBy(s => s)); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public async Task FieldQuery() + { + using var workspace = TestWorkspace.Create(DefaultWorkspaceXml, composition: FeaturesTestCompositions.Features); + + var solution = workspace.CurrentSolution; + + var service = solution.Services.GetRequiredLanguageService(LanguageNames.CSharp); + + var query = """ + static IEnumerable Find(IFieldSymbol field) + { + return [field]; + } + """; + + var results = new List(); + var observer = new MockSemanticSearchResultsObserver() { OnDefinitionFoundImpl = results.Add }; + var traceSource = new TraceSource("test"); + + var options = workspace.GlobalOptions.GetClassificationOptionsProvider(); + var result = await service.ExecuteQueryAsync(solution, query, s_referenceAssembliesDir, observer, options, traceSource, CancellationToken.None); + + Assert.Null(result.ErrorMessage); + AssertEx.Equal( + [ + "int C.F", + "readonly int C.P.field", + ], results.Select(Inspect).OrderBy(s => s)); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public async Task PropertyQuery() + { + using var workspace = TestWorkspace.Create(DefaultWorkspaceXml, composition: FeaturesTestCompositions.Features); + + var solution = workspace.CurrentSolution; + + var service = solution.Services.GetRequiredLanguageService(LanguageNames.CSharp); + + var query = """ + static IEnumerable Find(IPropertySymbol prop) + { + return [prop]; + } + """; + + var results = new List(); + var observer = new MockSemanticSearchResultsObserver() { OnDefinitionFoundImpl = results.Add }; + var traceSource = new TraceSource("test"); + + var options = workspace.GlobalOptions.GetClassificationOptionsProvider(); + var result = await service.ExecuteQueryAsync(solution, query, s_referenceAssembliesDir, observer, options, traceSource, CancellationToken.None); + + Assert.Null(result.ErrorMessage); + AssertEx.Equal(["int C.P { get; }"], results.Select(Inspect)); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public async Task EventQuery() + { + using var workspace = TestWorkspace.Create(DefaultWorkspaceXml, composition: FeaturesTestCompositions.Features); + + var solution = workspace.CurrentSolution; + + var service = solution.Services.GetRequiredLanguageService(LanguageNames.CSharp); + + var query = """ + static IEnumerable Find(IEventSymbol e) + { + return [e]; + } + """; + + var results = new List(); + var observer = new MockSemanticSearchResultsObserver() { OnDefinitionFoundImpl = results.Add }; + var traceSource = new TraceSource("test"); + + var options = workspace.GlobalOptions.GetClassificationOptionsProvider(); + var result = await service.ExecuteQueryAsync(solution, query, s_referenceAssembliesDir, observer, options, traceSource, CancellationToken.None); + + Assert.Null(result.ErrorMessage); + AssertEx.Equal(["event Action C.E"], results.Select(Inspect)); + } + [ConditionalFact(typeof(CoreClrOnly))] public async Task ForcedCancellation() { - using var workspace = TestWorkspace.Create(""" - - - - public class C - { - } - - - - """, composition: FeaturesTestCompositions.Features); + using var workspace = TestWorkspace.Create(DefaultWorkspaceXml, composition: FeaturesTestCompositions.Features); var solution = workspace.CurrentSolution; @@ -105,7 +276,7 @@ public class C var query = """ static IEnumerable Find(Compilation compilation) { - yield return compilation.GlobalNamespace.GetMembers("C").First(); + yield return compilation.GlobalNamespace.GetMembers("N").First(); while (true) { @@ -127,7 +298,7 @@ static IEnumerable Find(Compilation compilation) var traceSource = new TraceSource("test"); var options = workspace.GlobalOptions.GetClassificationOptionsProvider(); - await Assert.ThrowsAsync( + await Assert.ThrowsAsync( () => service.ExecuteQueryAsync(solution, query, s_referenceAssembliesDir, observer, options, traceSource, cancellationSource.Token)); Assert.Empty(exceptions); @@ -237,10 +408,58 @@ static ISymbol F(ISymbol s) var exception = exceptions.Single(); AssertEx.Equal($"CSharpAssembly1: [190..190) 'var x = s.ToString();': NullReferenceException: '{expectedMessage}'", Inspect(exception, query)); + AssertEx.Equal( $" at Program.<
$>g__F|0_1(ISymbol s) in {FeaturesResources.Query}:line 11" + Environment.NewLine + $" at Program.<>c.<
$>b__0_2(ISymbol x) in {FeaturesResources.Query}:line 5" + Environment.NewLine + - $" at System.Linq.Enumerable.ArraySelectIterator`2.MoveNext()" + Environment.NewLine, - exception.StackTrace.JoinText()); + $" at ")); + } + + /// + /// Checks that flow pass handles semantic query code end-to-end + /// (specifically, module cancellation and stack overflow instrumentation). + /// + [ConditionalFact(typeof(CoreClrOnly))] + public async Task FlowPass() + { + using var workspace = TestWorkspace.Create(DefaultWorkspaceXml, composition: FeaturesTestCompositions.Features); + + var solution = workspace.CurrentSolution; + + var service = solution.Services.GetRequiredLanguageService(LanguageNames.CSharp); + + var query = """ + using Microsoft.CodeAnalysis.CSharp; + using Microsoft.CodeAnalysis.CSharp.Syntax; + + static IEnumerable Find(IMethodSymbol method) + { + var syntaxReference = method.DeclaringSyntaxReferences.FirstOrDefault(); + if (syntaxReference != null) + { + while (true) + { + var syntaxNode = syntaxReference.GetSyntax() as MethodDeclarationSyntax; + if (syntaxNode != null) + { + yield return method; + } + + break; + } + } + } + """; + + var results = new List(); + var observer = new MockSemanticSearchResultsObserver() { OnDefinitionFoundImpl = results.Add }; + var traceSource = new TraceSource("test"); + + var options = workspace.GlobalOptions.GetClassificationOptionsProvider(); + var result = await service.ExecuteQueryAsync(solution, query, s_referenceAssembliesDir, observer, options, traceSource, CancellationToken.None); + + Assert.Null(result.ErrorMessage); + AssertEx.Equal(["void C.VisibleMethod(int)"], results.Select(Inspect)); } } diff --git a/src/Features/CSharpTest/Snippets/CSharpProprSnippetProviderTests.cs b/src/Features/CSharpTest/Snippets/CSharpProprSnippetProviderTests.cs index 5f75aef2b5a01..e905241afd8f4 100644 --- a/src/Features/CSharpTest/Snippets/CSharpProprSnippetProviderTests.cs +++ b/src/Features/CSharpTest/Snippets/CSharpProprSnippetProviderTests.cs @@ -4,7 +4,6 @@ using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; -using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Snippets; diff --git a/src/Features/CSharpTest/Snippets/CSharpUsingSnippetProviderTests.cs b/src/Features/CSharpTest/Snippets/CSharpUsingSnippetProviderTests.cs new file mode 100644 index 0000000000000..3cc449347bab4 --- /dev/null +++ b/src/Features/CSharpTest/Snippets/CSharpUsingSnippetProviderTests.cs @@ -0,0 +1,202 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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 CSharpUsingSnippetProviderTests : AbstractCSharpSnippetProviderTests +{ + protected override string SnippetIdentifier => "using"; + + [Fact] + public async Task InsertUsingSnippetInMethodTest() + { + await VerifySnippetAsync(""" + class Program + { + public void Method() + { + $$ + } + } + """, """ + class Program + { + public void Method() + { + using ({|0:resource|}) + { + $$ + } + } + } + """); + } + + [Fact] + public async Task InsertUsingSnippetInGlobalContextTest() + { + await VerifySnippetAsync(""" + $$ + """, """ + using ({|0:resource|}) + { + $$ + } + """); + } + + [Fact] + public async Task NoUsingSnippetInBusingNamespaceTest() + { + await VerifySnippetIsAbsentAsync(""" + namespace Namespace + { + $$ + } + """); + } + + [Fact] + public async Task NoUsingSnippetInFileScopedNamespaceTest() + { + await VerifySnippetIsAbsentAsync(""" + namespace Namespace; + $$ + """); + } + + [Fact] + public async Task InsertUsingSnippetInConstructorTest() + { + await VerifySnippetAsync(""" + class Program + { + public Program() + { + $$ + } + } + """, """ + class Program + { + public Program() + { + using ({|0:resource|}) + { + $$ + } + } + } + """); + } + + [Fact] + public async Task NoUsingSnippetInTypeBodyTest() + { + await VerifySnippetIsAbsentAsync(""" + class Program + { + $$ + } + """); + } + + [Fact] + public async Task InsertUsingSnippetInLocalFunctionTest() + { + await VerifySnippetAsync(""" + class Program + { + public void Method() + { + void LocalFunction() + { + $$ + } + } + } + """, """ + class Program + { + public void Method() + { + void LocalFunction() + { + using ({|0:resource|}) + { + $$ + } + } + } + } + """); + } + + [Fact] + public async Task InsertUsingSnippetInAnonymousFunctionTest() + { + await VerifySnippetAsync(""" + class Program + { + public void Method() + { + var action = delegate() + { + $$ + }; + } + } + """, """ + class Program + { + public void Method() + { + var action = delegate() + { + using ({|0:resource|}) + { + $$ + } + }; + } + } + """); + } + + [Fact] + public async Task InsertUsingSnippetInParenthesizedLambdaExpressionTest() + { + await VerifySnippetAsync(""" + class Program + { + public void Method() + { + var action = () => + { + $$ + }; + } + } + """, """ + class Program + { + public void Method() + { + var action = () => + { + using ({|0:resource|}) + { + $$ + } + }; + } + } + """); + } +} diff --git a/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForAccessorsRefactoringTests.cs b/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForAccessorsRefactoringTests.cs index 5011b0a17dae3..df68a60fc7121 100644 --- a/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForAccessorsRefactoringTests.cs +++ b/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForAccessorsRefactoringTests.cs @@ -83,207 +83,310 @@ private OptionsCollection UseBlockBodyForAccessors_BlockBodyForProperties_Disabl public async Task TestUpdatePropertyIfPropertyWantsBlockAndAccessorWantsExpression() { await TestInRegularAndScript1Async( -@"class C -{ - int Goo - { - get - { - [||]return Bar(); - } - } -}", -@"class C -{ - int Goo => Bar(); -}", parameters: new TestParameters(options: UseExpressionBodyForAccessors_BlockBodyForProperties)); + """ + class C + { + int Goo + { + get + { + [||]return Bar(); + } + } + } + """, + """ + class C + { + int Goo => Bar(); + } + """, + parameters: new TestParameters(options: UseExpressionBodyForAccessors_BlockBodyForProperties)); } [Fact] public async Task TestNotOfferedIfUserPrefersExpressionBodiesAndInBlockBody2() { await TestMissingAsync( -@"class C -{ - int Goo - { - get - { - [||]return Bar(); - } - } -}", parameters: new TestParameters(options: UseExpressionBodyForAccessors_ExpressionBodyForProperties)); + """ + class C + { + int Goo + { + get + { + [||]return Bar(); + } + } + } + """, + parameters: new TestParameters(options: UseExpressionBodyForAccessors_ExpressionBodyForProperties)); } [Fact] public async Task TestOfferedIfUserPrefersExpressionBodiesWithoutDiagnosticAndInBlockBody() { await TestInRegularAndScript1Async( -@"class C -{ - int Goo - { - get - { - return [||]Bar(); - } - } -}", -@"class C -{ - int Goo => Bar(); -}", parameters: new TestParameters(options: UseExpressionBodyForAccessors_BlockBodyForProperties_DisabledDiagnostic)); + """ + class C + { + int Goo + { + get + { + return [||]Bar(); + } + } + } + """, + """ + class C + { + int Goo => Bar(); + } + """, + parameters: new TestParameters(options: UseExpressionBodyForAccessors_BlockBodyForProperties_DisabledDiagnostic)); } [Fact] public async Task TestOfferedIfUserPrefersExpressionBodiesWithoutDiagnosticAndInBlockBody2() { await TestInRegularAndScript1Async( -@"class C -{ - int Goo - { - get - { - return [||]Bar(); - } - } -}", -@"class C -{ - int Goo => Bar(); -}", parameters: new TestParameters(options: UseExpressionBodyForAccessors_ExpressionBodyForProperties_DisabledDiagnostic)); + """ + class C + { + int Goo + { + get + { + return [||]Bar(); + } + } + } + """, + """ + class C + { + int Goo => Bar(); + } + """, + parameters: new TestParameters(options: UseExpressionBodyForAccessors_ExpressionBodyForProperties_DisabledDiagnostic)); } [Fact] public async Task TestOfferedIfUserPrefersBlockBodiesAndInBlockBody() { await TestInRegularAndScript1Async( -@"class C -{ - int Goo - { - get - { - return [||]Bar(); - } - } -}", -@"class C -{ - int Goo - { - get => Bar(); - } -}", parameters: new TestParameters(options: UseBlockBodyForAccessors_ExpressionBodyForProperties)); + """ + class C + { + int Goo + { + get + { + return [||]Bar(); + } + } + } + """, + """ + class C + { + int Goo + { + get => Bar(); + } + } + """, + parameters: new TestParameters(options: UseBlockBodyForAccessors_ExpressionBodyForProperties)); } [Fact] public async Task TestOfferExpressionBodyForPropertyIfPropertyAndAccessorBothPreferExpressions() { await TestInRegularAndScript1Async( -@"class C -{ - int Goo - { - get - { - return [||]Bar(); - } - } -}", -@"class C -{ - int Goo => [||]Bar(); -}", parameters: new TestParameters(options: UseBlockBodyForAccessors_BlockBodyForProperties)); + """ + class C + { + int Goo + { + get + { + return [||]Bar(); + } + } + } + """, + """ + class C + { + int Goo => [||]Bar(); + } + """, + parameters: new TestParameters(options: UseBlockBodyForAccessors_BlockBodyForProperties)); } [Fact] public async Task TestNotOfferedIfUserPrefersBlockBodiesAndInExpressionBody() { await TestMissingAsync( -@"class C -{ - int Goo { get => [||]Bar(); } -}", parameters: new TestParameters(options: UseBlockBodyForAccessors_ExpressionBodyForProperties)); + """ + class C + { + int Goo { get => [||]Bar(); } + } + """, + parameters: new TestParameters(options: UseBlockBodyForAccessors_ExpressionBodyForProperties)); } [Fact] public async Task TestOfferedIfUserPrefersBlockBodiesWithoutDiagnosticAndInExpressionBody() { await TestInRegularAndScript1Async( -@"class C -{ - int Goo { get => [||]Bar(); } -}", + """ + class C + { + int Goo { get => [||]Bar(); } + } + """, -@"class C -{ - int Goo => Bar(); -}", parameters: new TestParameters(options: UseBlockBodyForAccessors_BlockBodyForProperties_DisabledDiagnostic)); + """ + class C + { + int Goo => Bar(); + } + """, + parameters: new TestParameters(options: UseBlockBodyForAccessors_BlockBodyForProperties_DisabledDiagnostic)); } [Fact] public async Task TestOfferedIfUserPrefersBlockBodiesWithoutDiagnosticAndInExpressionBody2() { await TestInRegularAndScript1Async( -@"class C -{ - int Goo { get => [||]Bar(); } -}", + """ + class C + { + int Goo { get => [||]Bar(); } + } + """, -@"class C -{ - int Goo => Bar(); -}", parameters: new TestParameters(options: UseBlockBodyForAccessors_ExpressionBodyForProperties_DisabledDiagnostic)); + """ + class C + { + int Goo => Bar(); + } + """, + parameters: new TestParameters(options: UseBlockBodyForAccessors_ExpressionBodyForProperties_DisabledDiagnostic)); } [Fact] public async Task TestOfferedForPropertyIfUserPrefersBlockPropertiesAndHasBlockProperty() { await TestInRegularAndScript1Async( -@"class C -{ - int Goo { get => [||]Bar(); } -}", + """ + class C + { + int Goo { get => [||]Bar(); } + } + """, -@"class C -{ - int Goo => Bar(); -}", parameters: new TestParameters(options: UseBlockBodyForAccessors_BlockBodyForProperties)); + """ + class C + { + int Goo => Bar(); + } + """, + parameters: new TestParameters(options: UseBlockBodyForAccessors_BlockBodyForProperties)); } [Fact] public async Task TestOfferForPropertyIfPropertyPrefersBlockButCouldBecomeExpressionBody() { await TestInRegularAndScript1Async( -@"class C -{ - int Goo { get => [||]Bar(); } -}", -@"class C -{ - int Goo => Bar(); -}", parameters: new TestParameters(options: UseExpressionBodyForAccessors_BlockBodyForProperties)); + """ + class C + { + int Goo { get => [||]Bar(); } + } + """, + """ + class C + { + int Goo => Bar(); + } + """, + parameters: new TestParameters(options: UseExpressionBodyForAccessors_BlockBodyForProperties)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/20350")] public async Task TestAccessorListFormatting() { await TestInRegularAndScript1Async( -@"class C -{ - int Goo { get => [||]Bar(); } -}", -@"class C -{ - int Goo + """ + class C + { + int Goo { get => [||]Bar(); } + } + """, + """ + class C + { + int Goo + { + get + { + return Bar(); + } + } + } + """, + parameters: new TestParameters(options: UseExpressionBodyForAccessors_ExpressionBodyForProperties)); + } + + [Fact] + public async Task TestOfferedWithSelectionInsideExpressionBody() { - get - { - return Bar(); - } + await TestInRegularAndScript1Async( + """ + class C + { + int Goo + { + get + { + return [|Bar()|]; + } + } + } + """, + """ + class C + { + int Goo + { + get => Bar(); + } + } + """, + parameters: new TestParameters(options: UseBlockBodyForAccessors_ExpressionBodyForProperties)); } -}", parameters: new TestParameters(options: UseExpressionBodyForAccessors_ExpressionBodyForProperties)); + + [Fact] + public async Task TestNotOfferedWithSelectionOutsideExpressionBody() + { + await TestMissingAsync( + """ + class C + { + int Goo + { + get + { + return [|Bar(); + } + }|] + } + """, + parameters: new TestParameters(options: UseBlockBodyForAccessors_ExpressionBodyForProperties)); } } diff --git a/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForConstructorsRefactoringTests.cs b/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForConstructorsRefactoringTests.cs index b6d1855b4d4e7..8fa5b0c2b58a0 100644 --- a/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForConstructorsRefactoringTests.cs +++ b/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForConstructorsRefactoringTests.cs @@ -38,103 +38,170 @@ private OptionsCollection UseBlockBodyDisabledDiagnostic public async Task TestNotOfferedIfUserPrefersExpressionBodiesAndInBlockBody() { await TestMissingAsync( -@"class C -{ - public C() - { - [||]Bar(); - } -}", parameters: new TestParameters(options: UseExpressionBody)); + """ + class C + { + public C() + { + [||]Bar(); + } + } + """, + parameters: new TestParameters(options: UseExpressionBody)); } [Fact] public async Task TestOfferedIfUserPrefersExpressionBodiesWithoutDiagnosticAndInBlockBody() { await TestInRegularAndScript1Async( -@"class C -{ - public C() - { - [||]Bar(); - } -}", -@"class C -{ - public C() => Bar(); -}", parameters: new TestParameters(options: UseExpressionBodyDisabledDiagnostic)); + """ + class C + { + public C() + { + [||]Bar(); + } + } + """, + """ + class C + { + public C() => Bar(); + } + """, + parameters: new TestParameters(options: UseExpressionBodyDisabledDiagnostic)); } [Fact] public async Task TestOfferedIfUserPrefersBlockBodiesAndInBlockBody() { await TestInRegularAndScript1Async( -@"class C -{ - public C() - { - [||]Bar(); - } -}", -@"class C -{ - public C() => Bar(); -}", parameters: new TestParameters(options: UseBlockBody)); + """ + class C + { + public C() + { + [||]Bar(); + } + } + """, + """ + class C + { + public C() => Bar(); + } + """, + parameters: new TestParameters(options: UseBlockBody)); } [Fact] public async Task TestNotOfferedInLambda() { await TestMissingAsync( -@"class C -{ - public C() - { - return () => { [||] }; - } -}", parameters: new TestParameters(options: UseBlockBody)); + """ + class C + { + public C() + { + return () => { [||] }; + } + } + """, + parameters: new TestParameters(options: UseBlockBody)); } [Fact] public async Task TestNotOfferedIfUserPrefersBlockBodiesAndInExpressionBody() { await TestMissingAsync( -@"class C -{ - public C() => [||]Bar(); -}", parameters: new TestParameters(options: UseBlockBody)); + """ + class C + { + public C() => [||]Bar(); + } + """, + parameters: new TestParameters(options: UseBlockBody)); } [Fact] public async Task TestOfferedIfUserPrefersBlockBodiesWithoutDiagnosticAndInExpressionBody() { await TestInRegularAndScript1Async( -@"class C -{ - public C() => [||]Bar(); -}", -@"class C -{ - public C() - { - Bar(); - } -}", parameters: new TestParameters(options: UseBlockBodyDisabledDiagnostic)); + """ + class C + { + public C() => [||]Bar(); + } + """, + """ + class C + { + public C() + { + Bar(); + } + } + """, + parameters: new TestParameters(options: UseBlockBodyDisabledDiagnostic)); } [Fact] public async Task TestOfferedIfUserPrefersExpressionBodiesAndInExpressionBody() { await TestInRegularAndScript1Async( -@"class C -{ - public C() => [||]Bar(); -}", -@"class C -{ - public C() + """ + class C + { + public C() => [||]Bar(); + } + """, + """ + class C + { + public C() + { + Bar(); + } + } + """, + parameters: new TestParameters(options: UseExpressionBody)); + } + + [Fact] + public async Task TestOfferedWithSelectionInsideExpressionBody() { - Bar(); + await TestInRegularAndScript1Async( + """ + class C + { + public C() + { + [|Bar()|]; + } + } + """, + """ + class C + { + public C() => Bar(); + } + """, + parameters: new TestParameters(options: UseBlockBody)); } -}", parameters: new TestParameters(options: UseExpressionBody)); + + [Fact] + public async Task TestNotOfferedWithSelectionOutsideExpressionBody() + { + await TestMissingAsync( + """ + class C + { + public C() + { + [|Bar(); + } + }|] + """, + parameters: new TestParameters(options: UseBlockBody)); } } diff --git a/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForConversionOperatorsRefactoringTests.cs b/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForConversionOperatorsRefactoringTests.cs index 133ea945e407a..5b5c446a2e846 100644 --- a/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForConversionOperatorsRefactoringTests.cs +++ b/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForConversionOperatorsRefactoringTests.cs @@ -38,103 +38,170 @@ private OptionsCollection UseBlockBodyDisabledDiagnostic public async Task TestNotOfferedIfUserPrefersExpressionBodiesAndInBlockBody() { await TestMissingAsync( -@"class C -{ - public static implicit operator bool(C c1) - { - [||]Bar(); - } -}", parameters: new TestParameters(options: UseExpressionBody)); + """ + class C + { + public static implicit operator bool(C c1) + { + [||]Bar(); + } + } + """, + parameters: new TestParameters(options: UseExpressionBody)); } [Fact] public async Task TestOfferedIfUserPrefersExpressionBodiesWithoutDiagnosticAndInBlockBody() { await TestInRegularAndScript1Async( -@"class C -{ - public static implicit operator bool(C c1) - { - [||]Bar(); - } -}", -@"class C -{ - public static implicit operator bool(C c1) => Bar(); -}", parameters: new TestParameters(options: UseExpressionBodyDisabledDiagnostic)); + """ + class C + { + public static implicit operator bool(C c1) + { + [||]Bar(); + } + } + """, + """ + class C + { + public static implicit operator bool(C c1) => Bar(); + } + """, + parameters: new TestParameters(options: UseExpressionBodyDisabledDiagnostic)); } [Fact] public async Task TestOfferedIfUserPrefersBlockBodiesAndInBlockBody() { await TestInRegularAndScript1Async( -@"class C -{ - public static implicit operator bool(C c1) - { - [||]Bar(); - } -}", -@"class C -{ - public static implicit operator bool(C c1) => Bar(); -}", parameters: new TestParameters(options: UseBlockBody)); + """ + class C + { + public static implicit operator bool(C c1) + { + [||]Bar(); + } + } + """, + """ + class C + { + public static implicit operator bool(C c1) => Bar(); + } + """, + parameters: new TestParameters(options: UseBlockBody)); } [Fact] public async Task TestNotOfferedInLambda() { await TestMissingAsync( -@"class C -{ - public static implicit operator bool(C c1) - { - return () => { [||] }; - } -}", parameters: new TestParameters(options: UseBlockBody)); + """ + class C + { + public static implicit operator bool(C c1) + { + return () => { [||] }; + } + } + """, + parameters: new TestParameters(options: UseBlockBody)); } [Fact] public async Task TestNotOfferedIfUserPrefersBlockBodiesAndInExpressionBody() { await TestMissingAsync( -@"class C -{ - public static implicit operator bool(C c1) => [||]Bar(); -}", parameters: new TestParameters(options: UseBlockBody)); + """ + class C + { + public static implicit operator bool(C c1) => [||]Bar(); + } + """, + parameters: new TestParameters(options: UseBlockBody)); } [Fact] public async Task TestOfferedIfUserPrefersBlockBodiesWithoutDiagnosticAndInExpressionBody() { await TestInRegularAndScript1Async( -@"class C -{ - public static implicit operator bool(C c1) => [||]Bar(); -}", -@"class C -{ - public static implicit operator bool(C c1) - { - return Bar(); - } -}", parameters: new TestParameters(options: UseBlockBodyDisabledDiagnostic)); + """ + class C + { + public static implicit operator bool(C c1) => [||]Bar(); + } + """, + """ + class C + { + public static implicit operator bool(C c1) + { + return Bar(); + } + } + """, + parameters: new TestParameters(options: UseBlockBodyDisabledDiagnostic)); } [Fact] public async Task TestOfferedIfUserPrefersExpressionBodiesAndInExpressionBody() { await TestInRegularAndScript1Async( -@"class C -{ - public static implicit operator bool(C c1) => [||]Bar(); -}", -@"class C -{ - public static implicit operator bool(C c1) + """ + class C + { + public static implicit operator bool(C c1) => [||]Bar(); + } + """, + """ + class C + { + public static implicit operator bool(C c1) + { + return Bar(); + } + } + """, + parameters: new TestParameters(options: UseExpressionBody)); + } + + [Fact] + public async Task TestOfferedWithSelectionInsideBlockBody() { - return Bar(); + await TestInRegularAndScript1Async( + """ + class C + { + public static implicit operator bool(C c1) + { + [|Bar()|]; + } + } + """, + """ + class C + { + public static implicit operator bool(C c1) => Bar(); + } + """, + parameters: new TestParameters(options: UseBlockBody)); } -}", parameters: new TestParameters(options: UseExpressionBody)); + + [Fact] + public async Task TestNotOfferedWithSelectionOutsideBlockBody() + { + await TestMissingAsync( + """ + class C + { + public static implicit operator bool(C c1) + { + [|Bar(); + } + }|] + """, + parameters: new TestParameters(options: UseBlockBody)); } } diff --git a/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForIndexersRefactoringTests.cs b/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForIndexersRefactoringTests.cs index 4e49850fffdf7..70d744f4865db 100644 --- a/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForIndexersRefactoringTests.cs +++ b/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForIndexersRefactoringTests.cs @@ -39,121 +39,194 @@ private OptionsCollection UseBlockBodyDisabledDiagnostic public async Task TestNotOfferedIfUserPrefersExpressionBodiesAndInBlockBody() { await TestMissingAsync( -@"class C -{ - int this[int i] - { - get - { - [||]return Bar(); - } - } -}", parameters: new TestParameters(options: UseExpressionBody)); + """ + class C + { + int this[int i] + { + get + { + [||]return Bar(); + } + } + } + """, + parameters: new TestParameters(options: UseExpressionBody)); } [Fact] public async Task TestOfferedIfUserPrefersExpressionBodiesWithoutDiagnosticAndInBlockBody() { await TestInRegularAndScript1Async( -@"class C -{ - int this[int i] - { - get - { - [||]return Bar(); - } - } -}", -@"class C -{ - int this[int i] => Bar(); -}", parameters: new TestParameters(options: UseExpressionBodyDisabledDiagnostic)); + """ + class C + { + int this[int i] + { + get + { + [||]return Bar(); + } + } + } + """, + """ + class C + { + int this[int i] => Bar(); + } + """, + parameters: new TestParameters(options: UseExpressionBodyDisabledDiagnostic)); } [Fact] public async Task TestOfferedIfUserPrefersBlockBodiesAndInBlockBody() { await TestInRegularAndScript1Async( -@"class C -{ - int this[int i] - { - get - { - [||]return Bar(); - } - } -}", -@"class C -{ - int this[int i] => Bar(); -}", parameters: new TestParameters(options: UseBlockBody)); + """ + class C + { + int this[int i] + { + get + { + [||]return Bar(); + } + } + } + """, + """ + class C + { + int this[int i] => Bar(); + } + """, + parameters: new TestParameters(options: UseBlockBody)); } [Fact] public async Task TestNotOfferedInLambda() { await TestMissingAsync( -@"class C -{ - Action Goo[int i] - { - get - { - return () => { [||] }; - } - } -}", parameters: new TestParameters(options: UseBlockBody)); + """ + class C + { + Action Goo[int i] + { + get + { + return () => { [||] }; + } + } + } + """, + parameters: new TestParameters(options: UseBlockBody)); } [Fact] public async Task TestNotOfferedIfUserPrefersBlockBodiesAndInExpressionBody() { await TestMissingAsync( -@"class C -{ - int this[int i] => [||]Bar(); -}", parameters: new TestParameters(options: UseBlockBody)); + """ + class C + { + int this[int i] => [||]Bar(); + } + """, + parameters: new TestParameters(options: UseBlockBody)); } [Fact] public async Task TestOfferedIfUserPrefersBlockBodiesWithoutDiagnosticAndInExpressionBody() { await TestInRegularAndScript1Async( -@"class C -{ - int this[int i] => [||]Bar(); -}", -@"class C -{ - int this[int i] - { - get - { - return Bar(); - } - } -}", parameters: new TestParameters(options: UseBlockBodyDisabledDiagnostic)); + """ + class C + { + int this[int i] => [||]Bar(); + } + """, + """ + class C + { + int this[int i] + { + get + { + return Bar(); + } + } + } + """, + parameters: new TestParameters(options: UseBlockBodyDisabledDiagnostic)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/20363")] public async Task TestOfferedIfUserPrefersExpressionBodiesAndInExpressionBody() { await TestInRegularAndScript1Async( -@"class C -{ - int this[int i] => [||]Bar(); -}", -@"class C -{ - int this[int i] + """ + class C + { + int this[int i] => [||]Bar(); + } + """, + """ + class C + { + int this[int i] + { + get + { + return Bar(); + } + } + } + """, + parameters: new TestParameters(options: UseExpressionBody)); + } + + [Fact] + public async Task TestOfferedWithSelectionInsideBlockBody() { - get - { - return Bar(); - } + await TestInRegularAndScript1Async( + """ + class C + { + int this[int i] + { + get + { + [|return Bar()|]; + } + } + } + """, + """ + class C + { + int this[int i] => Bar(); + } + """, + parameters: new TestParameters(options: UseBlockBody)); } -}", parameters: new TestParameters(options: UseExpressionBody)); + + [Fact] + public async Task TestNotOfferedWithSelectionOutsideBlockBody() + { + await TestMissingAsync( + """ + class C + { + int this[int i] + { + get + { + [|return Bar(); + } + } + }|] + """, + parameters: new TestParameters(options: UseBlockBody)); } } diff --git a/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForLocalFunctionsRefactoringTests.cs b/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForLocalFunctionsRefactoringTests.cs index eba9f49b0322c..1be89b9af754b 100644 --- a/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForLocalFunctionsRefactoringTests.cs +++ b/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForLocalFunctionsRefactoringTests.cs @@ -38,120 +38,193 @@ private OptionsCollection UseBlockBodyDisabledDiagnostic public async Task TestNotOfferedIfUserPrefersExpressionBodiesAndInBlockBody() { await TestMissingAsync( -@"class C -{ - void Goo() - { - void Bar() - { - [||]Test(); - } - } -}", parameters: new TestParameters(options: UseExpressionBody)); + """ + class C + { + void Goo() + { + void Bar() + { + [||]Test(); + } + } + } + """, + parameters: new TestParameters(options: UseExpressionBody)); } [Fact] public async Task TestOfferedIfUserPrefersExpressionBodiesWithoutDiagnosticAndInBlockBody() { await TestInRegularAndScript1Async( -@"class C -{ - void Goo() - { - void Bar() - { - [||]Test(); - } - } -}", -@"class C -{ - void Goo() - { - void Bar() => Test(); - } -}", parameters: new TestParameters(options: UseExpressionBodyDisabledDiagnostic)); + """ + class C + { + void Goo() + { + void Bar() + { + [||]Test(); + } + } + } + """, + """ + class C + { + void Goo() + { + void Bar() => Test(); + } + } + """, + parameters: new TestParameters(options: UseExpressionBodyDisabledDiagnostic)); } [Fact] public async Task TestOfferedIfUserPrefersBlockBodiesAndInBlockBody() { await TestInRegularAndScript1Async( -@"class C -{ - void Goo() - { - void Bar() - { - [||]Test(); - } - } -}", -@"class C -{ - void Goo() - { - void Bar() => Test(); - } -}", parameters: new TestParameters(options: UseBlockBody)); + """ + class C + { + void Goo() + { + void Bar() + { + [||]Test(); + } + } + } + """, + """ + class C + { + void Goo() + { + void Bar() => Test(); + } + } + """, + parameters: new TestParameters(options: UseBlockBody)); } [Fact] public async Task TestNotOfferedIfUserPrefersBlockBodiesAndInExpressionBody() { await TestMissingAsync( -@"class C -{ - void Goo() - { - void Bar() => [||]Test(); - } -}", parameters: new TestParameters(options: UseBlockBody)); + """ + class C + { + void Goo() + { + void Bar() => [||]Test(); + } + } + """, + parameters: new TestParameters(options: UseBlockBody)); } [Fact] public async Task TestOfferedIfUserPrefersBlockBodiesWithoutDiagnosticAndInExpressionBody() { await TestInRegularAndScript1Async( -@"class C -{ - void Goo() - { - void Bar() => [||]Test(); - } -}", -@"class C -{ - void Goo() - { - void Bar() - { - Test(); - } - } -}", parameters: new TestParameters(options: UseBlockBodyDisabledDiagnostic)); + """ + class C + { + void Goo() + { + void Bar() => [||]Test(); + } + } + """, + """ + class C + { + void Goo() + { + void Bar() + { + Test(); + } + } + } + """, + parameters: new TestParameters(options: UseBlockBodyDisabledDiagnostic)); } [Fact] public async Task TestOfferedIfUserPrefersExpressionBodiesAndInExpressionBody() { await TestInRegularAndScript1Async( -@"class C -{ - void Goo() - { - void Bar() => [||]Test(); + """ + class C + { + void Goo() + { + void Bar() => [||]Test(); + } + } + """, + """ + class C + { + void Goo() + { + void Bar() + { + Test(); + } + } + } + """, + parameters: new TestParameters(options: UseExpressionBody)); } -}", -@"class C -{ - void Goo() + + [Fact] + public async Task TestOfferedWithSelectionInsideBlockBody() { - void Bar() - { - Test(); - } + await TestInRegularAndScript1Async( + """ + class C + { + void Goo() + { + void Bar() + { + [|Test()|]; + } + } + } + """, + """ + class C + { + void Goo() + { + void Bar() => Test(); + } + } + """, + parameters: new TestParameters(options: UseBlockBody)); } -}", parameters: new TestParameters(options: UseExpressionBody)); + + [Fact] + public async Task TestNotOfferedWithSelectionOutsideBlockBody() + { + await TestMissingAsync( + """ + class C + { + void Goo() + { + void Bar() + { + [|Test(); + } + }|] + } + """, + parameters: new TestParameters(options: UseBlockBody)); } } diff --git a/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForMethodsRefactoringTests.cs b/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForMethodsRefactoringTests.cs index b1a4b95308780..a967266cb9f8d 100644 --- a/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForMethodsRefactoringTests.cs +++ b/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForMethodsRefactoringTests.cs @@ -37,204 +37,332 @@ private OptionsCollection UseBlockBodyDisabledDiagnostic public async Task TestNotOfferedIfUserPrefersExpressionBodiesAndInBlockBody() { await TestMissingAsync( -@"class C -{ - void Goo() - { - [||]Bar(); - } -}", parameters: new TestParameters(options: UseExpressionBody)); + """ + class C + { + void Goo() + { + [||]Bar(); + } + } + """, + parameters: new TestParameters(options: UseExpressionBody)); } [Fact] public async Task TestOfferedIfUserPrefersExpressionBodiesWithoutDiagnosticAndInBlockBody() { await TestInRegularAndScript1Async( -@"class C -{ - void Goo() - { - [||]Bar(); - } -}", -@"class C -{ - void Goo() => Bar(); -}", parameters: new TestParameters(options: UseExpressionBodyDisabledDiagnostic)); + """ + class C + { + void Goo() + { + [||]Bar(); + } + } + """, + """ + class C + { + void Goo() => Bar(); + } + """, + parameters: new TestParameters(options: UseExpressionBodyDisabledDiagnostic)); } [Fact] public async Task TestOfferedIfUserPrefersBlockBodiesAndInBlockBody() { await TestInRegularAndScript1Async( -@"class C -{ - void Goo() - { - [||]Bar(); - } -}", -@"class C -{ - void Goo() => Bar(); -}", parameters: new TestParameters(options: UseBlockBody)); + """ + class C + { + void Goo() + { + [||]Bar(); + } + } + """, + """ + class C + { + void Goo() => Bar(); + } + """, + parameters: new TestParameters(options: UseBlockBody)); } [Fact] public async Task TestNotOfferedInLambda() { await TestMissingAsync( -@"class C -{ - Action Goo() - { - return () => { [||] }; - } -}", parameters: new TestParameters(options: UseBlockBody)); + """ + class C + { + Action Goo() + { + return () => { [||] }; + } + } + """, + parameters: new TestParameters(options: UseBlockBody)); } [Fact] public async Task TestNotOfferedIfUserPrefersBlockBodiesAndInExpressionBody() { await TestMissingAsync( -@"class C -{ - void Goo() => [||]Bar(); -}", parameters: new TestParameters(options: UseBlockBody)); + """ + class C + { + void Goo() => [||]Bar(); + } + """, + parameters: new TestParameters(options: UseBlockBody)); } [Fact] public async Task TestOfferedIfUserPrefersBlockBodiesWithoutDiagnosticAndInExpressionBody() { await TestInRegularAndScript1Async( -@"class C -{ - void Goo() => [||]Bar(); -}", -@"class C -{ - void Goo() - { - Bar(); - } -}", parameters: new TestParameters(options: UseBlockBodyDisabledDiagnostic)); + """ + class C + { + void Goo() => [||]Bar(); + } + """, + """ + class C + { + void Goo() + { + Bar(); + } + } + """, + parameters: new TestParameters(options: UseBlockBodyDisabledDiagnostic)); } [Fact] public async Task TestOfferedIfUserPrefersExpressionBodiesAndInExpressionBody() { await TestInRegularAndScript1Async( -@"class C -{ - void Goo() => [||]Bar(); -}", -@"class C -{ - void Goo() - { - Bar(); - } -}", parameters: new TestParameters(options: UseExpressionBody)); + """ + class C + { + void Goo() => [||]Bar(); + } + """, + """ + class C + { + void Goo() + { + Bar(); + } + } + """, + parameters: new TestParameters(options: UseExpressionBody)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/25501")] public async Task TestOfferedAtStartOfMethod() { await TestInRegularAndScript1Async( -@"class C -{ - [||]void Goo() - { - Bar(); - } -}", -@"class C -{ - void Goo() => Bar(); -}", parameters: new TestParameters(options: UseBlockBody)); + """ + class C + { + [||]void Goo() + { + Bar(); + } + } + """, + """ + class C + { + void Goo() => Bar(); + } + """, + parameters: new TestParameters(options: UseBlockBody)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/25501")] public async Task TestOfferedBeforeMethodOnSameLine() { await TestInRegularAndScript1Async( -@"class C -{ -[||] void Goo() - { - Bar(); - } -}", -@"class C -{ - void Goo() => Bar(); -}", parameters: new TestParameters(options: UseBlockBody)); + """ + class C + { + [||] void Goo() + { + Bar(); + } + } + """, + """ + class C + { + void Goo() => Bar(); + } + """, + parameters: new TestParameters(options: UseBlockBody)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/25501")] public async Task TestOfferedBeforeAttributes() { await TestInRegularAndScript1Async( -@"class C -{ - [||][A] - void Goo() - { - Bar(); - } -}", -@"class C -{ - [A] - void Goo() => Bar(); -}", parameters: new TestParameters(options: UseBlockBody)); + """ + class C + { + [||][A] + void Goo() + { + Bar(); + } + } + """, + """ + class C + { + [A] + void Goo() => Bar(); + } + """, + parameters: new TestParameters(options: UseBlockBody)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/25501")] public async Task TestNotOfferedBeforeComments() { await TestMissingInRegularAndScriptAsync( -@"class C -{ - [||]/// - void Goo() - { - Bar(); - } -}", parameters: new TestParameters(options: UseBlockBody)); + """ + class C + { + [||]/// + void Goo() + { + Bar(); + } + } + """, + parameters: new TestParameters(options: UseBlockBody)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/25501")] public async Task TestNotOfferedInComments() { await TestMissingInRegularAndScriptAsync( -@"class C -{ - /// [||] - void Goo() - { - Bar(); - } -}", parameters: new TestParameters(options: UseBlockBody)); + """ + class C + { + /// [||] + void Goo() + { + Bar(); + } + } + """, + parameters: new TestParameters(options: UseBlockBody)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/53532")] public async Task TestTriviaOnArrow1() { await TestInRegularAndScript1Async( -@"class C -{ - void M() - // Test - [||]=> Console.WriteLine(); -}", -@"class C -{ - void M() + """ + class C + { + void M() + // Test + [||]=> Console.WriteLine(); + } + """, + """ + class C + { + void M() + { + // Test + Console.WriteLine(); + } + } + """, + parameters: new TestParameters(options: UseExpressionBody)); + } + + [Fact] + public async Task TestOfferedWithSelectionInsideBlockBody() { - // Test - Console.WriteLine(); + await TestInRegularAndScript1Async( + """ + class C + { + void Goo() + { + [|Bar()|]; + } + } + """, + """ + class C + { + void Goo() => Bar(); + } + """, + parameters: new TestParameters(options: UseBlockBody)); + } + + [Fact] + public async Task TestNotOfferedWithSelectionOutsideBlockBody() + { + await TestMissingInRegularAndScriptAsync( + """ + class C + { + void Goo() + { + [|Bar(); + } + }|] + """, + parameters: new TestParameters(options: UseBlockBody)); } -}", parameters: new TestParameters(options: UseExpressionBody)); + + [Fact] + public async Task TestOfferedWithSelectionInsideExpressionBody() + { + await TestInRegularAndScript1Async( + """ + class C + { + void Goo() => [|Bar()|]; + } + """, + """ + class C + { + void Goo() + { + Bar(); + } + } + """, + parameters: new TestParameters(options: UseExpressionBody)); + } + + [Fact] + public async Task TestNotOfferedWithSelectionOutsideExpressionBody() + { + await TestMissingInRegularAndScriptAsync( + """ + class C + { + void Goo() => [|Bar(); + }|] + """, + parameters: new TestParameters(options: UseExpressionBody)); } } diff --git a/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForOperatorsRefactoringTests.cs b/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForOperatorsRefactoringTests.cs index efd9fa80f8460..9ecd34ddde838 100644 --- a/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForOperatorsRefactoringTests.cs +++ b/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForOperatorsRefactoringTests.cs @@ -38,103 +38,170 @@ private OptionsCollection UseBlockBodyDisabledDiagnostic public async Task TestNotOfferedIfUserPrefersExpressionBodiesAndInBlockBody() { await TestMissingAsync( -@"class C -{ - public static bool operator +(C c1, C c2) - { - [||]Bar(); - } -}", parameters: new TestParameters(options: UseExpressionBody)); + """ + class C + { + public static bool operator +(C c1, C c2) + { + [||]Bar(); + } + } + """, + parameters: new TestParameters(options: UseExpressionBody)); } [Fact] public async Task TestOfferedIfUserPrefersExpressionBodiesWithoutDiagnosticAndInBlockBody() { await TestInRegularAndScript1Async( -@"class C -{ - public static bool operator +(C c1, C c2) - { - [||]Bar(); - } -}", -@"class C -{ - public static bool operator +(C c1, C c2) => Bar(); -}", parameters: new TestParameters(options: UseExpressionBodyDisabledDiagnostic)); + """ + class C + { + public static bool operator +(C c1, C c2) + { + [||]Bar(); + } + } + """, + """ + class C + { + public static bool operator +(C c1, C c2) => Bar(); + } + """, + parameters: new TestParameters(options: UseExpressionBodyDisabledDiagnostic)); } [Fact] public async Task TestOfferedIfUserPrefersBlockBodiesAndInBlockBody() { await TestInRegularAndScript1Async( -@"class C -{ - public static bool operator +(C c1, C c2) - { - [||]Bar(); - } -}", -@"class C -{ - public static bool operator +(C c1, C c2) => Bar(); -}", parameters: new TestParameters(options: UseBlockBody)); + """ + class C + { + public static bool operator +(C c1, C c2) + { + [||]Bar(); + } + } + """, + """ + class C + { + public static bool operator +(C c1, C c2) => Bar(); + } + """, + parameters: new TestParameters(options: UseBlockBody)); } [Fact] public async Task TestNotOfferedInLambda() { await TestMissingAsync( -@"class C -{ - public static bool operator +(C c1, C c2) - { - return () => { [||] }; - } -}", parameters: new TestParameters(options: UseBlockBody)); + """ + class C + { + public static bool operator +(C c1, C c2) + { + return () => { [||] }; + } + } + """, + parameters: new TestParameters(options: UseBlockBody)); } [Fact] public async Task TestNotOfferedIfUserPrefersBlockBodiesAndInExpressionBody() { await TestMissingAsync( -@"class C -{ - public static bool operator +(C c1, C c2) => [||]Bar(); -}", parameters: new TestParameters(options: UseBlockBody)); + """ + class C + { + public static bool operator +(C c1, C c2) => [||]Bar(); + } + """, + parameters: new TestParameters(options: UseBlockBody)); } [Fact] public async Task TestOfferedIfUserPrefersBlockBodiesWithoutDiagnosticAndInExpressionBody() { await TestInRegularAndScript1Async( -@"class C -{ - public static bool operator +(C c1, C c2) => [||]Bar(); -}", -@"class C -{ - public static bool operator +(C c1, C c2) - { - return Bar(); - } -}", parameters: new TestParameters(options: UseBlockBodyDisabledDiagnostic)); + """ + class C + { + public static bool operator +(C c1, C c2) => [||]Bar(); + } + """, + """ + class C + { + public static bool operator +(C c1, C c2) + { + return Bar(); + } + } + """, + parameters: new TestParameters(options: UseBlockBodyDisabledDiagnostic)); } [Fact] public async Task TestOfferedIfUserPrefersExpressionBodiesAndInExpressionBody() { await TestInRegularAndScript1Async( -@"class C -{ - public static bool operator +(C c1, C c2) => [||]Bar(); -}", -@"class C -{ - public static bool operator +(C c1, C c2) + """ + class C + { + public static bool operator +(C c1, C c2) => [||]Bar(); + } + """, + """ + class C + { + public static bool operator +(C c1, C c2) + { + return Bar(); + } + } + """, + parameters: new TestParameters(options: UseExpressionBody)); + } + + [Fact] + public async Task TestOfferedWithSelectionInsideBlockBody() { - return Bar(); + await TestInRegularAndScript1Async( + """ + class C + { + public static bool operator +(C c1, C c2) + { + [|Bar()|]; + } + } + """, + """ + class C + { + public static bool operator +(C c1, C c2) => Bar(); + } + """, + parameters: new TestParameters(options: UseBlockBody)); } -}", parameters: new TestParameters(options: UseExpressionBody)); + + [Fact] + public async Task TestNotOfferedWithSelectionOutsideBlockBody() + { + await TestMissingAsync( + """ + class C + { + public static bool operator +(C c1, C c2) + { + [|Bar(); + } + }|] + """, + parameters: new TestParameters(options: UseBlockBody)); } } diff --git a/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForPropertiesRefactoringTests.cs b/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForPropertiesRefactoringTests.cs index cbd6e5394f8f4..4db58e84f1612 100644 --- a/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForPropertiesRefactoringTests.cs +++ b/src/Features/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForPropertiesRefactoringTests.cs @@ -77,235 +77,336 @@ private OptionsCollection UseBlockBodyForAccessors_BlockBodyForProperties_Disabl public async Task TestNotOfferedIfUserPrefersExpressionBodiesAndInBlockBody() { await TestMissingAsync( -@"class C -{ - int Goo - { - get - { - [||]return Bar(); - } - } -}", parameters: new TestParameters(options: UseExpressionBodyForAccessors_ExpressionBodyForProperties)); + """ + class C + { + int Goo + { + get + { + [||]return Bar(); + } + } + } + """, + parameters: new TestParameters(options: UseExpressionBodyForAccessors_ExpressionBodyForProperties)); } [Fact] public async Task TestOfferedIfUserPrefersExpressionBodiesWithoutDiagnosticAndInBlockBody() { await TestInRegularAndScript1Async( -@"class C -{ - int Goo - { - get - { - [||]return Bar(); - } - } -}", -@"class C -{ - int Goo => Bar(); -}", parameters: new TestParameters(options: UseExpressionBodyForAccessors_ExpressionBodyForProperties_DisabledDiagnostic)); + """ + class C + { + int Goo + { + get + { + [||]return Bar(); + } + } + } + """, + """ + class C + { + int Goo => Bar(); + } + """, + parameters: new TestParameters(options: UseExpressionBodyForAccessors_ExpressionBodyForProperties_DisabledDiagnostic)); } [Fact] public async Task TestUpdateAccessorIfAccessWantsBlockAndPropertyWantsExpression() { await TestInRegularAndScript1Async( -@"class C -{ - int Goo - { - get - { - [||]return Bar(); - } - } -}", -@"class C -{ - int Goo - { - get => Bar(); - } -}", parameters: new TestParameters(options: UseBlockBodyForAccessors_ExpressionBodyForProperties)); + """ + class C + { + int Goo + { + get + { + [||]return Bar(); + } + } + } + """, + """ + class C + { + int Goo + { + get => Bar(); + } + } + """, + parameters: new TestParameters(options: UseBlockBodyForAccessors_ExpressionBodyForProperties)); } [Fact] public async Task TestOfferedIfUserPrefersBlockBodiesAndInBlockBody() { await TestInRegularAndScript1Async( -@"class C -{ - int Goo - { - get - { - [||]return Bar(); - } - } -}", -@"class C -{ - int Goo => Bar(); -}", parameters: new TestParameters(options: UseExpressionBodyForAccessors_BlockBodyForProperties)); + """ + class C + { + int Goo + { + get + { + [||]return Bar(); + } + } + } + """, + """ + class C + { + int Goo => Bar(); + } + """, + parameters: new TestParameters(options: UseExpressionBodyForAccessors_BlockBodyForProperties)); } [Fact] public async Task TestOfferedIfUserPrefersBlockBodiesAndInBlockBody2() { await TestInRegularAndScript1Async( -@"class C -{ - int Goo - { - get - { - [||]return Bar(); - } - } -}", -@"class C -{ - int Goo => Bar(); -}", parameters: new TestParameters(options: UseBlockBodyForAccessors_BlockBodyForProperties)); + """ + class C + { + int Goo + { + get + { + [||]return Bar(); + } + } + } + """, + """ + class C + { + int Goo => Bar(); + } + """, + parameters: new TestParameters(options: UseBlockBodyForAccessors_BlockBodyForProperties)); } [Fact] public async Task TestNotOfferedInLambda() { await TestMissingAsync( -@"class C -{ - Action Goo - { - get - { - return () => { [||] }; - } - } -}", parameters: new TestParameters(options: UseBlockBodyForAccessors_BlockBodyForProperties)); + """ + class C + { + Action Goo + { + get + { + return () => { [||] }; + } + } + } + """, + parameters: new TestParameters(options: UseBlockBodyForAccessors_BlockBodyForProperties)); } [Fact] public async Task TestNotOfferedIfUserPrefersBlockBodiesAndInExpressionBody() { await TestMissingAsync( -@"class C -{ - int Goo => [||]Bar(); -}", parameters: new TestParameters(options: UseExpressionBodyForAccessors_BlockBodyForProperties)); + """ + class C + { + int Goo => [||]Bar(); + } + """, + parameters: new TestParameters(options: UseExpressionBodyForAccessors_BlockBodyForProperties)); } [Fact] public async Task TestNotOfferedIfUserPrefersBlockBodiesAndInExpressionBody2() { await TestMissingAsync( -@"class C -{ - int Goo => [||]Bar(); -}", parameters: new TestParameters(options: UseBlockBodyForAccessors_BlockBodyForProperties)); + """ + class C + { + int Goo => [||]Bar(); + } + """, + parameters: new TestParameters(options: UseBlockBodyForAccessors_BlockBodyForProperties)); } [Fact] public async Task TestOfferedIfUserPrefersBlockBodiesWithoutDiagnosticAndInExpressionBody() { await TestInRegularAndScript1Async( -@"class C -{ - int Goo => [||]Bar(); -}", -@"class C -{ - int Goo - { - get - { - return Bar(); - } - } -}", parameters: new TestParameters(options: UseExpressionBodyForAccessors_BlockBodyForProperties_DisabledDiagnostic)); + """ + class C + { + int Goo => [||]Bar(); + } + """, + """ + class C + { + int Goo + { + get + { + return Bar(); + } + } + } + """, + parameters: new TestParameters(options: UseExpressionBodyForAccessors_BlockBodyForProperties_DisabledDiagnostic)); } [Fact] public async Task TestOfferedIfUserPrefersBlockBodiesWithoutDiagnosticAndInExpressionBody2() { await TestInRegularAndScript1Async( -@"class C -{ - int Goo => [||]Bar(); -}", -@"class C -{ - int Goo - { - get - { - return Bar(); - } - } -}", parameters: new TestParameters(options: UseBlockBodyForAccessors_BlockBodyForProperties_DisabledDiagnostic)); + """ + class C + { + int Goo => [||]Bar(); + } + """, + """ + class C + { + int Goo + { + get + { + return Bar(); + } + } + } + """, + parameters: new TestParameters(options: UseBlockBodyForAccessors_BlockBodyForProperties_DisabledDiagnostic)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/20363")] public async Task TestOfferedIfUserPrefersExpressionBodiesAndInExpressionBody() { await TestInRegularAndScript1Async( -@"class C -{ - int Goo => [||]Bar(); -}", -@"class C -{ - int Goo - { - get - { - return Bar(); - } - } -}", parameters: new TestParameters(options: UseExpressionBodyForAccessors_ExpressionBodyForProperties)); + """ + class C + { + int Goo => [||]Bar(); + } + """, + """ + class C + { + int Goo + { + get + { + return Bar(); + } + } + } + """, + parameters: new TestParameters(options: UseExpressionBodyForAccessors_ExpressionBodyForProperties)); } [Fact] public async Task TestOfferedIfUserPrefersExpressionBodiesAndInExpressionBody2() { await TestInRegularAndScript1Async( -@"class C -{ - int Goo => [||]Bar(); -}", -@"class C -{ - int Goo - { - get - { - return Bar(); - } - } -}", parameters: new TestParameters(options: UseBlockBodyForAccessors_ExpressionBodyForProperties)); + """ + class C + { + int Goo => [||]Bar(); + } + """, + """ + class C + { + int Goo + { + get + { + return Bar(); + } + } + } + """, + parameters: new TestParameters(options: UseBlockBodyForAccessors_ExpressionBodyForProperties)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/20360")] public async Task TestOfferedIfUserPrefersExpressionBodiesAndInExpressionBody_CSharp6() { await TestAsync( -@"class C -{ - int Goo => [||]Bar(); -}", -@"class C -{ - int Goo + """ + class C + { + int Goo => [||]Bar(); + } + """, + """ + class C + { + int Goo + { + get + { + return Bar(); + } + } + } + """, + parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp6), + options: UseExpressionBodyForAccessors_ExpressionBodyForProperties); + } + + [Fact] + public async Task TestOfferedWithSelectionInsideBlockBody() { - get - { - return Bar(); - } + await TestInRegularAndScript1Async( + """ + class C + { + int Goo + { + get + { + [|return Bar()|]; + } + } + } + """, + """ + class C + { + int Goo => Bar(); + } + """, + parameters: new TestParameters(options: UseExpressionBodyForAccessors_BlockBodyForProperties)); } -}", parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp6), -options: UseExpressionBodyForAccessors_ExpressionBodyForProperties); + + [Fact] + public async Task TestNotOfferedWithSelectionOutsideBlockBody() + { + await TestMissingAsync( + """ + class C + { + int Goo + { + get + { + [|return Bar(); + } + } + }|] + """, + parameters: new TestParameters(options: UseExpressionBodyForAccessors_BlockBodyForProperties)); } } diff --git a/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs b/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs index a4e6a7b315b60..98611699ffc8d 100644 --- a/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Packaging; diff --git a/src/Features/Core/Portable/AddImport/CodeActions/AddImportCodeAction.cs b/src/Features/Core/Portable/AddImport/CodeActions/AddImportCodeAction.cs index 95e2a8cc1e314..3646b545bce14 100644 --- a/src/Features/Core/Portable/AddImport/CodeActions/AddImportCodeAction.cs +++ b/src/Features/Core/Portable/AddImport/CodeActions/AddImportCodeAction.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; diff --git a/src/Features/Core/Portable/AddImport/CodeActions/InstallPackageAndAddImportCodeAction.cs b/src/Features/Core/Portable/AddImport/CodeActions/InstallPackageAndAddImportCodeAction.cs index af6a66bb020ed..8360fc1f3120b 100644 --- a/src/Features/Core/Portable/AddImport/CodeActions/InstallPackageAndAddImportCodeAction.cs +++ b/src/Features/Core/Portable/AddImport/CodeActions/InstallPackageAndAddImportCodeAction.cs @@ -6,14 +6,12 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.AddPackage; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.AddImport; diff --git a/src/Features/Core/Portable/AddImport/CodeActions/InstallWithPackageManagerCodeAction.cs b/src/Features/Core/Portable/AddImport/CodeActions/InstallWithPackageManagerCodeAction.cs index 25984050cfc0b..9d1f04f95a08d 100644 --- a/src/Features/Core/Portable/AddImport/CodeActions/InstallWithPackageManagerCodeAction.cs +++ b/src/Features/Core/Portable/AddImport/CodeActions/InstallWithPackageManagerCodeAction.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Immutable; using System.Threading; diff --git a/src/Features/Core/Portable/AddImport/IAddImportFeatureService.cs b/src/Features/Core/Portable/AddImport/IAddImportFeatureService.cs index 6acecd82cae76..fde00770f53cf 100644 --- a/src/Features/Core/Portable/AddImport/IAddImportFeatureService.cs +++ b/src/Features/Core/Portable/AddImport/IAddImportFeatureService.cs @@ -3,11 +3,9 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; -using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Packaging; using Microsoft.CodeAnalysis.SymbolSearch; diff --git a/src/Features/Core/Portable/AddImport/Remote/IRemoteMissingImportDiscoveryService.cs b/src/Features/Core/Portable/AddImport/Remote/IRemoteMissingImportDiscoveryService.cs index c1f74045e0f9c..c6b2d81f0bd51 100644 --- a/src/Features/Core/Portable/AddImport/Remote/IRemoteMissingImportDiscoveryService.cs +++ b/src/Features/Core/Portable/AddImport/Remote/IRemoteMissingImportDiscoveryService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; diff --git a/src/Features/Core/Portable/AddImport/SearchScopes/ProjectSearchScope.cs b/src/Features/Core/Portable/AddImport/SearchScopes/ProjectSearchScope.cs index 11d34bf3904c2..f643933f13776 100644 --- a/src/Features/Core/Portable/AddImport/SearchScopes/ProjectSearchScope.cs +++ b/src/Features/Core/Portable/AddImport/SearchScopes/ProjectSearchScope.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Roslyn.Utilities; - namespace Microsoft.CodeAnalysis.AddImport; internal abstract partial class AbstractAddImportFeatureService diff --git a/src/Features/Core/Portable/AddImport/SymbolReferenceFinder.cs b/src/Features/Core/Portable/AddImport/SymbolReferenceFinder.cs index 2509bd09c77ab..7732b06817714 100644 --- a/src/Features/Core/Portable/AddImport/SymbolReferenceFinder.cs +++ b/src/Features/Core/Portable/AddImport/SymbolReferenceFinder.cs @@ -336,10 +336,12 @@ private async Task> GetReferencesForMatchingFiel private bool HasAccessibleStaticFieldOrProperty(INamedTypeSymbol namedType, string fieldOrPropertyName) { - return namedType.GetMembers(fieldOrPropertyName) - .Any(static (m, self) => (m is IFieldSymbol || m is IPropertySymbol) && - m.IsStatic && - m.IsAccessibleWithin(self._semanticModel.Compilation.Assembly), this); + return namedType + .GetMembers(fieldOrPropertyName) + .Any(static (m, self) => + m is IFieldSymbol or IPropertySymbol && + m.IsStatic && + m.IsAccessibleWithin(self._semanticModel.Compilation.Assembly), this); } /// diff --git a/src/Features/Core/Portable/AddImport/SymbolReferenceFinder_PackageAssemblySearch.cs b/src/Features/Core/Portable/AddImport/SymbolReferenceFinder_PackageAssemblySearch.cs index 5c64e0eb6f7cb..6693163cf0e2e 100644 --- a/src/Features/Core/Portable/AddImport/SymbolReferenceFinder_PackageAssemblySearch.cs +++ b/src/Features/Core/Portable/AddImport/SymbolReferenceFinder_PackageAssemblySearch.cs @@ -2,9 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Concurrent; -using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.LanguageService; diff --git a/src/Features/Core/Portable/AddMissingReference/AbstractAddMissingReferenceCodeFixProvider.cs b/src/Features/Core/Portable/AddMissingReference/AbstractAddMissingReferenceCodeFixProvider.cs index f94b609e766f3..1893de04d1020 100644 --- a/src/Features/Core/Portable/AddMissingReference/AbstractAddMissingReferenceCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddMissingReference/AbstractAddMissingReferenceCodeFixProvider.cs @@ -10,10 +10,8 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Packaging; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.SymbolSearch; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.AddMissingReference; diff --git a/src/Features/Core/Portable/AddPackage/AbstractAddSpecificPackageCodeFixProvider.cs b/src/Features/Core/Portable/AddPackage/AbstractAddSpecificPackageCodeFixProvider.cs index ddebcbe127d78..afad453be99db 100644 --- a/src/Features/Core/Portable/AddPackage/AbstractAddSpecificPackageCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddPackage/AbstractAddSpecificPackageCodeFixProvider.cs @@ -7,8 +7,6 @@ using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.Packaging; -using Microsoft.CodeAnalysis.SymbolSearch; namespace Microsoft.CodeAnalysis.AddPackage; diff --git a/src/Features/Core/Portable/AddPackage/InstallPackageDirectlyCodeAction.cs b/src/Features/Core/Portable/AddPackage/InstallPackageDirectlyCodeAction.cs index 3d1994705418b..3489f4c596dc1 100644 --- a/src/Features/Core/Portable/AddPackage/InstallPackageDirectlyCodeAction.cs +++ b/src/Features/Core/Portable/AddPackage/InstallPackageDirectlyCodeAction.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Immutable; using System.Threading; diff --git a/src/Features/Core/Portable/AddPackage/InstallWithPackageManagerCodeAction.cs b/src/Features/Core/Portable/AddPackage/InstallWithPackageManagerCodeAction.cs index 3e2e26bc7c043..9bdda9c841eea 100644 --- a/src/Features/Core/Portable/AddPackage/InstallWithPackageManagerCodeAction.cs +++ b/src/Features/Core/Portable/AddPackage/InstallWithPackageManagerCodeAction.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Immutable; using System.Threading; diff --git a/src/Features/Core/Portable/BraceMatching/BraceMatchingService.cs b/src/Features/Core/Portable/BraceMatching/BraceMatchingService.cs index d01e32dd5e861..f37bf8cd8b698 100644 --- a/src/Features/Core/Portable/BraceMatching/BraceMatchingService.cs +++ b/src/Features/Core/Portable/BraceMatching/BraceMatchingService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.Immutable; diff --git a/src/Features/Core/Portable/BraceMatching/ExportBraceMatcherAttribute.cs b/src/Features/Core/Portable/BraceMatching/ExportBraceMatcherAttribute.cs index a69f2265ff65c..7b791ce5656e9 100644 --- a/src/Features/Core/Portable/BraceMatching/ExportBraceMatcherAttribute.cs +++ b/src/Features/Core/Portable/BraceMatching/ExportBraceMatcherAttribute.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.Composition; diff --git a/src/Features/Core/Portable/ChangeSignature/ChangeSignatureTelemetryLogger.cs b/src/Features/Core/Portable/ChangeSignature/ChangeSignatureTelemetryLogger.cs index 6232b66e14c85..c904ab622e1e8 100644 --- a/src/Features/Core/Portable/ChangeSignature/ChangeSignatureTelemetryLogger.cs +++ b/src/Features/Core/Portable/ChangeSignature/ChangeSignatureTelemetryLogger.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.Internal.Log; diff --git a/src/Features/Core/Portable/ChangeSignature/IUnifiedArgumentSyntax.cs b/src/Features/Core/Portable/ChangeSignature/IUnifiedArgumentSyntax.cs index 98c9cde47b328..6eb1bbb1f9df2 100644 --- a/src/Features/Core/Portable/ChangeSignature/IUnifiedArgumentSyntax.cs +++ b/src/Features/Core/Portable/ChangeSignature/IUnifiedArgumentSyntax.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.ChangeSignature; internal interface IUnifiedArgumentSyntax diff --git a/src/Features/Core/Portable/ChangeSignature/Parameter.cs b/src/Features/Core/Portable/ChangeSignature/Parameter.cs index 05356fa3d7917..e8ee522823ee4 100644 --- a/src/Features/Core/Portable/ChangeSignature/Parameter.cs +++ b/src/Features/Core/Portable/ChangeSignature/Parameter.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Roslyn.Utilities; - namespace Microsoft.CodeAnalysis.ChangeSignature; /// diff --git a/src/Features/Core/Portable/ClassifiedSpansAndHighlightSpan.cs b/src/Features/Core/Portable/ClassifiedSpansAndHighlightSpan.cs index ee5f8cfffa159..b69e1dfc667d9 100644 --- a/src/Features/Core/Portable/ClassifiedSpansAndHighlightSpan.cs +++ b/src/Features/Core/Portable/ClassifiedSpansAndHighlightSpan.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/Core/Portable/CodeFixes/CodeFixCollection.cs b/src/Features/Core/Portable/CodeFixes/CodeFixCollection.cs index 606674ac7c07e..34834da5aa148 100644 --- a/src/Features/Core/Portable/CodeFixes/CodeFixCollection.cs +++ b/src/Features/Core/Portable/CodeFixes/CodeFixCollection.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using Microsoft.CodeAnalysis.Text; @@ -17,7 +15,7 @@ internal sealed class CodeFixCollection( object provider, TextSpan span, ImmutableArray fixes, - FixAllState fixAllState, + FixAllState? fixAllState, ImmutableArray supportedScopes, Diagnostic firstDiagnostic) { @@ -28,7 +26,7 @@ internal sealed class CodeFixCollection( /// /// Optional fix all context, which is non-null if the given supports fix all occurrences code fix. /// - public FixAllState FixAllState { get; } = fixAllState; + public FixAllState? FixAllState { get; } = fixAllState; public ImmutableArray SupportedScopes { get; } = supportedScopes.NullToEmpty(); public Diagnostic FirstDiagnostic { get; } = firstDiagnostic; } diff --git a/src/Features/Core/Portable/CodeFixes/Configuration/ConfigureCodeStyle/ConfigureCodeStyleOptionCodeFixProvider.cs b/src/Features/Core/Portable/CodeFixes/Configuration/ConfigureCodeStyle/ConfigureCodeStyleOptionCodeFixProvider.cs index 2ce7630a16636..10c4eb96236b4 100644 --- a/src/Features/Core/Portable/CodeFixes/Configuration/ConfigureCodeStyle/ConfigureCodeStyleOptionCodeFixProvider.cs +++ b/src/Features/Core/Portable/CodeFixes/Configuration/ConfigureCodeStyle/ConfigureCodeStyleOptionCodeFixProvider.cs @@ -17,7 +17,6 @@ using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; using static Microsoft.CodeAnalysis.CodeActions.CodeAction; namespace Microsoft.CodeAnalysis.CodeFixes.Configuration.ConfigureCodeStyle; diff --git a/src/Features/Core/Portable/CodeFixes/Configuration/ConfigureSeverity/ConfigureSeverityLevelCodeFixProvider.TopLevelConfigureSeverityCodeAction.cs b/src/Features/Core/Portable/CodeFixes/Configuration/ConfigureSeverity/ConfigureSeverityLevelCodeFixProvider.TopLevelConfigureSeverityCodeAction.cs index 41ce22e1b6c6a..f54119e14fcd3 100644 --- a/src/Features/Core/Portable/CodeFixes/Configuration/ConfigureSeverity/ConfigureSeverityLevelCodeFixProvider.TopLevelConfigureSeverityCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixes/Configuration/ConfigureSeverity/ConfigureSeverityLevelCodeFixProvider.TopLevelConfigureSeverityCodeAction.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using Microsoft.CodeAnalysis.CodeActions; diff --git a/src/Features/Core/Portable/CodeFixes/FixAllOccurrences/FixMultipleCodeAction.cs b/src/Features/Core/Portable/CodeFixes/FixAllOccurrences/FixMultipleCodeAction.cs index c618db13e848f..8e9a1aa4b3cea 100644 --- a/src/Features/Core/Portable/CodeFixes/FixAllOccurrences/FixMultipleCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixes/FixAllOccurrences/FixMultipleCodeAction.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.CodeFixesAndRefactorings; namespace Microsoft.CodeAnalysis.CodeFixes; diff --git a/src/Features/Core/Portable/CodeFixes/FixAllOccurrences/IFixMultipleOccurrencesService.cs b/src/Features/Core/Portable/CodeFixes/FixAllOccurrences/IFixMultipleOccurrencesService.cs index 6f1691cc9108a..5c66d2e38aed6 100644 --- a/src/Features/Core/Portable/CodeFixes/FixAllOccurrences/IFixMultipleOccurrencesService.cs +++ b/src/Features/Core/Portable/CodeFixes/FixAllOccurrences/IFixMultipleOccurrencesService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Immutable; using System.Threading; diff --git a/src/Features/Core/Portable/CodeFixes/ICodeFixProviderFactory.cs b/src/Features/Core/Portable/CodeFixes/ICodeFixProviderFactory.cs index d4f2b739a7742..fabccd188050e 100644 --- a/src/Features/Core/Portable/CodeFixes/ICodeFixProviderFactory.cs +++ b/src/Features/Core/Portable/CodeFixes/ICodeFixProviderFactory.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; namespace Microsoft.CodeAnalysis.CodeFixes; diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.AbstractSuppressionCodeAction.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.AbstractSuppressionCodeAction.cs index e100dde757739..eff28d66e0b6c 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.AbstractSuppressionCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.AbstractSuppressionCodeAction.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.CodeFixes.Suppression; internal abstract partial class AbstractSuppressionCodeFixProvider diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.FixAllProvider.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.FixAllProvider.cs index fef93e3f5c4ac..dbb9c1594392d 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.FixAllProvider.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.FixAllProvider.cs @@ -5,10 +5,8 @@ #nullable disable using System.Collections.Generic; -using System.Collections.Immutable; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeFixes.Suppression; diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageCodeAction.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageCodeAction.cs index 74ad683824a18..be345648227a7 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageCodeAction.cs @@ -2,12 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.AddImport; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.IPragmaBasedCodeAction.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.IPragmaBasedCodeAction.cs index ef72378420df2..4519081ad7253 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.IPragmaBasedCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.IPragmaBasedCodeAction.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; diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.PragmaWarningCodeAction.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.PragmaWarningCodeAction.cs index 204d8296e4658..a6ed417c47449 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.PragmaWarningCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.PragmaWarningCodeAction.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.Formatting; diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction.cs index b90e142d69b3b..9c2c87d041fbb 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction.cs @@ -6,7 +6,6 @@ using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Formatting; namespace Microsoft.CodeAnalysis.CodeFixes.Suppression; diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.cs index 5929cb0098c9c..9149a0150074f 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.cs @@ -11,7 +11,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.AddImport; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host; diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/ExportConfigurationFixProviderAttribute.cs b/src/Features/Core/Portable/CodeFixes/Suppression/ExportConfigurationFixProviderAttribute.cs index ea31ad2864db4..bf047cac1d951 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/ExportConfigurationFixProviderAttribute.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/ExportConfigurationFixProviderAttribute.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.Composition; diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/NestedSuppressionCodeAction.cs b/src/Features/Core/Portable/CodeFixes/Suppression/NestedSuppressionCodeAction.cs index c980a965211d0..0a5dce0c02437 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/NestedSuppressionCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/NestedSuppressionCodeAction.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.CodeActions; namespace Microsoft.CodeAnalysis.CodeFixes.Suppression; diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/SuppressionHelpers.cs b/src/Features/Core/Portable/CodeFixes/Suppression/SuppressionHelpers.cs index 2b1cf52b0e5cf..5840abac92c73 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/SuppressionHelpers.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/SuppressionHelpers.cs @@ -2,13 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Globalization; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeFixes.Suppression; diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/TopLevelSuppressionCodeAction.cs b/src/Features/Core/Portable/CodeFixes/Suppression/TopLevelSuppressionCodeAction.cs index 248788d106b3c..a2394ff67c03d 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/TopLevelSuppressionCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/TopLevelSuppressionCodeAction.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using Microsoft.CodeAnalysis.CodeActions; diff --git a/src/Features/Core/Portable/CodeFixesAndRefactorings/AbstractFixAllCodeAction.cs b/src/Features/Core/Portable/CodeFixesAndRefactorings/AbstractFixAllCodeAction.cs index 16c7df7bd1487..cb9287f68011d 100644 --- a/src/Features/Core/Portable/CodeFixesAndRefactorings/AbstractFixAllCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixesAndRefactorings/AbstractFixAllCodeAction.cs @@ -7,7 +7,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; -using Roslyn.Utilities; using FixAllScope = Microsoft.CodeAnalysis.CodeFixes.FixAllScope; namespace Microsoft.CodeAnalysis.CodeFixesAndRefactorings; diff --git a/src/Features/Core/Portable/CodeFixesAndRefactorings/AbstractFixAllGetFixesService.cs b/src/Features/Core/Portable/CodeFixesAndRefactorings/AbstractFixAllGetFixesService.cs index d47f72d6a39d8..d8e4e1e2111de 100644 --- a/src/Features/Core/Portable/CodeFixesAndRefactorings/AbstractFixAllGetFixesService.cs +++ b/src/Features/Core/Portable/CodeFixesAndRefactorings/AbstractFixAllGetFixesService.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.PooledObjects; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeFixesAndRefactorings; diff --git a/src/Features/Core/Portable/CodeLens/CodeLensFindReferenceProgress.cs b/src/Features/Core/Portable/CodeLens/CodeLensFindReferenceProgress.cs index 5a0a535ac915c..57d694691610d 100644 --- a/src/Features/Core/Portable/CodeLens/CodeLensFindReferenceProgress.cs +++ b/src/Features/Core/Portable/CodeLens/CodeLensFindReferenceProgress.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.Immutable; diff --git a/src/Features/Core/Portable/CodeLens/CodeLensReferencesServiceFactory.cs b/src/Features/Core/Portable/CodeLens/CodeLensReferencesServiceFactory.cs index ec245f4668dbc..a5f63eac45e4c 100644 --- a/src/Features/Core/Portable/CodeLens/CodeLensReferencesServiceFactory.cs +++ b/src/Features/Core/Portable/CodeLens/CodeLensReferencesServiceFactory.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.Composition; using Microsoft.CodeAnalysis.Host; diff --git a/src/Features/Core/Portable/CodeLens/ICodeLensDisplayInfoService.cs b/src/Features/Core/Portable/CodeLens/ICodeLensDisplayInfoService.cs index a269a5ae88e4c..bc9d2f463fb35 100644 --- a/src/Features/Core/Portable/CodeLens/ICodeLensDisplayInfoService.cs +++ b/src/Features/Core/Portable/CodeLens/ICodeLensDisplayInfoService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.CodeLens; diff --git a/src/Features/Core/Portable/CodeLens/IRemoteCodeLensReferencesService.cs b/src/Features/Core/Portable/CodeLens/IRemoteCodeLensReferencesService.cs index fbdc2ffc16686..54d75ca881458 100644 --- a/src/Features/Core/Portable/CodeLens/IRemoteCodeLensReferencesService.cs +++ b/src/Features/Core/Portable/CodeLens/IRemoteCodeLensReferencesService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; @@ -16,5 +14,5 @@ internal interface IRemoteCodeLensReferencesService ValueTask GetReferenceCountAsync(Checksum solutionChecksum, DocumentId documentId, TextSpan textSpan, int maxResultCount, CancellationToken cancellationToken); ValueTask?> FindReferenceLocationsAsync(Checksum solutionChecksum, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken); ValueTask?> FindReferenceMethodsAsync(Checksum solutionChecksum, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken); - ValueTask GetFullyQualifiedNameAsync(Checksum solutionChecksum, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken); + ValueTask GetFullyQualifiedNameAsync(Checksum solutionChecksum, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken); } diff --git a/src/Features/Core/Portable/CodeLens/ReferenceLocationDescriptor.cs b/src/Features/Core/Portable/CodeLens/ReferenceLocationDescriptor.cs index bb08943825cf2..e0074dbdb38ad 100644 --- a/src/Features/Core/Portable/CodeLens/ReferenceLocationDescriptor.cs +++ b/src/Features/Core/Portable/CodeLens/ReferenceLocationDescriptor.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.Runtime.Serialization; diff --git a/src/Features/Core/Portable/CodeLens/ReferenceMethodDescriptor.cs b/src/Features/Core/Portable/CodeLens/ReferenceMethodDescriptor.cs index e666941894cf1..12955d2634456 100644 --- a/src/Features/Core/Portable/CodeLens/ReferenceMethodDescriptor.cs +++ b/src/Features/Core/Portable/CodeLens/ReferenceMethodDescriptor.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.Runtime.Serialization; namespace Microsoft.CodeAnalysis.CodeLens; diff --git a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs index 741e36da818da..0c9811d172e7e 100644 --- a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs @@ -19,6 +19,7 @@ using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Telemetry; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeRefactorings; diff --git a/src/Features/Core/Portable/CodeRefactorings/ExtractMethod/AbstractExtractMethodCodeRefactoringProvider.cs b/src/Features/Core/Portable/CodeRefactorings/ExtractMethod/AbstractExtractMethodCodeRefactoringProvider.cs index 24ef70bf21c2a..bba947dab6d41 100644 --- a/src/Features/Core/Portable/CodeRefactorings/ExtractMethod/AbstractExtractMethodCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/CodeRefactorings/ExtractMethod/AbstractExtractMethodCodeRefactoringProvider.cs @@ -15,7 +15,6 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeRefactorings.ExtractMethod; diff --git a/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringProviderFactory.cs b/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringProviderFactory.cs index 05c5af6265fe3..f9a4837bf228a 100644 --- a/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringProviderFactory.cs +++ b/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringProviderFactory.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; namespace Microsoft.CodeAnalysis.CodeRefactorings; diff --git a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.Editor.cs b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.Editor.cs index bbdd9444b28fa..35aede8ef24c6 100644 --- a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.Editor.cs +++ b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.Editor.cs @@ -2,13 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeRefactorings.MoveType; @@ -19,15 +16,16 @@ internal abstract partial class AbstractMoveTypeService private abstract class Editor( TService service, - State state, + SemanticDocument semanticDocument, + TTypeDeclarationSyntax typeDeclaration, string fileName, CancellationToken cancellationToken) { - protected State State { get; } = state; protected TService Service { get; } = service; + protected SemanticDocument SemanticDocument { get; } = semanticDocument; + protected TTypeDeclarationSyntax TypeDeclaration { get; } = typeDeclaration; protected string FileName { get; } = fileName; protected CancellationToken CancellationToken { get; } = cancellationToken; - protected SemanticDocument SemanticDocument => State.SemanticDocument; /// /// Operations performed by CodeAction. @@ -35,27 +33,21 @@ private abstract class Editor( public virtual async Task> GetOperationsAsync() { var solution = await GetModifiedSolutionAsync().ConfigureAwait(false); - - if (solution == null) - { - return []; - } - - return [new ApplyChangesOperation(solution)]; + return solution == null ? [] : [new ApplyChangesOperation(solution)]; } /// /// Incremental solution edits that correlate to code operations /// - public abstract Task GetModifiedSolutionAsync(); + public abstract Task GetModifiedSolutionAsync(); - public static Editor GetEditor(MoveTypeOperationKind operationKind, TService service, State state, string fileName, CancellationToken cancellationToken) + public static Editor GetEditor(MoveTypeOperationKind operationKind, TService service, SemanticDocument document, TTypeDeclarationSyntax typeDeclaration, string fileName, CancellationToken cancellationToken) => operationKind switch { - MoveTypeOperationKind.MoveType => new MoveTypeEditor(service, state, fileName, cancellationToken), - MoveTypeOperationKind.RenameType => new RenameTypeEditor(service, state, fileName, cancellationToken), - MoveTypeOperationKind.RenameFile => new RenameFileEditor(service, state, fileName, cancellationToken), - MoveTypeOperationKind.MoveTypeNamespaceScope => new MoveTypeNamespaceScopeEditor(service, state, fileName, cancellationToken), + MoveTypeOperationKind.MoveType => new MoveTypeEditor(service, document, typeDeclaration, fileName, cancellationToken), + MoveTypeOperationKind.RenameType => new RenameTypeEditor(service, document, typeDeclaration, fileName, cancellationToken), + MoveTypeOperationKind.RenameFile => new RenameFileEditor(service, document, typeDeclaration, fileName, cancellationToken), + MoveTypeOperationKind.MoveTypeNamespaceScope => new MoveTypeNamespaceScopeEditor(service, document, typeDeclaration, fileName, cancellationToken), _ => throw ExceptionUtilities.UnexpectedValue(operationKind), }; } diff --git a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeCodeAction.cs b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeCodeAction.cs index 0cc0ababd3d02..c279936be45a9 100644 --- a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeCodeAction.cs +++ b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeCodeAction.cs @@ -2,14 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeRefactorings.MoveType; @@ -17,41 +14,43 @@ internal abstract partial class AbstractMoveTypeService _operationKind switch { MoveTypeOperationKind.MoveType => string.Format(FeaturesResources.Move_type_to_0, _fileName), - MoveTypeOperationKind.RenameType => string.Format(FeaturesResources.Rename_type_to_0, _state.DocumentNameWithoutExtension), + MoveTypeOperationKind.RenameType => string.Format(FeaturesResources.Rename_type_to_0, GetDocumentNameWithoutExtension(_document)), MoveTypeOperationKind.RenameFile => string.Format(FeaturesResources.Rename_file_to_0, _fileName), MoveTypeOperationKind.MoveTypeNamespaceScope => string.Empty, _ => throw ExceptionUtilities.UnexpectedValue(_operationKind), }; - public override string Title => _title; + public override string Title { get; } protected override async Task> ComputeOperationsAsync( IProgress progress, CancellationToken cancellationToken) { - var editor = Editor.GetEditor(_operationKind, _service, _state, _fileName, cancellationToken); + var editor = Editor.GetEditor(_operationKind, _service, _document, _typeDeclaration, _fileName, cancellationToken); return await editor.GetOperationsAsync().ConfigureAwait(false); } } diff --git a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeEditor.cs b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeEditor.cs index f904672a73af1..e4fc8389b3993 100644 --- a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeEditor.cs +++ b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeEditor.cs @@ -25,9 +25,10 @@ internal abstract partial class AbstractMoveTypeService /// Given a document and a type contained in it, moves the type @@ -42,10 +43,10 @@ private sealed class MoveTypeEditor( /// 3. Add this forked document to the solution. /// 4. Finally, update the original document and remove the type from it. /// - public override async Task GetModifiedSolutionAsync() + public override async Task GetModifiedSolutionAsync() { // Fork, update and add as new document. - var projectToBeUpdated = SemanticDocument.Document.Project; + var projectToBeUpdated = SemanticDocument.Project; var newDocumentId = DocumentId.CreateNewId(projectToBeUpdated.Id, FileName); // We do this process in the following steps: @@ -142,7 +143,7 @@ private async Task AddNewDocumentWithSingleTypeDeclarationAsync(Docume documentEditor.RemoveAllAttributes(root); // Now remove any leading directives on the type-node that actually correspond to prior nodes we removed. - var leadingTrivia = State.TypeNode.GetLeadingTrivia().ToSet(); + var leadingTrivia = this.TypeDeclaration.GetLeadingTrivia().ToSet(); foreach (var directive in correspondingDirectives) { if (leadingTrivia.Contains(directive.ParentTrivia)) @@ -185,7 +186,7 @@ void AddCorrespondingDirectives(SyntaxNode member, HashSet directive private void RemoveLeadingBlankLinesFromMovedType(DocumentEditor documentEditor) { - documentEditor.ReplaceNode(State.TypeNode, + documentEditor.ReplaceNode(this.TypeDeclaration, (currentNode, generator) => { var currentTypeNode = (TTypeDeclarationSyntax)currentNode; @@ -240,7 +241,7 @@ private async Task RemoveTypeFromSourceDocumentAsync(Document sourceDo // Now cleanup and remove the type we're moving to the new file. RemoveLeadingBlankLinesFromMovedType(documentEditor); - documentEditor.RemoveNode(State.TypeNode, SyntaxRemoveOptions.KeepUnbalancedDirectives); + documentEditor.RemoveNode(this.TypeDeclaration, SyntaxRemoveOptions.KeepUnbalancedDirectives); var updatedDocument = documentEditor.GetChangedDocument(); updatedDocument = await AddFileBannerHelpers.CopyBannerAsync(updatedDocument, sourceDocument.FilePath, sourceDocument, this.CancellationToken).ConfigureAwait(false); @@ -260,12 +261,12 @@ private ISet GetMembersToRemove(SyntaxNode root) var spine = new HashSet(); // collect the parent chain of declarations to keep. - spine.AddRange(State.TypeNode.GetAncestors()); + spine.AddRange(this.TypeDeclaration.GetAncestors()); // get potential namespace, types and members to remove. var removableCandidates = root .DescendantNodes(spine.Contains) - .Where(n => FilterToTopLevelMembers(n, State.TypeNode)).ToSet(); + .Where(n => FilterToTopLevelMembers(n, this.TypeDeclaration)).ToSet(); // diff candidates with items we want to keep. removableCandidates.ExceptWith(spine); @@ -304,12 +305,12 @@ private void AddPartialModifiersToTypeChain( bool removeTypeInheritance, bool removePrimaryConstructor) { - var semanticFacts = State.SemanticDocument.Document.GetRequiredLanguageService(); - var typeChain = State.TypeNode.Ancestors().OfType(); + var semanticFacts = SemanticDocument.GetRequiredLanguageService(); + var typeChain = this.TypeDeclaration.Ancestors().OfType(); foreach (var node in typeChain) { - var symbol = (INamedTypeSymbol?)State.SemanticDocument.SemanticModel.GetDeclaredSymbol(node, CancellationToken); + var symbol = (INamedTypeSymbol)SemanticDocument.SemanticModel.GetRequiredDeclaredSymbol(node, CancellationToken); Contract.ThrowIfNull(symbol); if (!semanticFacts.IsPartial(symbol, CancellationToken)) { @@ -338,8 +339,8 @@ private void AddPartialModifiersToTypeChain( private TTypeDeclarationSyntax RemoveLeadingBlankLines( TTypeDeclarationSyntax currentTypeNode) { - var syntaxFacts = State.SemanticDocument.Document.GetRequiredLanguageService(); - var bannerService = State.SemanticDocument.Document.GetRequiredLanguageService(); + var syntaxFacts = SemanticDocument.GetRequiredLanguageService(); + var bannerService = SemanticDocument.GetRequiredLanguageService(); var withoutBlankLines = bannerService.GetNodeWithoutLeadingBlankLines(currentTypeNode); diff --git a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeNamespaceScopeEditor.cs b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeNamespaceScopeEditor.cs index 73aa4788eb51b..596ed816f2a80 100644 --- a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeNamespaceScopeEditor.cs +++ b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeNamespaceScopeEditor.cs @@ -20,43 +20,40 @@ internal abstract partial class AbstractMoveTypeService< /// it will evaluate if the namespace scope needs to be closed and reopened to create a new scope. /// private sealed class MoveTypeNamespaceScopeEditor( - TService service, State state, string fileName, CancellationToken cancellationToken) - : Editor(service, state, fileName, cancellationToken) + TService service, + SemanticDocument document, + TTypeDeclarationSyntax typeDeclaration, + string fileName, + CancellationToken cancellationToken) + : Editor(service, document, typeDeclaration, fileName, cancellationToken) { public override async Task GetModifiedSolutionAsync() { - var node = State.TypeNode; - var documentToEdit = State.SemanticDocument.Document; - - if (node.Parent is not TNamespaceDeclarationSyntax namespaceDeclaration) - return null; - - return await GetNamespaceScopeChangedSolutionAsync(namespaceDeclaration, node, documentToEdit, CancellationToken).ConfigureAwait(false); + return TypeDeclaration.Parent is TNamespaceDeclarationSyntax namespaceDeclaration + ? await GetNamespaceScopeChangedSolutionAsync(namespaceDeclaration).ConfigureAwait(false) + : null; } - private static async Task GetNamespaceScopeChangedSolutionAsync( - TNamespaceDeclarationSyntax namespaceDeclaration, - TTypeDeclarationSyntax typeToMove, - Document documentToEdit, - CancellationToken cancellationToken) + private async Task GetNamespaceScopeChangedSolutionAsync( + TNamespaceDeclarationSyntax namespaceDeclaration) { - var syntaxFactsService = documentToEdit.GetRequiredLanguageService(); + var syntaxFactsService = SemanticDocument.GetRequiredLanguageService(); var childNodes = syntaxFactsService.GetMembersOfBaseNamespaceDeclaration(namespaceDeclaration); if (childNodes.Count <= 1) return null; - var editor = await DocumentEditor.CreateAsync(documentToEdit, cancellationToken).ConfigureAwait(false); - editor.RemoveNode(typeToMove, SyntaxRemoveOptions.KeepNoTrivia); + var editor = await DocumentEditor.CreateAsync(SemanticDocument.Document, this.CancellationToken).ConfigureAwait(false); + editor.RemoveNode(this.TypeDeclaration, SyntaxRemoveOptions.KeepNoTrivia); var generator = editor.Generator; - var index = childNodes.IndexOf(typeToMove); + var index = childNodes.IndexOf(this.TypeDeclaration); var itemsBefore = childNodes.Take(index).ToImmutableArray(); var itemsAfter = childNodes.Skip(index + 1).ToImmutableArray(); var name = syntaxFactsService.GetDisplayName(namespaceDeclaration, DisplayNameOptions.IncludeNamespaces); - var newNamespaceDeclaration = generator.NamespaceDeclaration(name, WithElasticTrivia(typeToMove)).WithAdditionalAnnotations(NamespaceScopeMovedAnnotation); + var newNamespaceDeclaration = generator.NamespaceDeclaration(name, WithElasticTrivia(this.TypeDeclaration)).WithAdditionalAnnotations(NamespaceScopeMovedAnnotation); if (itemsBefore.Any() && itemsAfter.Any()) { diff --git a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.RenameFileEditor.cs b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.RenameFileEditor.cs index 031364a87dbd4..73607e6b9e236 100644 --- a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.RenameFileEditor.cs +++ b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.RenameFileEditor.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; @@ -13,29 +11,25 @@ namespace Microsoft.CodeAnalysis.CodeRefactorings.MoveType; internal abstract partial class AbstractMoveTypeService { - private sealed class RenameFileEditor(TService service, State state, string fileName, CancellationToken cancellationToken) : Editor(service, state, fileName, cancellationToken) + /// + /// Renames the file to match the type contained in it. + /// + private sealed class RenameFileEditor( + TService service, + SemanticDocument document, + TTypeDeclarationSyntax typeDeclaration, + string fileName, + CancellationToken cancellationToken) : Editor(service, document, typeDeclaration, fileName, cancellationToken) { - public override Task> GetOperationsAsync() - => Task.FromResult(RenameFileToMatchTypeName()); - - public override Task GetModifiedSolutionAsync() - { - var modifiedSolution = SemanticDocument.Project.Solution - .WithDocumentName(SemanticDocument.Document.Id, FileName); - - return Task.FromResult(modifiedSolution); - } - - /// - /// Renames the file to match the type contained in it. - /// - private ImmutableArray RenameFileToMatchTypeName() + public override async Task> GetOperationsAsync() { - var documentId = SemanticDocument.Document.Id; - var oldSolution = SemanticDocument.Document.Project.Solution; - var newSolution = oldSolution.WithDocumentName(documentId, FileName); - + var newSolution = await GetModifiedSolutionAsync().ConfigureAwait(false); + Contract.ThrowIfNull(newSolution); return [new ApplyChangesOperation(newSolution)]; } + + public override Task GetModifiedSolutionAsync() + => Task.FromResult( + SemanticDocument.Project.Solution.WithDocumentName(SemanticDocument.Document.Id, FileName)); } } diff --git a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.RenameTypeEditor.cs b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.RenameTypeEditor.cs index a7ede6d827d32..6ec382833414d 100644 --- a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.RenameTypeEditor.cs +++ b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.RenameTypeEditor.cs @@ -2,29 +2,32 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Rename; +using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.CodeRefactorings.MoveType; internal abstract partial class AbstractMoveTypeService { - private sealed class RenameTypeEditor(TService service, State state, string fileName, CancellationToken cancellationToken) : Editor(service, state, fileName, cancellationToken) + private sealed class RenameTypeEditor( + TService service, + SemanticDocument document, + TTypeDeclarationSyntax typeDeclaration, + string fileName, + CancellationToken cancellationToken) : Editor(service, document, typeDeclaration, fileName, cancellationToken) { - /// /// Renames a type to match its containing file name. /// - public override async Task GetModifiedSolutionAsync() + public override async Task GetModifiedSolutionAsync() { // TODO: detect conflicts ahead of time and open an inline rename session if any exists. // this will bring up dashboard with conflicts and will allow the user to resolve them. // if no such conflicts exist, proceed with RenameSymbolAsync. - var solution = SemanticDocument.Document.Project.Solution; - var symbol = State.SemanticDocument.SemanticModel.GetDeclaredSymbol(State.TypeNode, CancellationToken); + var solution = SemanticDocument.Project.Solution; + var symbol = SemanticDocument.SemanticModel.GetRequiredDeclaredSymbol(this.TypeDeclaration, CancellationToken); return await Renamer.RenameSymbolAsync(solution, symbol, new SymbolRenameOptions(), FileName, CancellationToken).ConfigureAwait(false); } } diff --git a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.State.cs b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.State.cs deleted file mode 100644 index e7b7c1141a844..0000000000000 --- a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.State.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 System.IO; -using System.Linq; -using System.Threading; -using Microsoft.CodeAnalysis.LanguageService; -using Microsoft.CodeAnalysis.Shared.Extensions; - -namespace Microsoft.CodeAnalysis.CodeRefactorings.MoveType; - -internal abstract partial class AbstractMoveTypeService -{ - private sealed class State - { - public SemanticDocument SemanticDocument { get; } - - public TTypeDeclarationSyntax TypeNode { get; set; } - public string TypeName { get; set; } - public string DocumentNameWithoutExtension { get; set; } - public bool IsDocumentNameAValidIdentifier { get; set; } - - private State(SemanticDocument document) - { - SemanticDocument = document; - } - - internal static State Generate( - SemanticDocument document, TTypeDeclarationSyntax typeDeclaration, - CancellationToken cancellationToken) - { - var state = new State(document); - if (!state.TryInitialize(typeDeclaration, cancellationToken)) - { - return null; - } - - return state; - } - - private bool TryInitialize( - TTypeDeclarationSyntax typeDeclaration, - CancellationToken cancellationToken) - { - if (cancellationToken.IsCancellationRequested) - { - return false; - } - - var tree = SemanticDocument.SyntaxTree; - var root = SemanticDocument.Root; - var syntaxFacts = SemanticDocument.Document.GetLanguageService(); - - // compiler declared types, anonymous types, types defined in metadata should be filtered out. - if (SemanticDocument.SemanticModel.GetDeclaredSymbol(typeDeclaration, cancellationToken) is not INamedTypeSymbol typeSymbol || - typeSymbol.Locations.Any(static loc => loc.IsInMetadata) || - typeSymbol.IsAnonymousType || - typeSymbol.IsImplicitlyDeclared || - typeSymbol.Name == string.Empty) - { - return false; - } - - TypeNode = typeDeclaration; - TypeName = typeSymbol.Name; - DocumentNameWithoutExtension = Path.GetFileNameWithoutExtension(SemanticDocument.Document.Name); - IsDocumentNameAValidIdentifier = syntaxFacts.IsValidIdentifier(DocumentNameWithoutExtension); - - return true; - } - } -} diff --git a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.cs b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.cs index ffc6f4db6dbca..39ff19a2d8b3b 100644 --- a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.cs @@ -11,7 +11,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -38,83 +37,69 @@ internal abstract partial class AbstractMoveTypeService GetRelevantNodeAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken); protected abstract bool IsMemberDeclaration(SyntaxNode syntaxNode); + protected string GetSymbolName(TTypeDeclarationSyntax syntax) + => GetSymbolNameAndArity(syntax).name; + public override async Task> GetRefactoringAsync( Document document, TextSpan textSpan, CancellationToken cancellationToken) { - var state = await CreateStateAsync(document, textSpan, cancellationToken).ConfigureAwait(false); - return CreateActions(state, cancellationToken); + var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); + var typeDeclaration = await GetTypeDeclarationAsync(document, textSpan, cancellationToken).ConfigureAwait(false); + return CreateActions(semanticDocument, typeDeclaration); } public override async Task GetModifiedSolutionAsync(Document document, TextSpan textSpan, MoveTypeOperationKind operationKind, CancellationToken cancellationToken) { - var state = await CreateStateAsync(document, textSpan, cancellationToken).ConfigureAwait(false); - - if (state == null) - { + var typeDeclaration = await GetTypeDeclarationAsync(document, textSpan, cancellationToken).ConfigureAwait(false); + if (typeDeclaration == null) return document.Project.Solution; - } - var suggestedFileNames = GetSuggestedFileNames( - state.TypeNode, - IsNestedType(state.TypeNode), - state.TypeName, - state.SemanticDocument.Document.Name, - state.SemanticDocument.SemanticModel, - cancellationToken); - - var editor = Editor.GetEditor(operationKind, (TService)this, state, suggestedFileNames.FirstOrDefault(), cancellationToken); + var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); + var suggestedFileNames = GetSuggestedFileNames(semanticDocument, typeDeclaration, includeComplexFileNames: false); + + var editor = Editor.GetEditor(operationKind, (TService)this, semanticDocument, typeDeclaration, suggestedFileNames.First(), cancellationToken); var modifiedSolution = await editor.GetModifiedSolutionAsync().ConfigureAwait(false); return modifiedSolution ?? document.Project.Solution; } - private async Task CreateStateAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken) + private async Task GetTypeDeclarationAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken) { var nodeToAnalyze = await GetRelevantNodeAsync(document, textSpan, cancellationToken).ConfigureAwait(false); if (nodeToAnalyze == null) return null; - var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); - return State.Generate(semanticDocument, nodeToAnalyze, cancellationToken); + var name = this.GetSymbolName(nodeToAnalyze); + return name == "" ? null : nodeToAnalyze; } - private ImmutableArray CreateActions(State? state, CancellationToken cancellationToken) + private ImmutableArray CreateActions( + SemanticDocument document, TTypeDeclarationSyntax? typeDeclaration) { - if (state is null) + if (typeDeclaration is null) return []; - var typeMatchesDocumentName = TypeMatchesDocumentName( - state.TypeNode, - state.TypeName, - state.DocumentNameWithoutExtension, - state.SemanticDocument.SemanticModel, - cancellationToken); + var documentNameWithoutExtension = GetDocumentNameWithoutExtension(document); + var typeMatchesDocumentName = TypeMatchesDocumentName(typeDeclaration, documentNameWithoutExtension); + // if type name matches document name, per style conventions, we have nothing to do. if (typeMatchesDocumentName) - { - // if type name matches document name, per style conventions, we have nothing to do. return []; - } using var _ = ArrayBuilder.GetInstance(out var actions); - var manyTypes = MultipleTopLevelTypeDeclarationInSourceDocument(state.SemanticDocument.Root); - var isNestedType = IsNestedType(state.TypeNode); - var syntaxFacts = state.SemanticDocument.Document.GetRequiredLanguageService(); - var isClassNextToGlobalStatements = manyTypes - ? false - : ClassNextToGlobalStatements(state.SemanticDocument.Root, syntaxFacts); + var manyTypes = MultipleTopLevelTypeDeclarationInSourceDocument(document.Root); + var isNestedType = IsNestedType(typeDeclaration); + + var syntaxFacts = document.GetRequiredLanguageService(); + var isClassNextToGlobalStatements = !manyTypes && ClassNextToGlobalStatements(document.Root, syntaxFacts); var suggestedFileNames = GetSuggestedFileNames( - state.TypeNode, - isNestedType, - state.TypeName, - state.SemanticDocument.Document.Name, - state.SemanticDocument.SemanticModel, - cancellationToken); + document, typeDeclaration, includeComplexFileNames: false); // (1) Add Move type to new file code action: // case 1: There are multiple type declarations in current document. offer, move to new file. @@ -126,26 +111,21 @@ private ImmutableArray CreateActions(State? state, CancellationToken if (manyTypes || isNestedType || isClassNextToGlobalStatements) { foreach (var fileName in suggestedFileNames) - { - actions.Add(GetCodeAction(state, fileName, operationKind: MoveTypeOperationKind.MoveType)); - } + actions.Add(GetCodeAction(fileName, operationKind: MoveTypeOperationKind.MoveType)); } // (2) Add rename file and rename type code actions: // Case: No type declaration in file matches the file name. - if (!AnyTopLevelTypeMatchesDocumentName(state, cancellationToken)) + if (!AnyTopLevelTypeMatchesDocumentName()) { foreach (var fileName in suggestedFileNames) - { - actions.Add(GetCodeAction(state, fileName, operationKind: MoveTypeOperationKind.RenameFile)); - } + actions.Add(GetCodeAction(fileName, operationKind: MoveTypeOperationKind.RenameFile)); - // only if the document name can be legal identifier in the language, - // offer to rename type with document name - if (state.IsDocumentNameAValidIdentifier) + // Only if the document name can be legal identifier in the language, offer to rename type with document name + if (syntaxFacts.IsValidIdentifier(documentNameWithoutExtension)) { actions.Add(GetCodeAction( - state, fileName: state.DocumentNameWithoutExtension, + fileName: documentNameWithoutExtension, operationKind: MoveTypeOperationKind.RenameType)); } } @@ -153,14 +133,19 @@ private ImmutableArray CreateActions(State? state, CancellationToken Debug.Assert(actions.Count != 0, "No code actions found for MoveType Refactoring"); return actions.ToImmutableAndClear(); + + bool AnyTopLevelTypeMatchesDocumentName() + => TopLevelTypeDeclarations(document.Root).Any( + typeDeclaration => TypeMatchesDocumentName( + typeDeclaration, documentNameWithoutExtension)); + + MoveTypeCodeAction GetCodeAction(string fileName, MoveTypeOperationKind operationKind) + => new((TService)this, document, typeDeclaration, operationKind, fileName); } private static bool ClassNextToGlobalStatements(SyntaxNode root, ISyntaxFactsService syntaxFacts) => syntaxFacts.ContainsGlobalStatement(root); - private MoveTypeCodeAction GetCodeAction(State state, string fileName, MoveTypeOperationKind operationKind) - => new((TService)this, state, operationKind, fileName); - private static bool IsNestedType(TTypeDeclarationSyntax typeNode) => typeNode.Parent is TTypeDeclarationSyntax; @@ -174,23 +159,10 @@ private static bool MultipleTopLevelTypeDeclarationInSourceDocument(SyntaxNode r => TopLevelTypeDeclarations(root).Skip(1).Any(); private static IEnumerable TopLevelTypeDeclarations(SyntaxNode root) - => root.DescendantNodes(n => n is TCompilationUnitSyntax or TNamespaceDeclarationSyntax) - .OfType(); - - private static bool AnyTopLevelTypeMatchesDocumentName(State state, CancellationToken cancellationToken) - { - var root = state.SemanticDocument.Root; - var semanticModel = state.SemanticDocument.SemanticModel; + => root.DescendantNodes(n => n is TCompilationUnitSyntax or TNamespaceDeclarationSyntax).OfType(); - return TopLevelTypeDeclarations(root).Any( - typeDeclaration => - { - var typeName = semanticModel.GetRequiredDeclaredSymbol(typeDeclaration, cancellationToken).Name; - return TypeMatchesDocumentName( - typeDeclaration, typeName, state.DocumentNameWithoutExtension, - semanticModel, cancellationToken); - }); - } + private static string GetDocumentNameWithoutExtension(SemanticDocument document) + => Path.GetFileNameWithoutExtension(document.Document.Name); /// /// checks if type name matches its parent document name, per style rules. @@ -199,58 +171,90 @@ private static bool AnyTopLevelTypeMatchesDocumentName(State state, Cancellation /// Note: For a nested type, a matching document name could be just the type name or a /// dotted qualified name of its type hierarchy. /// - protected static bool TypeMatchesDocumentName( + protected bool TypeMatchesDocumentName( TTypeDeclarationSyntax typeNode, - string typeName, - string documentNameWithoutExtension, - SemanticModel semanticModel, - CancellationToken cancellationToken) + string documentNameWithoutExtension) { // If it is not a nested type, we compare the unqualified type name with the document name. // If it is a nested type, the type name `Outer.Inner` matches file names `Inner.cs` and `Outer.Inner.cs` - var namesMatch = typeName.Equals(documentNameWithoutExtension, StringComparison.CurrentCulture); - if (!namesMatch) - { - var typeNameParts = GetTypeNamePartsForNestedTypeNode(typeNode, semanticModel, cancellationToken); - var fileNameParts = documentNameWithoutExtension.Split('.'); + var (typeName, arity) = GetSymbolNameAndArity(typeNode); + if (TypeNameMatches(documentNameWithoutExtension, typeName, arity)) + return true; + + var typeNameParts = GetTypeNamePartsForNestedTypeNode(typeNode).ToImmutableArray(); + var fileNameParts = documentNameWithoutExtension.Split('.', '+'); - // qualified type name `Outer.Inner` matches file names `Inner.cs` and `Outer.Inner.cs` - return typeNameParts.SequenceEqual(fileNameParts, StringComparer.CurrentCulture); + if (typeNameParts.Length != fileNameParts.Length) + return false; + + // qualified type name `Outer.Inner` matches file names `Inner.cs` and `Outer.Inner.cs` as well as + // Outer`1.Inner`2.cs + for (int i = 0, n = typeNameParts.Length; i < n; i++) + { + if (!TypeNameMatches(fileNameParts[i], typeNameParts[i].name, typeNameParts[i].arity)) + return false; } - return namesMatch; + return true; + } + + private static bool TypeNameMatches(string documentNameWithoutExtension, string typeName, int arity) + { + if (typeName.Equals(documentNameWithoutExtension, StringComparison.CurrentCulture)) + return true; + + if ($"{typeName}`{arity}".Equals(documentNameWithoutExtension, StringComparison.CurrentCulture)) + return true; + + return false; } - private static ImmutableArray GetSuggestedFileNames( + private ImmutableArray GetSuggestedFileNames( + SemanticDocument document, TTypeDeclarationSyntax typeNode, - bool isNestedType, - string typeName, - string documentNameWithExtension, - SemanticModel semanticModel, - CancellationToken cancellationToken) + bool includeComplexFileNames) { + var documentNameWithExtension = document.Document.Name; + var isNestedType = IsNestedType(typeNode); + var (typeName, arity) = this.GetSymbolNameAndArity(typeNode); var fileExtension = Path.GetExtension(documentNameWithExtension); var standaloneName = typeName + fileExtension; - // If it is a nested type, we should match type hierarchy's name parts with the file name. + using var _ = ArrayBuilder.GetInstance(out var suggestedFileNames); + + suggestedFileNames.Add(typeName + fileExtension); + if (includeComplexFileNames && arity > 0) + suggestedFileNames.Add($"{typeName}`{arity}{fileExtension}"); + if (isNestedType) { - var typeNameParts = GetTypeNamePartsForNestedTypeNode(typeNode, semanticModel, cancellationToken); - var dottedName = typeNameParts.Join(".") + fileExtension; + var typeNameParts = GetTypeNamePartsForNestedTypeNode(typeNode); + AddNameParts(typeNameParts.Select(t => t.name)); + + if (includeComplexFileNames && typeNameParts.Any(t => t.arity > 0)) + AddNameParts(typeNameParts.Select(t => t.arity > 0 ? $"{t.name}`{t.arity}" : t.name)); + } + + return suggestedFileNames.ToImmutableAndClear(); + + void AddNameParts(IEnumerable parts) + { + AddNamePartsWithSeparator(parts, "."); - return [standaloneName, dottedName]; + if (includeComplexFileNames) + AddNamePartsWithSeparator(parts, "+"); } - else + + void AddNamePartsWithSeparator(IEnumerable parts, string separator) { - return [standaloneName]; + suggestedFileNames.Add(parts.Join(separator) + fileExtension); } } - private static IEnumerable GetTypeNamePartsForNestedTypeNode( - TTypeDeclarationSyntax typeNode, SemanticModel semanticModel, CancellationToken cancellationToken) - => typeNode.AncestorsAndSelf() - .OfType() - .Select(n => semanticModel.GetRequiredDeclaredSymbol(n, cancellationToken).Name) - .Reverse(); + private IEnumerable<(string name, int arity)> GetTypeNamePartsForNestedTypeNode(TTypeDeclarationSyntax typeNode) + => typeNode.AncestorsAndSelf() + .OfType() + .Select(GetSymbolNameAndArity) + .Reverse(); } diff --git a/src/Features/Core/Portable/CodeRefactorings/MoveType/IMoveTypeService.cs b/src/Features/Core/Portable/CodeRefactorings/MoveType/IMoveTypeService.cs index 23c02bfa1ca52..51674c63f44a6 100644 --- a/src/Features/Core/Portable/CodeRefactorings/MoveType/IMoveTypeService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/MoveType/IMoveTypeService.cs @@ -2,13 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/Core/Portable/CodeRefactorings/PredefinedCodeRefactoringProviderNames.cs b/src/Features/Core/Portable/CodeRefactorings/PredefinedCodeRefactoringProviderNames.cs index 019ad957c381e..559eb5f952faa 100644 --- a/src/Features/Core/Portable/CodeRefactorings/PredefinedCodeRefactoringProviderNames.cs +++ b/src/Features/Core/Portable/CodeRefactorings/PredefinedCodeRefactoringProviderNames.cs @@ -30,6 +30,7 @@ internal static class PredefinedCodeRefactoringProviderNames public const string ConvertNumericLiteral = nameof(ConvertNumericLiteral); public const string ConvertPlaceholderToInterpolatedString = nameof(ConvertPlaceholderToInterpolatedString); public const string ConvertPrimaryToRegularConstructor = nameof(ConvertPrimaryToRegularConstructor); + public const string ConvertToExtension = nameof(ConvertToExtension); public const string ConvertToInterpolatedString = "Convert To Interpolated String Code Action Provider"; public const string ConvertToProgramMain = "Convert To Program.Main"; public const string ConvertToRawString = nameof(ConvertToRawString); diff --git a/src/Features/Core/Portable/CodeRefactorings/ServicesLayerCodeActionHelpersService.cs b/src/Features/Core/Portable/CodeRefactorings/ServicesLayerCodeActionHelpersService.cs index d881ce4234945..67c4c3e5664bc 100644 --- a/src/Features/Core/Portable/CodeRefactorings/ServicesLayerCodeActionHelpersService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/ServicesLayerCodeActionHelpersService.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.Composition; using Microsoft.CodeAnalysis.Host; diff --git a/src/Features/Core/Portable/CodeRefactorings/WorkspaceServices/IAddMetadataReferenceCodeActionOperationFactoryWorkspaceService.cs b/src/Features/Core/Portable/CodeRefactorings/WorkspaceServices/IAddMetadataReferenceCodeActionOperationFactoryWorkspaceService.cs index 059a65cac955c..414ff17bdc7cd 100644 --- a/src/Features/Core/Portable/CodeRefactorings/WorkspaceServices/IAddMetadataReferenceCodeActionOperationFactoryWorkspaceService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/WorkspaceServices/IAddMetadataReferenceCodeActionOperationFactoryWorkspaceService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.CodeActions.WorkspaceServices; diff --git a/src/Features/Core/Portable/CodeRefactorings/WorkspaceServices/ISymbolRenamedCodeActionOperationFactoryWorkspaceService.cs b/src/Features/Core/Portable/CodeRefactorings/WorkspaceServices/ISymbolRenamedCodeActionOperationFactoryWorkspaceService.cs index 48de894b7db0f..8a6f7e5670348 100644 --- a/src/Features/Core/Portable/CodeRefactorings/WorkspaceServices/ISymbolRenamedCodeActionOperationFactoryWorkspaceService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/WorkspaceServices/ISymbolRenamedCodeActionOperationFactoryWorkspaceService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.CodeActions.WorkspaceServices; diff --git a/src/Features/Core/Portable/Common/GlyphExtensions.cs b/src/Features/Core/Portable/Common/GlyphExtensions.cs index 6f5fde9a39849..66f610befa68b 100644 --- a/src/Features/Core/Portable/Common/GlyphExtensions.cs +++ b/src/Features/Core/Portable/Common/GlyphExtensions.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using Microsoft.CodeAnalysis.Tags; diff --git a/src/Features/Core/Portable/Common/GlyphTags.cs b/src/Features/Core/Portable/Common/GlyphTags.cs index d84cc4d3b6aaf..d7737b9b4ac31 100644 --- a/src/Features/Core/Portable/Common/GlyphTags.cs +++ b/src/Features/Core/Portable/Common/GlyphTags.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using Microsoft.CodeAnalysis.Tags; diff --git a/src/Features/Core/Portable/Common/TextTags.cs b/src/Features/Core/Portable/Common/TextTags.cs index 105ee48bcf446..d280725037810 100644 --- a/src/Features/Core/Portable/Common/TextTags.cs +++ b/src/Features/Core/Portable/Common/TextTags.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; /// diff --git a/src/Features/Core/Portable/Completion/CompletionChange.cs b/src/Features/Core/Portable/Completion/CompletionChange.cs index 34c86ae91789c..489acd9982f58 100644 --- a/src/Features/Core/Portable/Completion/CompletionChange.cs +++ b/src/Features/Core/Portable/Completion/CompletionChange.cs @@ -31,7 +31,13 @@ public sealed class CompletionChange /// The new caret position after the change has been applied. /// If null then the new caret position will be determined by the completion host. /// - public int? NewPosition { get; } + public int? NewPosition { get => NewSelection?.End; } + + /// + /// The new selection after the change has been applied. + /// If null then the new caret position will be determined by the completion host. + /// + internal TextSpan? NewSelection { get; } /// /// True if the changes include the typed character that caused the @@ -50,9 +56,15 @@ private CompletionChange( private CompletionChange( TextChange textChange, ImmutableArray textChanges, int? newPosition, bool includesCommitCharacter, ImmutableDictionary properties) + : this(textChange, textChanges, newPosition != null ? new TextSpan(newPosition.Value, 0) : null, includesCommitCharacter, properties) + { + } + + private CompletionChange( + TextChange textChange, ImmutableArray textChanges, TextSpan? newSelection, bool includesCommitCharacter, ImmutableDictionary properties) { TextChange = textChange; - NewPosition = newPosition; + NewSelection = newSelection; IncludesCommitCharacter = includesCommitCharacter; TextChanges = textChanges.NullToEmpty(); if (TextChanges.IsEmpty) @@ -106,6 +118,16 @@ public static CompletionChange Create( return new CompletionChange(textChange, textChanges, newPosition, includesCommitCharacter); } + internal static CompletionChange Create( + TextChange textChange, + ImmutableArray textChanges, + ImmutableDictionary properties, + TextSpan? newSpan = null, + bool includesCommitCharacter = false) + { + return new CompletionChange(textChange, textChanges, newSpan, includesCommitCharacter, properties); + } + internal static CompletionChange Create( TextChange textChange, ImmutableArray textChanges, diff --git a/src/Features/Core/Portable/Completion/CompletionOptions.cs b/src/Features/Core/Portable/Completion/CompletionOptions.cs index e625ab9819d59..bc674c7ff9778 100644 --- a/src/Features/Core/Portable/Completion/CompletionOptions.cs +++ b/src/Features/Core/Portable/Completion/CompletionOptions.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.Immutable; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Recommendations; using Microsoft.CodeAnalysis.Shared; diff --git a/src/Features/Core/Portable/Completion/CompletionService.ProviderManager.cs b/src/Features/Core/Portable/Completion/CompletionService.ProviderManager.cs index 3eb3abbd0a57f..546ffa37175d9 100644 --- a/src/Features/Core/Portable/Completion/CompletionService.ProviderManager.cs +++ b/src/Features/Core/Portable/Completion/CompletionService.ProviderManager.cs @@ -16,6 +16,7 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Shared.Utilities; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Completion; diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractAggregateEmbeddedLanguageCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractAggregateEmbeddedLanguageCompletionProvider.cs index ed1a97629f109..c920fce114139 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractAggregateEmbeddedLanguageCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractAggregateEmbeddedLanguageCompletionProvider.cs @@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Completion.Providers; diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractCrefCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractCrefCompletionProvider.cs index 55db699a45d8a..e32dfa6ef5b15 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractCrefCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractCrefCompletionProvider.cs @@ -6,8 +6,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.LanguageService; -using Microsoft.CodeAnalysis.Options; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Completion.Providers; diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractKeywordCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractKeywordCompletionProvider.cs index b3864d7dcf94e..84fe32c5f955d 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractKeywordCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractKeywordCompletionProvider.cs @@ -54,7 +54,7 @@ private async Task> RecommendKeywordsAsync( TContext context, CancellationToken cancellationToken) { - var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); + var syntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var syntaxFacts = document.GetRequiredLanguageService(); if (syntaxFacts.IsInNonUserCode(syntaxTree, position, cancellationToken)) return []; diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractMemberInsertingCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractMemberInsertingCompletionProvider.cs index f2a5475f289e3..7760cc453e3b2 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractMemberInsertingCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractMemberInsertingCompletionProvider.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; +using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -37,7 +38,8 @@ internal abstract partial class AbstractMemberInsertingCompletionProvider : LSPC protected abstract Task GenerateMemberAsync( Document document, CompletionItem item, Compilation compilation, ISymbol member, INamedTypeSymbol containingType, CancellationToken cancellationToken); - protected abstract int GetTargetCaretPosition(SyntaxNode caretTarget); + protected abstract TextSpan GetTargetSelectionSpan(SyntaxNode caretTarget); + protected abstract SyntaxNode GetSyntax(SyntaxToken commonSyntaxToken); protected static CompletionItemRules GetRules() @@ -45,35 +47,17 @@ protected static CompletionItemRules GetRules() public override async Task GetChangeAsync(Document document, CompletionItem item, char? commitKey = null, CancellationToken cancellationToken = default) { - var newDocument = await DetermineNewDocumentAsync(document, item, cancellationToken).ConfigureAwait(false); + var (newDocument, newSpan) = await DetermineNewDocumentAsync(document, item, cancellationToken).ConfigureAwait(false); var newText = await newDocument.GetValueTextAsync(cancellationToken).ConfigureAwait(false); - var newRoot = await newDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - - int? newPosition = null; - - // Attempt to find the inserted node and move the caret appropriately - if (newRoot != null) - { - var caretTarget = newRoot.GetAnnotatedNodes(_annotation).FirstOrDefault(); - if (caretTarget != null) - { - var targetPosition = GetTargetCaretPosition(caretTarget); - - if (targetPosition > 0 && targetPosition <= newText.Length) - { - newPosition = targetPosition; - } - } - } var changes = await newDocument.GetTextChangesAsync(document, cancellationToken).ConfigureAwait(false); var changesArray = changes.ToImmutableArray(); var change = Utilities.Collapse(newText, changesArray); - return CompletionChange.Create(change, changesArray, newPosition, includesCommitCharacter: true); + return CompletionChange.Create(change, changesArray, properties: ImmutableDictionary.Empty, newSpan, includesCommitCharacter: true); } - private async Task DetermineNewDocumentAsync( + private async Task<(Document, TextSpan? caretPosition)> DetermineNewDocumentAsync( Document document, CompletionItem completionItem, CancellationToken cancellationToken) @@ -122,15 +106,13 @@ private async Task DetermineNewDocumentAsync( // Generating the new document failed because we somehow couldn't resolve // the underlying symbol's SymbolKey. At this point, we won't be able to // make any changes, so just return the document we started with. - return document; + return (document, null); } var memberContainingDocumentCleanupOptions = await document.GetCodeCleanupOptionsAsync(cancellationToken).ConfigureAwait(false); - document = await RemoveDestinationNodeAsync(memberContainingDocument, memberContainingDocumentCleanupOptions, cancellationToken).ConfigureAwait(false); - var formattingOptions = await document.GetSyntaxFormattingOptionsAsync(cancellationToken).ConfigureAwait(false); - document = await Simplifier.ReduceAsync(document, _annotation, memberContainingDocumentCleanupOptions.SimplifierOptions, cancellationToken).ConfigureAwait(false); - return await Formatter.FormatAsync(document, _annotation, formattingOptions, cancellationToken).ConfigureAwait(false); + var result = await RemoveDestinationNodeAsync(memberContainingDocument, memberContainingDocumentCleanupOptions, cancellationToken).ConfigureAwait(false); + return result; } private async Task GenerateMemberAndUsingsAsync( @@ -187,41 +169,88 @@ private TextSpan ComputeDestinationSpan(SyntaxNode insertionRoot) return TextSpan.FromBounds(startToken.Value.SpanStart, line.EndIncludingLineBreak); } - private async Task RemoveDestinationNodeAsync( + private async Task<(Document Document, TextSpan? Selection)> RemoveDestinationNodeAsync( Document memberContainingDocument, CodeCleanupOptions cleanupOptions, CancellationToken cancellationToken) { - // At this stage we have created the replacing node, but we also have the source node that triggered the completion - // To remove the old node, we need to port over the trivia and then recalculate the node to remove - // since we may have adjusted the position of the node by inserting trivia before the new node - + // We now have a replacement node inserted into the document, but we still have the source code that triggered completion (with associated trivia). + // We need to move the trivia to the new replacement and remove the original code. var root = await memberContainingDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + + // Compute the destination span and node in the new tree. Depending on the context, the destination node can end up + // containing more code (and trivia) than what we want to remove. For example + // ``` + // override Eq + // [Attribute] public void M() {} + // ``` + // returns a destination node (array syntax) containing both the `override Eq` and the `[Attribute]` on the line below. var destinationSpan = ComputeDestinationSpan(root); var destinationNode = root.FindNode(destinationSpan, true); + var syntaxFacts = memberContainingDocument.Project.Services.GetRequiredService(); + + // Given that the destination node can contain code we want to keep, we can't directly remove it using syntax tree manipulations. + // It is difficult to create a valid syntax tree manipulation that does only a partial removal of the destination node / tokens. + // + // Instead it is much easier to remove the old completion source with a direct text edit (we know the exact span). + // But in order to do that, we first must move trivia to the replacement node and format/simplify (requires tree annotations). + + // First find all tokens inside the node that intersect the span being deleted. Move trivia from these tokens to the replacement node. + // Tokens from the destination node, but outside the destination span should not be touched. + var destinationTokens = destinationNode.DescendantTokens(destinationSpan); + + SyntaxTriviaList leadingTriviaToCopy = []; + SyntaxTriviaList trailingTriviaToCopy = []; + root = root.ReplaceTokens(destinationTokens, (original, originalAdjusted) => + { + // Save the trivia for later application onto the replacement node and then delete. + leadingTriviaToCopy = leadingTriviaToCopy.AddRange(original.LeadingTrivia); + trailingTriviaToCopy = trailingTriviaToCopy.AddRange(original.TrailingTrivia); + + var trailingEndOfLine = originalAdjusted.TrailingTrivia.FirstOrNull(t => syntaxFacts.IsEndOfLineTrivia(t)); + var destinationWithoutTrivia = originalAdjusted.WithoutTrivia(); + // If there was an end of line attached to the destination token, keep it as otherwise lines below + // may get moved up to the same line as the destination span line we're removing later. + if (trailingEndOfLine is not null) + destinationWithoutTrivia = destinationWithoutTrivia.WithTrailingTrivia(trailingEndOfLine.Value); + return destinationWithoutTrivia; + }); + + // Add the saved trivia on to the replacement node. var replacingNode = root.GetAnnotatedNodes(_annotation).Single(); - // WithTriviaFrom does not completely fit our purpose because we could be missing trivia from interior missing tokens, - // with all the last tokens being missing, and thus only having part of the picture - root = root.ReplaceNode(replacingNode, replacingNode.WithTriviaFromIncludingMissingTokens(destinationNode)); + root = root.ReplaceNode(replacingNode, replacingNode.WithLeadingTrivia(leadingTriviaToCopy).WithTrailingTrivia(trailingTriviaToCopy)); + + // We've finished the major modifications, we can now format and simplify. + var document = memberContainingDocument.WithSyntaxRoot(root); + document = await Simplifier.ReduceAsync(document, Simplifier.Annotation, cleanupOptions.SimplifierOptions, cancellationToken).ConfigureAwait(false); + document = await Formatter.FormatAsync(document, Formatter.Annotation, cleanupOptions.FormattingOptions, cancellationToken).ConfigureAwait(false); - // Now that we have replaced the node, find the destination node again + // Formatting/simplification changed the tree, so recompute the destination span. + root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); destinationSpan = ComputeDestinationSpan(root); - destinationNode = root.FindNode(destinationSpan); - SyntaxNode newRoot; - if (destinationSpan.Contains(destinationNode.Span)) - { - newRoot = root.RemoveNode(destinationNode, SyntaxRemoveOptions.KeepNoTrivia)!; - } - else + var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); + + // We have basically the final tree. Calculate the new caret position while we still have the annotations. + TextSpan? newSpan = null; + var caretTarget = root.GetAnnotatedNodes(_annotation).FirstOrDefault(); + if (caretTarget != null) { - var tokens = destinationNode.DescendantTokens(destinationSpan); - newRoot = root.ReplaceTokens(tokens, static (_, _) => default); - } + var targetSelectionSpan = GetTargetSelectionSpan(caretTarget); - var document = memberContainingDocument.WithSyntaxRoot(newRoot); + if (targetSelectionSpan.Start > 0 && targetSelectionSpan.End <= text.Length) + { + // The new replacement method should always be inserted before the destination span we're removing. + // This means the end selection position in the inserted method should be safe to return as-is. + Debug.Assert(targetSelectionSpan.End < destinationSpan.Start); + newSpan = targetSelectionSpan; + } + } - document = await Simplifier.ReduceAsync(document, Simplifier.Annotation, cleanupOptions.SimplifierOptions, cancellationToken).ConfigureAwait(false); - document = await Formatter.FormatAsync(document, Formatter.Annotation, cleanupOptions.FormattingOptions, cancellationToken).ConfigureAwait(false); + // Now we can finally delete the destination span. It is safe to delete the whole line here (instead of just the destination span) + // as override completion will not be shown with unrelated text preceding or following the override trigger. + text.GetLineAndOffset(destinationSpan.Start, out var lineNumber, out _); + var textChange = new TextChange(text.Lines[lineNumber].SpanIncludingLineBreak, string.Empty); - return document; + text = text.WithChanges(textChange); + return (document.WithText(text), newSpan); } internal override Task GetDescriptionWorkerAsync(Document document, CompletionItem item, CompletionOptions options, SymbolDescriptionOptions displayOptions, CancellationToken cancellationToken) diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractOverrideCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractOverrideCompletionProvider.cs index c5d077a6e7208..063f7796c3a79 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractOverrideCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractOverrideCompletionProvider.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Completion.Providers; diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractRecommendationServiceBasedCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractRecommendationServiceBasedCompletionProvider.cs index 584deebb8a09d..98384794866e5 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractRecommendationServiceBasedCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractRecommendationServiceBasedCompletionProvider.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractImportCompletionCacheServiceFactory.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractImportCompletionCacheServiceFactory.cs index e91c21220a3bb..4799c399e5108 100644 --- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractImportCompletionCacheServiceFactory.cs +++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractImportCompletionCacheServiceFactory.cs @@ -11,7 +11,7 @@ using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.TestHooks; -using Roslyn.Utilities; +using Microsoft.CodeAnalysis.Threading; namespace Microsoft.CodeAnalysis.Completion.Providers; diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/IImportCompletionCacheService.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/IImportCompletionCacheService.cs index 64b2d8787533e..7c3bb764c5faa 100644 --- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/IImportCompletionCacheService.cs +++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/IImportCompletionCacheService.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using Microsoft.CodeAnalysis.Host; -using Roslyn.Utilities; +using Microsoft.CodeAnalysis.Threading; namespace Microsoft.CodeAnalysis.Completion.Providers; diff --git a/src/Features/Core/Portable/Completion/Providers/Scripting/AbstractLoadDirectiveCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/Scripting/AbstractLoadDirectiveCompletionProvider.cs index f94d6a005db03..72bc45690570d 100644 --- a/src/Features/Core/Portable/Completion/Providers/Scripting/AbstractLoadDirectiveCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/Scripting/AbstractLoadDirectiveCompletionProvider.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Shared.Collections; diff --git a/src/Features/Core/Portable/Completion/Providers/Scripting/GlobalAssemblyCacheCompletionHelper.cs b/src/Features/Core/Portable/Completion/Providers/Scripting/GlobalAssemblyCacheCompletionHelper.cs index dcc1e89aa24b9..a0aa0b1fd4684 100644 --- a/src/Features/Core/Portable/Completion/Providers/Scripting/GlobalAssemblyCacheCompletionHelper.cs +++ b/src/Features/Core/Portable/Completion/Providers/Scripting/GlobalAssemblyCacheCompletionHelper.cs @@ -2,13 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.PooledObjects; diff --git a/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs b/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs index a4ce028eefdb4..0d8ad3bde2e12 100644 --- a/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs +++ b/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs @@ -24,7 +24,7 @@ internal static class SymbolCompletionItem private static readonly Action, ArrayBuilder>> s_addSymbolEncoding = AddSymbolEncoding; private static readonly Action, ArrayBuilder>> s_addSymbolInfo = AddSymbolInfo; - private static readonly char[] s_projectSeperators = [';']; + private const char ProjectSeperatorChar = ';'; private static CompletionItem CreateWorker( string displayText, @@ -236,13 +236,45 @@ private static void AddSupportedPlatforms(ArrayBuilder ProjectId.CreateFromSerialized(Guid.Parse(s))), - candidateProjects.Split(s_projectSeperators).SelectAsArray(s => ProjectId.CreateFromSerialized(Guid.Parse(s)))); + SplitIntoProjectIds(invalidProjects), + SplitIntoProjectIds(candidateProjects)); } return null; } + private static ImmutableArray SplitIntoProjectIds(string projectIds) + { + // Does the equivalent of string.Split, with fewer allocations + var start = 0; + var current = 0; + using var _ = ArrayBuilder.GetInstance(out var builder); + + while (current < projectIds.Length) + { + if (projectIds[current] == ProjectSeperatorChar) + { + if (start != current) + { + var projectGuid = Guid.Parse(projectIds.Substring(start, current - start)); + builder.Add(ProjectId.CreateFromSerialized(projectGuid)); + } + + start = current + 1; + } + + current++; + } + + if (start != current) + { + var projectGuid = Guid.Parse(projectIds.Substring(start, current - start)); + builder.Add(ProjectId.CreateFromSerialized(projectGuid)); + } + + return builder.ToImmutableAndClear(); + } + public static int GetContextPosition(CompletionItem item) { if (item.TryGetProperty("ContextPosition", out var text) && diff --git a/src/Features/Core/Portable/ConvertAutoPropertyToFullProperty/AbstractConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertAutoPropertyToFullProperty/AbstractConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs index 9fdb11ae24361..1275577e9282f 100644 --- a/src/Features/Core/Portable/ConvertAutoPropertyToFullProperty/AbstractConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertAutoPropertyToFullProperty/AbstractConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs @@ -99,9 +99,9 @@ private async Task ExpandToFullPropertyAsync( var fieldName = await GetFieldNameAsync(document, propertySymbol, cancellationToken).ConfigureAwait(false); var (newGetAccessor, newSetAccessor) = GetNewAccessors(info, property, fieldName, cancellationToken); - editor.ReplaceNode( - property, - CreateFinalProperty(document, property, info, newGetAccessor, newSetAccessor)); + var finalProperty = CreateFinalProperty( + document, GetPropertyWithoutInitializer(property), info, newGetAccessor, newSetAccessor); + editor.ReplaceNode(property, finalProperty); // add backing field, plus initializer if it exists var newField = CodeGenerationSymbolFactory.CreateFieldSymbol( @@ -137,7 +137,7 @@ protected SyntaxNode CreateFinalProperty( var fullProperty = generator .WithAccessorDeclarations( - GetPropertyWithoutInitializer(property), + property, newSetAccessor == null ? [newGetAccessor] : [newGetAccessor, newSetAccessor]) diff --git a/src/Features/Core/Portable/ConvertLinq/ConvertForEachToLinqQuery/ForEachInfo.cs b/src/Features/Core/Portable/ConvertLinq/ConvertForEachToLinqQuery/ForEachInfo.cs index 492de0fb3fcf0..147b0f645195e 100644 --- a/src/Features/Core/Portable/ConvertLinq/ConvertForEachToLinqQuery/ForEachInfo.cs +++ b/src/Features/Core/Portable/ConvertLinq/ConvertForEachToLinqQuery/ForEachInfo.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; namespace Microsoft.CodeAnalysis.ConvertLinq.ConvertForEachToLinqQuery; diff --git a/src/Features/Core/Portable/ConvertToInterpolatedString/AbstractConvertPlaceholderToInterpolatedStringRefactoringProvider.cs b/src/Features/Core/Portable/ConvertToInterpolatedString/AbstractConvertPlaceholderToInterpolatedStringRefactoringProvider.cs index 6f6906bec80e7..45f15e9dc395f 100644 --- a/src/Features/Core/Portable/ConvertToInterpolatedString/AbstractConvertPlaceholderToInterpolatedStringRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertToInterpolatedString/AbstractConvertPlaceholderToInterpolatedStringRefactoringProvider.cs @@ -9,12 +9,15 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ConvertToInterpolatedString; @@ -26,7 +29,7 @@ internal abstract class AbstractConvertPlaceholderToInterpolatedStringRefactorin TInterpolatedStringExpressionSyntax, TArgumentSyntax, TArgumentListExpressionSyntax, - TInterpolationSyntax> : CodeRefactoringProvider + TInterpolationSyntax> : SyntaxEditorBasedCodeRefactoringProvider where TExpressionSyntax : SyntaxNode where TLiteralExpressionSyntax : TExpressionSyntax where TInvocationExpressionSyntax : TExpressionSyntax @@ -35,29 +38,32 @@ internal abstract class AbstractConvertPlaceholderToInterpolatedStringRefactorin where TArgumentListExpressionSyntax : SyntaxNode where TInterpolationSyntax : SyntaxNode { - protected abstract TExpressionSyntax ParseExpression(string text); + private readonly record struct InvocationData( + TInvocationExpressionSyntax Invocation, + TArgumentSyntax PlaceholderArgument, + IMethodSymbol InvocationSymbol, + TInterpolatedStringExpressionSyntax InterpolatedString, + bool ShouldReplaceInvocation); - public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) - { - var (document, span, cancellationToken) = context; - var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + protected abstract TExpressionSyntax ParseExpression(string text); - var stringType = semanticModel.Compilation.GetSpecialType(SpecialType.System_String); - if (stringType.IsErrorType()) - return; + protected override ImmutableArray SupportedFixAllScopes { get; } = AllFixAllScopes; + private InvocationData? AnalyzeInvocation( + Document document, + SemanticModel semanticModel, + TInvocationExpressionSyntax invocation, + TArgumentSyntax placeholderArgument, + CancellationToken cancellationToken) + { var syntaxFacts = document.GetRequiredLanguageService(); - var (invocation, placeholderArgument) = await TryFindInvocationAsync().ConfigureAwait(false); - if (invocation is null || placeholderArgument is null) - return; - var placeholderExpression = syntaxFacts.GetExpressionOfArgument(placeholderArgument); var stringToken = placeholderExpression.GetFirstToken(); // don't offer if the string argument has errors in it, or if converting it to an interpolated string creates errors. if (stringToken.GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error)) - return; + return null; // Not supported if there are any omitted arguments following the placeholder. var arguments = syntaxFacts.GetArgumentsOfInvocationExpression(invocation); @@ -67,14 +73,14 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte { var argument = arguments[i]; if (syntaxFacts.GetExpressionOfArgument(argument) is null) - return; + return null; if (syntaxFacts.GetRefKindOfArgument(argument) != RefKind.None) - return; + return null; } if (semanticModel.GetSymbolInfo(invocation, cancellationToken).GetAnySymbol() is not IMethodSymbol invocationSymbol) - return; + return null; // If the user is actually passing an array to a params argument, we can't change this to be an interpolated string. if (invocationSymbol.IsParams()) @@ -82,31 +88,52 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte var lastArgument = syntaxFacts.GetArgumentsOfInvocationExpression(invocation).Last(); var lastArgumentType = semanticModel.GetTypeInfo(syntaxFacts.GetExpressionOfArgument(lastArgument), cancellationToken).Type; if (lastArgumentType is IArrayTypeSymbol) - return; + return null; } // if the user is explicitly passing in a CultureInfo, don't offer as it's likely they want specialized // formatting for the values. foreach (var argument in arguments) { - var type = semanticModel.GetTypeInfo(syntaxFacts.GetExpressionOfArgument(argument)).Type; + var type = semanticModel.GetTypeInfo(syntaxFacts.GetExpressionOfArgument(argument), cancellationToken).Type; if (type is { Name: nameof(CultureInfo), ContainingNamespace.Name: nameof(System.Globalization), ContainingNamespace.ContainingNamespace.Name: nameof(System) }) - return; + return null; } if (ParseExpression("$" + stringToken.Text) is not TInterpolatedStringExpressionSyntax interpolatedString) - return; + return null; if (interpolatedString.GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error)) - return; + return null; var shouldReplaceInvocation = invocationSymbol is { ContainingType.SpecialType: SpecialType.System_String, Name: nameof(string.Format) }; + return new(invocation, placeholderArgument, invocationSymbol, interpolatedString, shouldReplaceInvocation); + } + + public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) + { + var (document, span, cancellationToken) = context; + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + + var stringType = semanticModel.Compilation.GetSpecialType(SpecialType.System_String); + if (stringType.IsErrorType()) + return; + + var syntaxFacts = document.GetRequiredLanguageService(); + + var (invocation, placeholderArgument) = await TryFindInvocationAsync().ConfigureAwait(false); + if (invocation is null || placeholderArgument is null) + return; + + var data = this.AnalyzeInvocation(document, semanticModel, invocation, placeholderArgument, cancellationToken); + if (data is null) + return; + context.RegisterRefactoring( CodeAction.Create( FeaturesResources.Convert_to_interpolated_string, - cancellationToken => CreateInterpolatedStringAsync( - document, invocation, placeholderArgument, invocationSymbol, interpolatedString, shouldReplaceInvocation, cancellationToken), + cancellationToken => CreateInterpolatedStringAsync(document, data.Value, cancellationToken), nameof(FeaturesResources.Convert_to_interpolated_string)), invocation.Span); @@ -118,7 +145,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte var invocations = await document.GetRelevantNodesAsync(span, cancellationToken).ConfigureAwait(false); foreach (var invocation in invocations) { - var placeholderArgument = FindValidPlaceholderArgument(invocation); + var placeholderArgument = FindValidPlaceholderArgument(syntaxFacts, invocation, cancellationToken); if (placeholderArgument != null) return (invocation, placeholderArgument); } @@ -127,7 +154,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte // User selected a single argument of the invocation (expression / format string) instead of the whole invocation. var selectedArgument = await document.TryGetRelevantNodeAsync(span, cancellationToken).ConfigureAwait(false); var invocation = selectedArgument?.Parent?.Parent as TInvocationExpressionSyntax; - var placeholderArgument = FindValidPlaceholderArgument(invocation); + var placeholderArgument = FindValidPlaceholderArgument(syntaxFacts, invocation, cancellationToken); if (placeholderArgument != null) return (invocation, placeholderArgument); } @@ -136,47 +163,52 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte // User selected the whole argument list: string format with placeholders plus all expressions var argumentList = await document.TryGetRelevantNodeAsync(span, cancellationToken).ConfigureAwait(false); var invocation = argumentList?.Parent as TInvocationExpressionSyntax; - var placeholderArgument = FindValidPlaceholderArgument(invocation); + var placeholderArgument = FindValidPlaceholderArgument(syntaxFacts, invocation, cancellationToken); if (placeholderArgument != null) return (invocation, placeholderArgument); } return default; } + } - TArgumentSyntax? FindValidPlaceholderArgument(TInvocationExpressionSyntax? invocation) + private static TArgumentSyntax? FindValidPlaceholderArgument( + ISyntaxFacts syntaxFacts, TInvocationExpressionSyntax? invocation, CancellationToken cancellationToken) + { + if (invocation != null) { - if (invocation != null) + // look for a string argument containing `"...{0}..."`, followed by more arguments. + var arguments = (SeparatedSyntaxList)syntaxFacts.GetArgumentsOfInvocationExpression(invocation); + for (int i = 0, n = arguments.Count - 1; i < n; i++) { - // look for a string argument containing `"...{0}..."`, followed by more arguments. - var arguments = (SeparatedSyntaxList)syntaxFacts.GetArgumentsOfInvocationExpression(invocation); - for (int i = 0, n = arguments.Count - 1; i < n; i++) + cancellationToken.ThrowIfCancellationRequested(); + + var argument = arguments[i]; + var expression = syntaxFacts.GetExpressionOfArgument(argument); + if (syntaxFacts.IsStringLiteralExpression(expression)) { - var argument = arguments[i]; - var expression = syntaxFacts.GetExpressionOfArgument(argument); - if (syntaxFacts.IsStringLiteralExpression(expression)) + var remainingArgCount = arguments.Count - i - 1; + Debug.Assert(remainingArgCount > 0); + var stringLiteralText = expression.GetFirstToken().Text; + if (stringLiteralText.Contains('{') && stringLiteralText.Contains('}')) { - var remainingArgCount = arguments.Count - i - 1; - Debug.Assert(remainingArgCount > 0); - var stringLiteralText = expression.GetFirstToken().Text; - if (stringLiteralText.Contains('{') && stringLiteralText.Contains('}')) - { - if (IsValidPlaceholderArgument(stringLiteralText, remainingArgCount)) - return (TArgumentSyntax)argument; - } + if (IsValidPlaceholderArgument(stringLiteralText, remainingArgCount)) + return argument; } } } - - return null; } + return null; + bool IsValidPlaceholderArgument(string stringLiteralText, int remainingArgCount) { // See how many arguments follow the `"...{0}..."`. We have to have a {0}, {1}, ... {N} part in the // string for each of them. Note, those could be in any order. for (var i = 0; i < remainingArgCount; i++) { + cancellationToken.ThrowIfCancellationRequested(); + var indexString = i.ToString(CultureInfo.InvariantCulture); if (!ContainsIndex(stringLiteralText, indexString)) return false; @@ -219,23 +251,79 @@ bool ContainsIndex(string stringLiteralText, string indexString) } } - private static async Task CreateInterpolatedStringAsync( + protected override async Task FixAllAsync( Document document, - TInvocationExpressionSyntax invocation, - TArgumentSyntax placeholderArgument, - IMethodSymbol invocationSymbol, - TInterpolatedStringExpressionSyntax interpolatedString, - bool shouldReplaceInvocation, + ImmutableArray fixAllSpans, + SyntaxEditor editor, + string? equivalenceKey, CancellationToken cancellationToken) { var syntaxFacts = document.GetRequiredLanguageService(); + + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + + var normalizedSpans = new NormalizedTextSpanCollection(fixAllSpans); + + using var _ = ArrayBuilder.GetInstance(out var stack); + stack.Push(root); + + while (stack.TryPop(out var node)) + { + if (node is TInvocationExpressionSyntax invocation) + { + var placeholderArgument = FindValidPlaceholderArgument(syntaxFacts, invocation, cancellationToken); + if (placeholderArgument is not null && + AnalyzeInvocation(document, semanticModel, invocation, placeholderArgument, cancellationToken) is { } invocationData) + { + ReplaceInvocation(editor, semanticModel, syntaxFacts, invocationData, cancellationToken); + continue; + } + } + + foreach (var child in node.ChildNodesAndTokens()) + { + if (child.IsNode) + { + var childNode = child.AsNode(); + if (normalizedSpans.IntersectsWith(childNode!.Span)) + stack.Push(childNode); + } + } + } + } + + private static async Task CreateInterpolatedStringAsync( + Document document, + InvocationData invocationData, + CancellationToken cancellationToken) + { + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var syntaxFacts = document.GetRequiredLanguageService(); + var syntaxGenerator = document.GetRequiredLanguageService(); + var editor = new SyntaxEditor(root, syntaxGenerator); + + ReplaceInvocation(editor, semanticModel, syntaxFacts, invocationData, cancellationToken); + + return document.WithSyntaxRoot(editor.GetChangedRoot()); + } + + private static void ReplaceInvocation( + SyntaxEditor editor, + SemanticModel semanticModel, + ISyntaxFacts syntaxFacts, + InvocationData invocationData, + CancellationToken cancellationToken) + { + var (invocation, placeholderArgument, invocationSymbol, interpolatedString, shouldReplaceInvocation) = invocationData; + var arguments = (SeparatedSyntaxList)syntaxFacts.GetArgumentsOfInvocationExpression(invocation); var literalExpression = (TLiteralExpressionSyntax?)syntaxFacts.GetExpressionOfArgument(placeholderArgument); Contract.ThrowIfNull(literalExpression); - var syntaxGenerator = document.GetRequiredLanguageService(); + var syntaxGenerator = editor.Generator; var newInterpolatedString = InsertArgumentsIntoInterpolatedString( @@ -248,9 +336,8 @@ private static async Task CreateInterpolatedStringAsync( syntaxFacts.GetExpressionOfInvocationExpression(invocation), newInterpolatedString); - var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var newRoot = root.ReplaceNode(invocation, replacementNode.WithTriviaFrom(invocation)); - return document.WithSyntaxRoot(newRoot); + editor.ReplaceNode(invocation, replacementNode.WithTriviaFrom(invocation)); + return; ImmutableArray GetReorderedArgumentsAfterPlaceholderArgument() { diff --git a/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs index 865ec14ec093d..2547e03fcc758 100644 --- a/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs @@ -11,7 +11,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; diff --git a/src/Features/Core/Portable/ConvertTupleToStruct/IConvertTupleToStructCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertTupleToStruct/IConvertTupleToStructCodeRefactoringProvider.cs index 1220eaed05d3d..2d8e2660d3c50 100644 --- a/src/Features/Core/Portable/ConvertTupleToStruct/IConvertTupleToStructCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertTupleToStruct/IConvertTupleToStructCodeRefactoringProvider.cs @@ -4,7 +4,6 @@ using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/Core/Portable/Copilot/ICopilotCodeAnalysisService.cs b/src/Features/Core/Portable/Copilot/ICopilotCodeAnalysisService.cs index a4ce548bcfa7c..c8e4a55485f86 100644 --- a/src/Features/Core/Portable/Copilot/ICopilotCodeAnalysisService.cs +++ b/src/Features/Core/Portable/Copilot/ICopilotCodeAnalysisService.cs @@ -2,11 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; +using System.Collections.Generic; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.DocumentationComments; +using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.QuickInfo; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Copilot; @@ -62,19 +65,40 @@ internal interface ICopilotCodeAnalysisService : ILanguageService Task StartRefinementSessionAsync(Document oldDocument, Document newDocument, Diagnostic? primaryDiagnostic, CancellationToken cancellationToken); /// - /// Method to fetch the on-the-fly documentation based on a a symbols - /// and the code for the symbols in . - /// - /// is a formatted string representation of an .
- /// is a list of a code definitions from an . - /// is the language of the originating . - ///
+ /// Retrieves the prompt ///
- Task<(string responseString, bool isQuotaExceeded)> GetOnTheFlyDocsAsync(string symbolSignature, ImmutableArray declarationCode, string language, CancellationToken cancellationToken); + /// Type containing code and other context about the symbol being examined. + /// + Task GetOnTheFlyDocsPromptAsync(OnTheFlyDocsInfo onTheFlyDocsInfo, CancellationToken cancellationToken); + + /// + /// Retrieves the response from Copilot summarizing what a symbol is being used for and whether or not the quota has exceeded. + /// + /// The input text used to generate the response. + Task<(string responseString, bool isQuotaExceeded)> GetOnTheFlyDocsResponseAsync(string prompt, CancellationToken cancellationToken); /// /// Determines if the given is excluded in the workspace. /// Task IsFileExcludedAsync(string filePath, CancellationToken cancellationToken); + /// + /// Method to retrieve the documentation comment for a given + /// + /// The documentation comment that has been broken down into its individual pieces. + Task<(Dictionary? responseDictionary, bool isQuotaExceeded)> GetDocumentationCommentAsync(DocumentationCommentProposal proposal, CancellationToken cancellationToken); + + /// + /// Checks if the feature for implementing is available. + /// + Task IsImplementNotImplementedExceptionsAvailableAsync(CancellationToken cancellationToken); + + /// + /// Implements methods or properties containing throws in the given . + /// + /// A dictionary mapping the original syntax nodes to their implementation details. + Task> ImplementNotImplementedExceptionsAsync( + Document document, + ImmutableDictionary> methodOrProperties, + CancellationToken cancellationToken); } diff --git a/src/Features/Core/Portable/Copilot/ICopilotOptionsService.cs b/src/Features/Core/Portable/Copilot/ICopilotOptionsService.cs index 234c3ccbc748c..fce617f51ef5b 100644 --- a/src/Features/Core/Portable/Copilot/ICopilotOptionsService.cs +++ b/src/Features/Core/Portable/Copilot/ICopilotOptionsService.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.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; @@ -28,4 +29,14 @@ internal interface ICopilotOptionsService : ILanguageService /// Returns true if Copilot on-the-fly docs feature is enabled. ///
Task IsOnTheFlyDocsOptionEnabledAsync(); + + /// + /// Returns true if Copilot generate documentation comment feature is enabled. + /// + Task IsGenerateDocumentationCommentOptionEnabledAsync(); + + /// + /// Returns true if Copilot generate method implementation feature is enabled. + /// + Task IsImplementNotImplementedExceptionEnabledAsync(); } diff --git a/src/Features/Core/Portable/Copilot/ImplementationDetails.cs b/src/Features/Core/Portable/Copilot/ImplementationDetails.cs new file mode 100644 index 0000000000000..3d001e1e8cc71 --- /dev/null +++ b/src/Features/Core/Portable/Copilot/ImplementationDetails.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 Microsoft.CodeAnalysis.Copilot; + +/// +/// Holds details about a replacement node, providing either a message explaining the absence of a replacement or the +/// replacement syntax node itself. One of or must always be set. +/// +internal sealed class ImplementationDetails +{ + /// + /// Gets the message explaining why a replacement node is not provided. Either this property or must be set. + /// + public string? Message { get; init; } + + /// + /// Gets the replacement syntax node. Either this property or must be set. + /// + public SyntaxNode? ReplacementNode { get; init; } +} diff --git a/src/Features/Core/Portable/Debugging/AbstractBreakpointResolver.NameAndArity.cs b/src/Features/Core/Portable/Debugging/AbstractBreakpointResolver.NameAndArity.cs index c893ef0494379..42647c95058c8 100644 --- a/src/Features/Core/Portable/Debugging/AbstractBreakpointResolver.NameAndArity.cs +++ b/src/Features/Core/Portable/Debugging/AbstractBreakpointResolver.NameAndArity.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.Debugging; internal abstract partial class AbstractBreakpointResolver diff --git a/src/Features/Core/Portable/Debugging/AbstractBreakpointResolver.cs b/src/Features/Core/Portable/Debugging/AbstractBreakpointResolver.cs index 75229c8f43e08..e6d9ecaa380d9 100644 --- a/src/Features/Core/Portable/Debugging/AbstractBreakpointResolver.cs +++ b/src/Features/Core/Portable/Debugging/AbstractBreakpointResolver.cs @@ -231,6 +231,7 @@ private async Task> GetAllTypesAsync(CancellationT { SymbolKind.Method => ((IMethodSymbol)symbol).PartialImplementationPart, SymbolKind.Property => ((IPropertySymbol)symbol).PartialImplementationPart, + SymbolKind.Event => ((IEventSymbol)symbol).PartialImplementationPart, _ => null }; diff --git a/src/Features/Core/Portable/Debugging/IProximityExpressionsService.cs b/src/Features/Core/Portable/Debugging/IProximityExpressionsService.cs index a578e78e14098..b34a832e695bd 100644 --- a/src/Features/Core/Portable/Debugging/IProximityExpressionsService.cs +++ b/src/Features/Core/Portable/Debugging/IProximityExpressionsService.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.Threading; using System.Threading.Tasks; diff --git a/src/Features/Core/Portable/Diagnostics/Analyzers/DocumentDiagnosticAnalyzer.cs b/src/Features/Core/Portable/Diagnostics/Analyzers/DocumentDiagnosticAnalyzer.cs index 5c1544cdb470b..abcc5ba0a84dc 100644 --- a/src/Features/Core/Portable/Diagnostics/Analyzers/DocumentDiagnosticAnalyzer.cs +++ b/src/Features/Core/Portable/Diagnostics/Analyzers/DocumentDiagnosticAnalyzer.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.Runtime.CompilerServices; using Microsoft.CodeAnalysis.Diagnostics; diff --git a/src/Features/Core/Portable/Diagnostics/Analyzers/UnboundIdentifiersDiagnosticAnalyzerBase.cs b/src/Features/Core/Portable/Diagnostics/Analyzers/UnboundIdentifiersDiagnosticAnalyzerBase.cs index de3204768c301..7cae891a5897b 100644 --- a/src/Features/Core/Portable/Diagnostics/Analyzers/UnboundIdentifiersDiagnosticAnalyzerBase.cs +++ b/src/Features/Core/Portable/Diagnostics/Analyzers/UnboundIdentifiersDiagnosticAnalyzerBase.cs @@ -4,7 +4,6 @@ using System.Collections.Immutable; using System.Linq; -using Microsoft.CodeAnalysis.Simplification; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Diagnostics.AddImport; diff --git a/src/Features/Core/Portable/Diagnostics/CodeAnalysisDiagnosticAnalyzerService.cs b/src/Features/Core/Portable/Diagnostics/CodeAnalysisDiagnosticAnalyzerService.cs index cc52cd179ee96..6776c555c1283 100644 --- a/src/Features/Core/Portable/Diagnostics/CodeAnalysisDiagnosticAnalyzerService.cs +++ b/src/Features/Core/Portable/Diagnostics/CodeAnalysisDiagnosticAnalyzerService.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Concurrent; using System.Collections.Immutable; using System.Composition; using System.Linq; @@ -23,39 +24,35 @@ internal sealed class CodeAnalysisDiagnosticAnalyzerServiceFactory() : IWorkspac public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) { var diagnosticAnalyzerService = workspaceServices.SolutionServices.ExportProvider.GetExports().Single().Value; - var diagnosticsRefresher = workspaceServices.SolutionServices.ExportProvider.GetExports().Single().Value; - return new CodeAnalysisDiagnosticAnalyzerService(diagnosticAnalyzerService, diagnosticsRefresher, workspaceServices.Workspace); + return new CodeAnalysisDiagnosticAnalyzerService(diagnosticAnalyzerService, workspaceServices.Workspace); } private sealed class CodeAnalysisDiagnosticAnalyzerService : ICodeAnalysisDiagnosticAnalyzerService { private readonly IDiagnosticAnalyzerService _diagnosticAnalyzerService; - private readonly IDiagnosticsRefresher _diagnosticsRefresher; private readonly Workspace _workspace; /// - /// List of projects that we've finished running "run code analysis" on. Cached results can now be returned for - /// these through and . + /// Mapping of projects to the diagnostics for the projects that we've finished running "run code analysis" on. + /// Cached results can now be returned for these through + /// and . /// - private readonly ConcurrentSet _analyzedProjectIds = []; + private readonly ConcurrentDictionary> _analyzedProjectToDiagnostics = []; /// /// Previously analyzed projects that we no longer want to report results for. This happens when an explicit /// build is kicked off. At that point, we want the build results to win out for a particular project. We mark - /// this project (as opposed to removing from ) as we want our LSP handler to - /// still think it should process it, as that will the cause the diagnostics to be removed when they now - /// transition to an empty list returned from this type. + /// this project (as opposed to removing from ) as we want our LSP + /// handler to still think it should process it, as that will the cause the diagnostics to be removed when they + /// now transition to an empty list returned from this type. /// private readonly ConcurrentSet _clearedProjectIds = []; public CodeAnalysisDiagnosticAnalyzerService( IDiagnosticAnalyzerService diagnosticAnalyzerService, - IDiagnosticsRefresher diagnosticsRefresher, Workspace workspace) { _diagnosticAnalyzerService = diagnosticAnalyzerService; - _diagnosticsRefresher = diagnosticsRefresher; _workspace = workspace; _workspace.WorkspaceChanged += OnWorkspaceChanged; @@ -70,11 +67,11 @@ private void OnWorkspaceChanged(object? sender, WorkspaceChangeEventArgs e) case WorkspaceChangeKind.SolutionReloaded: case WorkspaceChangeKind.SolutionRemoved: - _analyzedProjectIds.Clear(); + _analyzedProjectToDiagnostics.Clear(); _clearedProjectIds.Clear(); // Let LSP know so that it requests up to date info, and will see our cached info disappear. - _diagnosticsRefresher.RequestWorkspaceRefresh(); + _diagnosticAnalyzerService.RequestDiagnosticRefresh(); break; } } @@ -82,13 +79,14 @@ private void OnWorkspaceChanged(object? sender, WorkspaceChangeEventArgs e) public void Clear() { // Clear the list of analyzed projects. - _clearedProjectIds.AddRange(_analyzedProjectIds); + _clearedProjectIds.AddRange(_analyzedProjectToDiagnostics.Keys); // Let LSP know so that it requests up to date info, and will see our cached info disappear. - _diagnosticsRefresher.RequestWorkspaceRefresh(); + _diagnosticAnalyzerService.RequestDiagnosticRefresh(); } - public bool HasProjectBeenAnalyzed(ProjectId projectId) => _analyzedProjectIds.Contains(projectId); + public bool HasProjectBeenAnalyzed(ProjectId projectId) + => _analyzedProjectToDiagnostics.ContainsKey(projectId); public async Task RunAnalysisAsync(Solution solution, ProjectId? projectId, Action onAfterProjectAnalyzed, CancellationToken cancellationToken) { @@ -115,11 +113,11 @@ await RoslynParallel.ForEachAsync( private async ValueTask AnalyzeProjectCoreAsync(Project project, Action onAfterProjectAnalyzed, CancellationToken cancellationToken) { // Execute force analysis for the project. - await _diagnosticAnalyzerService.ForceAnalyzeProjectAsync(project, cancellationToken).ConfigureAwait(false); + var diagnostics = await _diagnosticAnalyzerService.ForceAnalyzeProjectAsync(project, cancellationToken).ConfigureAwait(false); // Add the given project to the analyzed projects list **after** analysis has completed. // We need this ordering to ensure that 'HasProjectBeenAnalyzed' call above functions correctly. - _analyzedProjectIds.Add(project.Id); + _analyzedProjectToDiagnostics[project.Id] = diagnostics; // Remove from the cleared list now that we've run a more recent "run code analysis" on this project. _clearedProjectIds.Remove(project.Id); @@ -128,47 +126,50 @@ private async ValueTask AnalyzeProjectCoreAsync(Project project, Action onAfterProjectAnalyzed(project); // Finally, invoke a workspace refresh request for LSP client to pull onto these diagnostics. - // TODO: Below call will eventually be replaced with a special workspace refresh request that skips - // pulling document diagnostics and also does not add any delay for pulling workspace diagnostics. - _diagnosticsRefresher.RequestWorkspaceRefresh(); + // + // TODO: Below call will eventually be replaced with a special workspace refresh request that skips pulling + // document diagnostics and also does not add any delay for pulling workspace diagnostics. + _diagnosticAnalyzerService.RequestDiagnosticRefresh(); } /// - /// Running code analysis on the project force computes and caches the diagnostics on the - /// DiagnosticAnalyzerService. We return these cached document diagnostics here, including both local and - /// non-local document diagnostics. + /// Running code analysis on the project force computes and caches the diagnostics in . We return these cached document diagnostics here, including both + /// local and non-local document diagnostics. /// /// /// Only returns non-suppressed diagnostics. /// - public async Task> GetLastComputedDocumentDiagnosticsAsync(DocumentId documentId, CancellationToken cancellationToken) + public ImmutableArray GetLastComputedDocumentDiagnostics(DocumentId documentId) { if (_clearedProjectIds.Contains(documentId.ProjectId)) return []; - var diagnostics = await _diagnosticAnalyzerService.GetCachedDiagnosticsAsync( - _workspace, documentId.ProjectId, documentId, includeLocalDocumentDiagnostics: true, - includeNonLocalDocumentDiagnostics: true, cancellationToken).ConfigureAwait(false); - return diagnostics.WhereAsArray(d => !d.IsSuppressed); + if (!_analyzedProjectToDiagnostics.TryGetValue(documentId.ProjectId, out var diagnostics)) + return []; + + return diagnostics.WhereAsArray(static (d, documentId) => + !d.IsSuppressed && d.DataLocation.DocumentId == documentId, documentId); } /// - /// Running code analysis on the project force computes and caches the diagnostics on the - /// DiagnosticAnalyzerService. We return these cached project diagnostics here, i.e. diagnostics with no - /// location, by excluding all local and non-local document diagnostics. + /// Running code analysis on the project force computes and caches the diagnostics in . We return these cached project diagnostics here, i.e. diagnostics + /// with no location, by excluding all local and non-local document diagnostics. /// /// /// Only returns non-suppressed diagnostics. /// - public async Task> GetLastComputedProjectDiagnosticsAsync(ProjectId projectId, CancellationToken cancellationToken) + public ImmutableArray GetLastComputedProjectDiagnostics(ProjectId projectId) { if (_clearedProjectIds.Contains(projectId)) return []; - var diagnostics = await _diagnosticAnalyzerService.GetCachedDiagnosticsAsync( - _workspace, projectId, documentId: null, includeLocalDocumentDiagnostics: false, - includeNonLocalDocumentDiagnostics: false, cancellationToken).ConfigureAwait(false); - return diagnostics.WhereAsArray(d => !d.IsSuppressed); + if (!_analyzedProjectToDiagnostics.TryGetValue(projectId, out var diagnostics)) + return []; + + return diagnostics.WhereAsArray(static (d, projectId) => + !d.IsSuppressed && d.ProjectId == projectId && d.DataLocation.DocumentId == null, projectId); } } } diff --git a/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerExtensions.cs b/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerExtensions.cs index e1d85cc8844a9..6855cedf92a45 100644 --- a/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerExtensions.cs +++ b/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerExtensions.cs @@ -8,8 +8,6 @@ using System.Linq; using System.Reflection; using Microsoft.CodeAnalysis.Diagnostics.Telemetry; -using Microsoft.CodeAnalysis.Simplification; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Diagnostics; diff --git a/src/Features/Core/Portable/Diagnostics/IAnalyzerDriverService.cs b/src/Features/Core/Portable/Diagnostics/IAnalyzerDriverService.cs index c8b3bb1119f07..77526616e7c6e 100644 --- a/src/Features/Core/Portable/Diagnostics/IAnalyzerDriverService.cs +++ b/src/Features/Core/Portable/Diagnostics/IAnalyzerDriverService.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 Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.PooledObjects; diff --git a/src/Features/Core/Portable/Diagnostics/ICodeAnalysisDiagnosticAnalyzerService.cs b/src/Features/Core/Portable/Diagnostics/ICodeAnalysisDiagnosticAnalyzerService.cs index ec4a395e3e964..5b80a8e4b01bd 100644 --- a/src/Features/Core/Portable/Diagnostics/ICodeAnalysisDiagnosticAnalyzerService.cs +++ b/src/Features/Core/Portable/Diagnostics/ICodeAnalysisDiagnosticAnalyzerService.cs @@ -18,36 +18,39 @@ internal interface ICodeAnalysisDiagnosticAnalyzerService : IWorkspaceService void Clear(); /// - /// Runs all the applicable analyzers on the given project or entire solution if is null. + /// Runs all the applicable analyzers on the given project or entire solution if is + /// null. /// Task RunAnalysisAsync(Solution solution, ProjectId? projectId, Action onAfterProjectAnalyzed, CancellationToken cancellationToken); /// - /// Returns true if was invoked - /// on either the current or a prior snapshot of the project or containing solution for the given . - /// This method will keep returning true for a given project ID once any given snapshot of the project has been analyzed. - /// This changes once the solution is closed/reloaded, at which point all the projects are returned back to not analyzed state - /// and this method will return false. + /// Returns true if was + /// invoked on either the current or a prior snapshot of the project or containing solution for the given . This method will keep returning true for a given project ID once any given snapshot of the + /// project has been analyzed. This changes once the solution is closed/reloaded, at which point all the projects + /// are returned back to not analyzed state and this method will return false. /// bool HasProjectBeenAnalyzed(ProjectId projectId); /// - /// Returns analyzer diagnostics reported on the given > from the last - /// invocation on the containing project or solution. - /// The caller is expected to check prior to calling this method. + /// Returns analyzer diagnostics reported on the given > from the last invocation on the containing + /// project or solution. The caller is expected to check prior to + /// calling this method. /// /// /// Note that the returned diagnostics may not be from the latest document snapshot. /// - Task> GetLastComputedDocumentDiagnosticsAsync(DocumentId documentId, CancellationToken cancellationToken); + ImmutableArray GetLastComputedDocumentDiagnostics(DocumentId documentId); /// - /// Returns analyzer diagnostics without any document location reported on the given > from the last - /// invocation on the given project or solution. - /// The caller is expected to check prior to calling this method. + /// Returns analyzer diagnostics without any document location reported on the given > + /// from the last + /// invocation on the given project or solution. The caller is expected to check prior to calling this method. /// /// /// Note that the returned diagnostics may not be from the latest project snapshot. /// - Task> GetLastComputedProjectDiagnosticsAsync(ProjectId projectId, CancellationToken cancellationToken); + ImmutableArray GetLastComputedProjectDiagnostics(ProjectId projectId); } diff --git a/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs b/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs index 406c168c5324e..3ce287befb209 100644 --- a/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs +++ b/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs @@ -3,20 +3,16 @@ // 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.CodeActions; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Diagnostics; internal interface IDiagnosticAnalyzerService { - public IGlobalOptionService GlobalOptions { get; } - /// /// Provides and caches analyzer information. /// @@ -28,39 +24,17 @@ internal interface IDiagnosticAnalyzerService void RequestDiagnosticRefresh(); /// - /// Get diagnostics currently stored in the source. returned diagnostic might be out-of-date if solution has changed but analyzer hasn't run for the new solution. + /// Force analyzes the given project by running all applicable analyzers on the project. /// - /// Workspace for the document/project/solution to compute diagnostics for. - /// Optional project to scope the returned diagnostics. - /// Optional document to scope the returned diagnostics. - /// - /// Indicates if local document diagnostics must be returned. - /// Local diagnostics are the ones that are reported by analyzers on the same file for which the callback was received - /// and hence can be computed by analyzing a single file in isolation. - /// - /// - /// Indicates if non-local document diagnostics must be returned. - /// Non-local diagnostics are the ones reported by analyzers either at compilation end callback OR - /// in a different file from which the callback was made. Entire project must be analyzed to get the - /// complete set of non-local document diagnostics. - /// - /// Cancellation token. - Task> GetCachedDiagnosticsAsync(Workspace workspace, ProjectId? projectId, DocumentId? documentId, bool includeLocalDocumentDiagnostics, bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken); - - /// - /// Force analyzes the given project by running all applicable analyzers on the project and caching the reported analyzer diagnostics. - /// - Task ForceAnalyzeProjectAsync(Project project, CancellationToken cancellationToken); + Task> ForceAnalyzeProjectAsync(Project project, CancellationToken cancellationToken); /// /// Get diagnostics of the given diagnostic ids and/or analyzers from the given solution. all diagnostics returned /// should be up-to-date with respect to the given solution. Note that for project case, this method returns - /// diagnostics from all project documents as well. Use if you want + /// diagnostics from all project documents as well. Use if you want /// to fetch only project diagnostics without source locations. /// - /// Solution to fetch the diagnostics for. - /// Optional project to scope the returned diagnostics. + /// Project to fetch the diagnostics for. /// Optional document to scope the returned diagnostics. /// Optional set of diagnostic IDs to scope the returned diagnostics. /// Option callback to filter out analyzers to execute for computing diagnostics. @@ -75,7 +49,7 @@ internal interface IDiagnosticAnalyzerService /// project must be analyzed to get the complete set of non-local document diagnostics. /// /// Cancellation token. - Task> GetDiagnosticsForIdsAsync(Solution solution, ProjectId? projectId, DocumentId? documentId, ImmutableHashSet? diagnosticIds, Func? shouldIncludeAnalyzer, Func>? getDocumentIds, bool includeLocalDocumentDiagnostics, bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken); + Task> GetDiagnosticsForIdsAsync(Project project, DocumentId? documentId, ImmutableHashSet? diagnosticIds, Func? shouldIncludeAnalyzer, bool includeLocalDocumentDiagnostics, bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken); /// /// Get project diagnostics (diagnostics with no source location) of the given diagnostic ids and/or analyzers from @@ -83,8 +57,7 @@ internal interface IDiagnosticAnalyzerService /// this method doesn't return any document diagnostics. Use to also fetch /// those. /// - /// Solution to fetch the diagnostics for. - /// Optional project to scope the returned diagnostics. + /// Project to fetch the diagnostics for. /// Optional set of diagnostic IDs to scope the returned diagnostics. /// Option callback to filter out analyzers to execute for computing diagnostics. /// @@ -93,7 +66,7 @@ internal interface IDiagnosticAnalyzerService /// Entire project must be analyzed to get the complete set of non-local diagnostics. /// /// Cancellation token. - Task> GetProjectDiagnosticsForIdsAsync(Solution solution, ProjectId? projectId, ImmutableHashSet? diagnosticIds, Func? shouldIncludeAnalyzer, bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken); + Task> GetProjectDiagnosticsForIdsAsync(Project project, ImmutableHashSet? diagnosticIds, Func? shouldIncludeAnalyzer, bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken); /// /// Return up to date diagnostics for the given span for the document @@ -105,7 +78,6 @@ internal interface IDiagnosticAnalyzerService /// Task> GetDiagnosticsForSpanAsync( TextDocument document, TextSpan? range, Func? shouldIncludeDiagnostic, - bool includeCompilerDiagnostics, ICodeActionRequestPriorityProvider priorityProvider, DiagnosticKind diagnosticKind, bool isExplicit, @@ -146,15 +118,6 @@ public static Task> GetDiagnosticsForSpanAsync(th { Func? shouldIncludeDiagnostic = diagnosticId != null ? id => id == diagnosticId : null; return service.GetDiagnosticsForSpanAsync(document, range, shouldIncludeDiagnostic, - includeCompilerDiagnostics: true, priorityProvider, - diagnosticKind, isExplicit, cancellationToken); - } - - public static Task> GetDiagnosticsForIdsAsync( - this IDiagnosticAnalyzerService service, Solution solution, ProjectId? projectId, DocumentId? documentId, ImmutableHashSet? diagnosticIds, Func? shouldIncludeAnalyzer, bool includeLocalDocumentDiagnostics, bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken) - { - return service.GetDiagnosticsForIdsAsync( - solution, projectId, documentId, diagnosticIds, shouldIncludeAnalyzer, getDocumentIds: null, - includeLocalDocumentDiagnostics, includeNonLocalDocumentDiagnostics, cancellationToken); + priorityProvider, diagnosticKind, isExplicit, cancellationToken); } } diff --git a/src/Features/Core/Portable/Diagnostics/IDiagnosticsRefresher.cs b/src/Features/Core/Portable/Diagnostics/IDiagnosticsRefresher.cs index bd1b413174aa7..e185068a39c34 100644 --- a/src/Features/Core/Portable/Diagnostics/IDiagnosticsRefresher.cs +++ b/src/Features/Core/Portable/Diagnostics/IDiagnosticsRefresher.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; + namespace Microsoft.CodeAnalysis.Diagnostics; /// @@ -9,6 +11,8 @@ namespace Microsoft.CodeAnalysis.Diagnostics; /// internal interface IDiagnosticsRefresher { + event Action? WorkspaceRefreshRequested; + /// /// Requests workspace diagnostics refresh. /// Any component that maintains state whose change may affect reported diagnostics should call whenever that state changes. diff --git a/src/Features/Core/Portable/Diagnostics/IRemoteDiagnosticAnalyzerService.cs b/src/Features/Core/Portable/Diagnostics/IRemoteDiagnosticAnalyzerService.cs index 3d1f95c1a8c1e..d212ebc32a8a1 100644 --- a/src/Features/Core/Portable/Diagnostics/IRemoteDiagnosticAnalyzerService.cs +++ b/src/Features/Core/Portable/Diagnostics/IRemoteDiagnosticAnalyzerService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Immutable; using System.Runtime.Serialization; diff --git a/src/Features/Core/Portable/Diagnostics/Log/DiagnosticLogger.cs b/src/Features/Core/Portable/Diagnostics/Log/DiagnosticLogger.cs index 31e0854b54f5e..fc9e912614162 100644 --- a/src/Features/Core/Portable/Diagnostics/Log/DiagnosticLogger.cs +++ b/src/Features/Core/Portable/Diagnostics/Log/DiagnosticLogger.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Internal.Log; namespace Microsoft.CodeAnalysis.Diagnostics.Log; diff --git a/src/Features/Core/Portable/DocumentationComments/AbstractDocumentationCommentSnippetService.cs b/src/Features/Core/Portable/DocumentationComments/AbstractDocumentationCommentSnippetService.cs index 94819510eb903..923f4cf08b690 100644 --- a/src/Features/Core/Portable/DocumentationComments/AbstractDocumentationCommentSnippetService.cs +++ b/src/Features/Core/Portable/DocumentationComments/AbstractDocumentationCommentSnippetService.cs @@ -87,8 +87,8 @@ private bool IsAtEndOfDocCommentTriviaOnBlankLine(SourceText text, int endPositi return null; var lines = addIndentation - ? GetDocumentationCommentLines(token, text, options, out _, out var caretOffset, out var spanToReplaceLength) - : GetDocumentationCommentLinesNoIndentation(token, text, options, out caretOffset, out spanToReplaceLength); + ? GetDocumentationCommentLines(token, text, options, out var indentText, out var caretOffset, out var spanToReplaceLength) + : GetDocumentationCommentLinesNoIndentation(token, text, options, out caretOffset, out spanToReplaceLength, out indentText); if (lines == null) return null; @@ -102,7 +102,9 @@ private bool IsAtEndOfDocCommentTriviaOnBlankLine(SourceText text, int endPositi var replaceSpan = new TextSpan(token.Span.Start, spanToReplaceLength); - return new DocumentationCommentSnippet(replaceSpan, comments, caretOffset); + var memberNode = GetContainingMember(syntaxTree, position, cancellationToken); + + return new DocumentationCommentSnippet(replaceSpan, comments, caretOffset, position, memberNode, indentText); } private List? GetDocumentationCommentLines(SyntaxToken token, SourceText text, in DocumentationCommentOptions options, out string? indentText, out int caretOffset, out int spanToReplaceLength) @@ -136,8 +138,9 @@ private bool IsAtEndOfDocCommentTriviaOnBlankLine(SourceText text, int endPositi return lines; } - private List? GetDocumentationCommentLinesNoIndentation(SyntaxToken token, SourceText text, in DocumentationCommentOptions options, out int caretOffset, out int spanToReplaceLength) + private List? GetDocumentationCommentLinesNoIndentation(SyntaxToken token, SourceText text, in DocumentationCommentOptions options, out int caretOffset, out int spanToReplaceLength, out string? indentText) { + indentText = null; var lines = GetDocumentationStubLines(token, text, options, out caretOffset, out spanToReplaceLength, out var existingCommentText); if (lines is null) { @@ -319,7 +322,7 @@ private static void IndentLines(List lines, string? indentText) replaceSpan = new TextSpan(start, currentLinePosition.Value - start); } - return new DocumentationCommentSnippet(replaceSpan, newText, offset); + return new DocumentationCommentSnippet(replaceSpan, newText, offset, position: null, memberNode: null, indentText: null); } public DocumentationCommentSnippet? GetDocumentationCommentSnippetOnCommandInvoke(ParsedDocument document, int position, in DocumentationCommentOptions options, CancellationToken cancellationToken) @@ -358,7 +361,7 @@ private static void IndentLines(List lines, string? indentText) // For a command we don't replace a token, but insert before it var replaceSpan = new TextSpan(token.Span.Start, 0); - return new DocumentationCommentSnippet(replaceSpan, comments, offset); + return new DocumentationCommentSnippet(replaceSpan, comments, offset, position: null, memberNode: null, indentText: null); } private DocumentationCommentSnippet? GenerateExteriorTriviaAfterEnter(ParsedDocument document, int position, in DocumentationCommentOptions options, CancellationToken cancellationToken) @@ -434,7 +437,7 @@ public DocumentationCommentSnippet GetDocumentationCommentSnippetFromPreviousLin ? TextSpan.FromBounds(currentLine.Start, currentLine.Start + firstNonWhitespaceOffset.Value) : currentLine.Span; - return new DocumentationCommentSnippet(replaceSpan, insertionText, insertionText.Length); + return new DocumentationCommentSnippet(replaceSpan, insertionText, insertionText.Length, position: null, memberNode: null, indentText: null); } private string CreateInsertionTextFromPreviousLine(TextLine previousLine, in DocumentationCommentOptions options) diff --git a/src/Features/Core/Portable/DocumentationComments/DocumentationCommentProposal.cs b/src/Features/Core/Portable/DocumentationComments/DocumentationCommentProposal.cs new file mode 100644 index 0000000000000..f4392262d16d8 --- /dev/null +++ b/src/Features/Core/Portable/DocumentationComments/DocumentationCommentProposal.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.Collections.Immutable; + +namespace Microsoft.CodeAnalysis.DocumentationComments; + +/// +/// Represents the set of all edits that will be needed to fill in the documentation comment for a symbol. +/// +internal sealed record DocumentationCommentProposal +{ + public string SymbolToAnalyze { get; } + + public ImmutableArray ProposedEdits { get; } + + public DocumentationCommentProposal(string symbolToAnalyze, ImmutableArray proposedEdits) + { + SymbolToAnalyze = symbolToAnalyze; + ProposedEdits = proposedEdits; + } +} diff --git a/src/Features/Core/Portable/DocumentationComments/DocumentationCommentProposedEdit.cs b/src/Features/Core/Portable/DocumentationComments/DocumentationCommentProposedEdit.cs new file mode 100644 index 0000000000000..8ec2489563732 --- /dev/null +++ b/src/Features/Core/Portable/DocumentationComments/DocumentationCommentProposedEdit.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 Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.DocumentationComments; + +/// +/// The individual piece of each documentation comment that will eventually be proposed as an edit. +/// E.g. the summary tag, the param tag, etc. +/// +internal sealed record DocumentationCommentProposedEdit +{ + public TextSpan SpanToReplace { get; } + + // May be null if the piece of the comment to document does not have an + // associated name. + public string? SymbolName { get; } + + public DocumentationCommentTagType TagType { get; } + + public DocumentationCommentProposedEdit(TextSpan spanToReplace, string? symbolName, DocumentationCommentTagType tagType) + { + SpanToReplace = spanToReplace; + SymbolName = symbolName; + TagType = tagType; + } +} diff --git a/src/Features/Core/Portable/DocumentationComments/DocumentationCommentSnippet.cs b/src/Features/Core/Portable/DocumentationComments/DocumentationCommentSnippet.cs index 89e88c6c201c1..6daa1f9e2069e 100644 --- a/src/Features/Core/Portable/DocumentationComments/DocumentationCommentSnippet.cs +++ b/src/Features/Core/Portable/DocumentationComments/DocumentationCommentSnippet.cs @@ -23,10 +23,29 @@ internal sealed class DocumentationCommentSnippet /// public int CaretOffset { get; } - internal DocumentationCommentSnippet(TextSpan spanToReplace, string snippetText, int caretOffset) + /// + /// The original position of the caret in the original text. + /// + public int? Position { get; } + + /// + /// The node that is being documented. + /// + public SyntaxNode? MemberNode { get; } + + /// + /// The text to use for indentation. This is specifically used for the generate documentation with + /// Copilot case to ensure the wrapped comments are indented correctly. + /// + public string? IndentText { get; } + + internal DocumentationCommentSnippet(TextSpan spanToReplace, string snippetText, int caretOffset, int? position, SyntaxNode? memberNode, string? indentText) { SpanToReplace = spanToReplace; SnippetText = snippetText; CaretOffset = caretOffset; + Position = position; + MemberNode = memberNode; + IndentText = indentText; } } diff --git a/src/Features/Core/Portable/DocumentationComments/DocumentationCommentTagType.cs b/src/Features/Core/Portable/DocumentationComments/DocumentationCommentTagType.cs new file mode 100644 index 0000000000000..69a4f3d651a36 --- /dev/null +++ b/src/Features/Core/Portable/DocumentationComments/DocumentationCommentTagType.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 Microsoft.CodeAnalysis.DocumentationComments +{ + internal enum DocumentationCommentTagType + { + Summary, + Remarks, + TypeParam, + Param, + Returns, + Value, + Exception, + } +} diff --git a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs index 0eb3caab26dfd..f4871492616c1 100644 --- a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs +++ b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs @@ -2721,8 +2721,8 @@ newSymbol is IPropertySymbol newProperty && } // 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?.IsPartialDefinition() == true) + // so must be the implementation (if it exists). An edit will be issued for the implementation change. + if (oldSymbol.IsPartialDefinition()) { continue; } diff --git a/src/Features/Core/Portable/EditAndContinue/ActiveStatementExceptionRegions.cs b/src/Features/Core/Portable/EditAndContinue/ActiveStatementExceptionRegions.cs index 1e81372175f8b..50ed55948041b 100644 --- a/src/Features/Core/Portable/EditAndContinue/ActiveStatementExceptionRegions.cs +++ b/src/Features/Core/Portable/EditAndContinue/ActiveStatementExceptionRegions.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.EditAndContinue; diff --git a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs index b14c697b558bc..d03722a3b56b6 100644 --- a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs @@ -511,13 +511,27 @@ public async ValueTask EmitSolutionUpdateAsync( solutionUpdate.Log(SessionLog, updateId); _lastModuleUpdatesLog = solutionUpdate.ModuleUpdates.Updates; - if (solutionUpdate.ModuleUpdates.Status == ModuleUpdateStatus.Ready) + switch (solutionUpdate.ModuleUpdates.Status) { - StorePendingUpdate(new PendingSolutionUpdate( - solution, - solutionUpdate.ProjectBaselines, - solutionUpdate.ModuleUpdates.Updates, - solutionUpdate.NonRemappableRegions)); + case ModuleUpdateStatus.Ready: + // We have updates to be applied. The debugger will call Commit/Discard on the solution + // based on whether the updates will be applied successfully or not. + StorePendingUpdate(new PendingSolutionUpdate( + solution, + solutionUpdate.ProjectBaselines, + solutionUpdate.ModuleUpdates.Updates, + solutionUpdate.NonRemappableRegions)); + + break; + + case ModuleUpdateStatus.None: + Contract.ThrowIfFalse(solutionUpdate.ModuleUpdates.Updates.IsEmpty); + Contract.ThrowIfFalse(solutionUpdate.NonRemappableRegions.IsEmpty); + + // No significant changes have been made. + // Commit the solution to apply any changes in comments that do not generate updates. + LastCommittedSolution.CommitSolution(solution); + break; } using var _ = ArrayBuilder.GetInstance(out var rudeEditDiagnostics); diff --git a/src/Features/Core/Portable/EditAndContinue/DocumentActiveStatementChanges.cs b/src/Features/Core/Portable/EditAndContinue/DocumentActiveStatementChanges.cs index 3d77a22e13c1d..cb0b443d7d41b 100644 --- a/src/Features/Core/Portable/EditAndContinue/DocumentActiveStatementChanges.cs +++ b/src/Features/Core/Portable/EditAndContinue/DocumentActiveStatementChanges.cs @@ -4,7 +4,6 @@ using System.Collections.Immutable; using System.Diagnostics; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.EditAndContinue; diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs index 0ce5dcb32db29..d4b48c9582807 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs @@ -166,8 +166,8 @@ void AddGeneralDiagnostic(EditAndContinueErrorCode code, string resourceName, Di AddGeneralDiagnostic(EditAndContinueErrorCode.ErrorReadingFile, nameof(FeaturesResources.ErrorReadingFile)); AddGeneralDiagnostic(EditAndContinueErrorCode.CannotApplyChangesUnexpectedError, nameof(FeaturesResources.CannotApplyChangesUnexpectedError)); AddGeneralDiagnostic(EditAndContinueErrorCode.ChangesDisallowedWhileStoppedAtException, nameof(FeaturesResources.ChangesDisallowedWhileStoppedAtException)); - AddGeneralDiagnostic(EditAndContinueErrorCode.DocumentIsOutOfSyncWithDebuggee, nameof(FeaturesResources.DocumentIsOutOfSyncWithDebuggee), DiagnosticSeverity.Warning); - AddGeneralDiagnostic(EditAndContinueErrorCode.UnableToReadSourceFileOrPdb, nameof(FeaturesResources.UnableToReadSourceFileOrPdb), DiagnosticSeverity.Warning); + AddGeneralDiagnostic(EditAndContinueErrorCode.DocumentIsOutOfSyncWithDebuggee, nameof(FeaturesResources.DocumentIsOutOfSyncWithDebuggee)); + AddGeneralDiagnostic(EditAndContinueErrorCode.UnableToReadSourceFileOrPdb, nameof(FeaturesResources.UnableToReadSourceFileOrPdb)); AddGeneralDiagnostic(EditAndContinueErrorCode.AddingTypeRuntimeCapabilityRequired, nameof(FeaturesResources.ChangesRequiredSynthesizedType)); s_descriptors = builder.ToImmutable(); diff --git a/src/Features/Core/Portable/EditAndContinue/EditSession.cs b/src/Features/Core/Portable/EditAndContinue/EditSession.cs index 4e9ea34a5b0a8..83e5711a2c544 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditSession.cs @@ -821,8 +821,9 @@ public async ValueTask EmitSolutionUpdateAsync(Solution solution var oldSolution = DebuggingSession.LastCommittedSolution; - var isBlocked = false; + var blockUpdates = false; var hasEmitErrors = false; + var hadDocumentReadError = false; foreach (var newProject in solution.Projects) { if (!newProject.SupportsEditAndContinue(Log)) @@ -866,7 +867,7 @@ public async ValueTask EmitSolutionUpdateAsync(Solution solution diagnostics.Add(new(newProject.Id, [mvidReadError])); Telemetry.LogProjectAnalysisSummary(ProjectAnalysisSummary.ValidChanges, newProject.State.ProjectInfo.Attributes.TelemetryId, ImmutableArray.Create(mvidReadError.Descriptor.Id)); - isBlocked = true; + blockUpdates = true; continue; } @@ -899,6 +900,11 @@ public async ValueTask EmitSolutionUpdateAsync(Solution solution // If in future the file is updated so that its content matches the PDB checksum, the document transitions to a matching state, // and we consider any further changes to it for application. diagnostics.Add(new(newProject.Id, documentDiagnostics)); + + if (documentDiagnostics.Any(d => d.Severity == DiagnosticSeverity.Error)) + { + blockUpdates = hadDocumentReadError = true; + } } foreach (var changedDocumentAnalysis in changedDocumentAnalyses) @@ -935,12 +941,12 @@ public async ValueTask EmitSolutionUpdateAsync(Solution solution if (isModuleEncBlocked) { diagnostics.Add(new(newProject.Id, moduleDiagnostics)); - isBlocked = true; + blockUpdates = true; } if (projectSummary is ProjectAnalysisSummary.SyntaxErrors or ProjectAnalysisSummary.RudeEdits) { - isBlocked = true; + blockUpdates = true; } // Report rude edit diagnostics - these can be blocking (errors) or non-blocking (warnings): @@ -972,7 +978,7 @@ public async ValueTask EmitSolutionUpdateAsync(Solution solution diagnostics.Add(new(newProject.Id, createBaselineErrors)); Telemetry.LogProjectAnalysisSummary(projectSummary, newProject.State.ProjectInfo.Attributes.TelemetryId, createBaselineErrors); - isBlocked = true; + blockUpdates = true; await LogDocumentChangesAsync(generation: null, cancellationToken).ConfigureAwait(false); continue; } @@ -1050,7 +1056,7 @@ public async ValueTask EmitSolutionUpdateAsync(Solution solution if (!emitResult.Success) { // error - isBlocked = hasEmitErrors = true; + blockUpdates = hasEmitErrors = true; emitDiagnostics = emitResult.Diagnostics; break; } @@ -1062,7 +1068,7 @@ public async ValueTask EmitSolutionUpdateAsync(Solution solution { emitDiagnostics = [unsupportedChangesDiagnostic]; diagnostics.Add(new(newProject.Id, emitDiagnostics)); - isBlocked = true; + blockUpdates = true; break; } @@ -1127,13 +1133,17 @@ async ValueTask LogDocumentChangesAsync(int? generation, CancellationToken cance } // log capabilities for edit sessions with changes or reported errors: - if (isBlocked || deltas.Count > 0) + if (blockUpdates || deltas.Count > 0) { Telemetry.LogRuntimeCapabilities(await Capabilities.GetValueAsync(cancellationToken).ConfigureAwait(false)); } - var update = isBlocked - ? SolutionUpdate.Blocked(diagnostics.ToImmutable(), documentsWithRudeEdits.ToImmutable(), syntaxError, hasEmitErrors) + var update = blockUpdates + ? SolutionUpdate.Empty( + diagnostics.ToImmutable(), + documentsWithRudeEdits.ToImmutable(), + syntaxError, + syntaxError != null || hasEmitErrors || hadDocumentReadError ? ModuleUpdateStatus.Blocked : ModuleUpdateStatus.RestartRequired) : new SolutionUpdate( new ModuleUpdates( (deltas.Count > 0) ? ModuleUpdateStatus.Ready : ModuleUpdateStatus.None, diff --git a/src/Features/Core/Portable/EditAndContinue/IEditAndContinueService.cs b/src/Features/Core/Portable/EditAndContinue/IEditAndContinueService.cs index cc39e13802a7f..abbbf80f06865 100644 --- a/src/Features/Core/Portable/EditAndContinue/IEditAndContinueService.cs +++ b/src/Features/Core/Portable/EditAndContinue/IEditAndContinueService.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; diff --git a/src/Features/Core/Portable/EditAndContinue/Remote/RemoteDebuggingSessionProxy.cs b/src/Features/Core/Portable/EditAndContinue/Remote/RemoteDebuggingSessionProxy.cs index 376c21819f30c..21d56b9a3274b 100644 --- a/src/Features/Core/Portable/EditAndContinue/Remote/RemoteDebuggingSessionProxy.cs +++ b/src/Features/Core/Portable/EditAndContinue/Remote/RemoteDebuggingSessionProxy.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; diff --git a/src/Features/Core/Portable/EditAndContinue/SolutionSnapshotRegistry.cs b/src/Features/Core/Portable/EditAndContinue/SolutionSnapshotRegistry.cs index f070c83001665..c5b914ff79999 100644 --- a/src/Features/Core/Portable/EditAndContinue/SolutionSnapshotRegistry.cs +++ b/src/Features/Core/Portable/EditAndContinue/SolutionSnapshotRegistry.cs @@ -8,7 +8,6 @@ using System.Threading; using Microsoft.CodeAnalysis.Contracts.Client; using Microsoft.CodeAnalysis.Host.Mef; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.EditAndContinue; diff --git a/src/Features/Core/Portable/EditAndContinue/SolutionUpdate.cs b/src/Features/Core/Portable/EditAndContinue/SolutionUpdate.cs index 3b6caa83edbb3..54411d4be74a6 100644 --- a/src/Features/Core/Portable/EditAndContinue/SolutionUpdate.cs +++ b/src/Features/Core/Portable/EditAndContinue/SolutionUpdate.cs @@ -24,13 +24,13 @@ internal readonly struct SolutionUpdate( public readonly ImmutableArray<(DocumentId DocumentId, ImmutableArray Diagnostics)> DocumentsWithRudeEdits = documentsWithRudeEdits; public readonly Diagnostic? SyntaxError = syntaxError; - public static SolutionUpdate Blocked( + public static SolutionUpdate Empty( ImmutableArray diagnostics, ImmutableArray<(DocumentId, ImmutableArray)> documentsWithRudeEdits, Diagnostic? syntaxError, - bool hasEmitErrors) + ModuleUpdateStatus status) => new( - new(syntaxError != null || hasEmitErrors ? ModuleUpdateStatus.Blocked : ModuleUpdateStatus.RestartRequired, []), + new(status, Updates: []), nonRemappableRegions: [], projectBaselines: [], diagnostics, diff --git a/src/Features/Core/Portable/EmbeddedLanguages/AbstractLanguageDetector.cs b/src/Features/Core/Portable/EmbeddedLanguages/AbstractLanguageDetector.cs index 5c4048ac1afbf..503a4fdd866b5 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/AbstractLanguageDetector.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/AbstractLanguageDetector.cs @@ -20,7 +20,7 @@ internal abstract class AbstractLanguageDetector( where TOptions : struct, Enum { protected readonly EmbeddedLanguageInfo Info = info; - protected readonly EmbeddedLanguageDetector Detector = new EmbeddedLanguageDetector(info, languageIdentifiers, commentDetector); + protected readonly EmbeddedLanguageDetector Detector = new(info, languageIdentifiers, commentDetector); /// /// Whether or not this is an argument to a well known api for this language (like Regex.Match or JToken.Parse). diff --git a/src/Features/Core/Portable/EmbeddedLanguages/EmbeddedLanguageDetector.cs b/src/Features/Core/Portable/EmbeddedLanguages/EmbeddedLanguageDetector.cs index 40607160ecfcb..37359943592a9 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/EmbeddedLanguageDetector.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/EmbeddedLanguageDetector.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; @@ -322,7 +321,8 @@ private bool IsEmbeddedLanguageStringLiteralToken( semanticModel.GetDeclaredSymbol(variableDeclarator, cancellationToken) ?? semanticModel.GetDeclaredSymbol(syntaxFacts.GetIdentifierOfVariableDeclarator(variableDeclarator).GetRequiredParent(), cancellationToken); - return IsLocalConsumedByApiWithStringSyntaxAttribute(symbol, container, semanticModel, cancellationToken, out identifier); + return IsLocalConsumedByApiWithStringSyntaxAttribute(symbol, container, semanticModel, cancellationToken, out identifier) || + IsFieldConsumedByApiWithStringSyntaxAttribute(symbol, container, semanticModel, cancellationToken, out identifier); } return false; @@ -336,46 +336,83 @@ private bool IsLocalConsumedByApiWithStringSyntaxAttribute( [NotNullWhen(true)] out string? identifier) { identifier = null; - if (symbol is not ILocalSymbol localSymbol) + if (symbol is not ILocalSymbol { Name: not "" } localSymbol) return false; var blockFacts = this.Info.BlockFacts; - var syntaxFacts = this.Info.SyntaxFacts; var block = tokenParent.AncestorsAndSelf().FirstOrDefault(blockFacts.IsExecutableBlock); if (block is null) return false; - var localName = localSymbol.Name; - if (localName == "") - return false; - // Now look at the next statements that follow for usages of this local variable. foreach (var statement in blockFacts.GetExecutableBlockStatements(block)) { - foreach (var descendent in statement.DescendantNodesAndSelf()) - { - cancellationToken.ThrowIfCancellationRequested(); + if (CheckDescendants(localSymbol, semanticModel, statement, cancellationToken, out identifier)) + return true; + } - if (!syntaxFacts.IsIdentifierName(descendent)) - continue; + return false; + } - var identifierToken = syntaxFacts.GetIdentifierOfIdentifierName(descendent); - if (identifierToken.ValueText != localName) - continue; + private bool IsFieldConsumedByApiWithStringSyntaxAttribute( + ISymbol? symbol, + SyntaxNode tokenParent, + SemanticModel semanticModel, + CancellationToken cancellationToken, + [NotNullWhen(true)] out string? identifier) + { + identifier = null; + if (symbol is not IFieldSymbol { Name: not "" } fieldSymbol) + return false; - var otherSymbol = semanticModel.GetSymbolInfo(descendent, cancellationToken).GetAnySymbol(); + var isConst = fieldSymbol.IsConst; + var isStaticReadonly = fieldSymbol.IsStatic && fieldSymbol.IsReadOnly; + if (!isConst && !isStaticReadonly) + return false; - // Only do a direct check here. We don't want to continually do indirect checks where a string literal - // is assigned to one local, assigned to another local, assigned to another local, and so on. - if (localSymbol.Equals(otherSymbol) && - IsEmbeddedLanguageStringLiteralToken_Direct(identifierToken, semanticModel, cancellationToken, out identifier)) - { - return true; - } + var syntaxFacts = this.Info.SyntaxFacts; + + var typeDeclaration = tokenParent.AncestorsAndSelf().FirstOrDefault(syntaxFacts.IsTypeDeclaration); + if (typeDeclaration is null) + return false; + + return CheckDescendants(fieldSymbol, semanticModel, typeDeclaration, cancellationToken, out identifier); + } + + private bool CheckDescendants( + ISymbol symbol, + SemanticModel semanticModel, + SyntaxNode node, + CancellationToken cancellationToken, + [NotNullWhen(true)] out string? identifier) + { + var symbolName = symbol.Name; + var syntaxFacts = this.Info.SyntaxFacts; + + foreach (var descendent in node.DescendantNodesAndSelf()) + { + cancellationToken.ThrowIfCancellationRequested(); + + if (!syntaxFacts.IsIdentifierName(descendent)) + continue; + + var identifierToken = syntaxFacts.GetIdentifierOfIdentifierName(descendent); + if (identifierToken.ValueText != symbolName) + continue; + + var otherSymbol = semanticModel.GetSymbolInfo(descendent, cancellationToken).GetAnySymbol(); + + // Only do a direct check here. We don't want to continually do indirect checks where a string literal + // is assigned to one local, assigned to another local, assigned to another local, and so on. + if (symbol.Equals(otherSymbol) && + IsEmbeddedLanguageStringLiteralToken_Direct(identifierToken, semanticModel, cancellationToken, out identifier)) + { + return true; } } + identifier = null; return false; } diff --git a/src/Features/Core/Portable/EmbeddedLanguages/ExportEmbeddedLanguageFeatureServiceAttribute.cs b/src/Features/Core/Portable/EmbeddedLanguages/ExportEmbeddedLanguageFeatureServiceAttribute.cs index 1b6b7ef232887..256072c40ec1b 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/ExportEmbeddedLanguageFeatureServiceAttribute.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/ExportEmbeddedLanguageFeatureServiceAttribute.cs @@ -4,7 +4,6 @@ using System; using System.Composition; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.EmbeddedLanguages; diff --git a/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonLexer.cs b/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonLexer.cs index bc07d43a097fd..a99d7f22d249d 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonLexer.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonLexer.cs @@ -8,7 +8,6 @@ using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json; diff --git a/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/AbstractJsonDiagnosticAnalyzer.cs b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/AbstractJsonDiagnosticAnalyzer.cs index 1fa13d07cf929..ff7204ab6e17c 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/AbstractJsonDiagnosticAnalyzer.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/AbstractJsonDiagnosticAnalyzer.cs @@ -7,7 +7,6 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.EmbeddedLanguages; using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Simplification; namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json.LanguageServices; diff --git a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/IRegexNodeVisitor.cs b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/IRegexNodeVisitor.cs index 8770faabbacd5..388df5e1572c8 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/IRegexNodeVisitor.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/IRegexNodeVisitor.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.EmbeddedLanguages.RegularExpressions; internal interface IRegexNodeVisitor diff --git a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexCharClass.cs b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexCharClass.cs index 8e1974186964a..1bccdf1542ee4 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexCharClass.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexCharClass.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 - // LICENSING NOTE: The license for this file is from the originating // source and not the general https://github.com/dotnet/roslyn license. // See https://github.com/dotnet/runtime/blob/5b5bd46c03c86f8545f2c4c8628ac25d875210fe/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCharClass.cs diff --git a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexLexer.cs b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexLexer.cs index 056f1278ffb3b..d931882a81304 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexLexer.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexLexer.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Diagnostics; using System.Text.RegularExpressions; diff --git a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexNode.cs b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexNode.cs index ad7e40a179e7f..d83c30efce233 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexNode.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexNode.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.EmbeddedLanguages.Common; namespace Microsoft.CodeAnalysis.EmbeddedLanguages.RegularExpressions; diff --git a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexNodes.cs b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexNodes.cs index d5debdeeacfda..33bd1687e4eaf 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexNodes.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexNodes.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Immutable; using System.Diagnostics; diff --git a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexParser.cs b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexParser.cs index 1e5bb6f880021..03b98b5d837e8 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexParser.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexParser.cs @@ -12,7 +12,6 @@ using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.EmbeddedLanguages.RegularExpressions; diff --git a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexTree.cs b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexTree.cs index 2c47898336cc8..dbe5582ef778f 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexTree.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexTree.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using Microsoft.CodeAnalysis.EmbeddedLanguages.Common; using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; diff --git a/src/Features/Core/Portable/EmbeddedLanguages/StackFrame/StackFrameTree.cs b/src/Features/Core/Portable/EmbeddedLanguages/StackFrame/StackFrameTree.cs index c457311e87240..e69ff2bd30731 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/StackFrame/StackFrameTree.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/StackFrame/StackFrameTree.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.Immutable; using Microsoft.CodeAnalysis.EmbeddedLanguages.Common; using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; diff --git a/src/Features/Core/Portable/EncapsulateField/EncapsulateFieldResult.cs b/src/Features/Core/Portable/EncapsulateField/EncapsulateFieldResult.cs index 0318404ba0175..f176f8d3ae829 100644 --- a/src/Features/Core/Portable/EncapsulateField/EncapsulateFieldResult.cs +++ b/src/Features/Core/Portable/EncapsulateField/EncapsulateFieldResult.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Threading; using System.Threading.Tasks; diff --git a/src/Features/Core/Portable/EncapsulateField/IRemoteEncapsulateFieldService.cs b/src/Features/Core/Portable/EncapsulateField/IRemoteEncapsulateFieldService.cs index 74bec39df7c2f..87afcffb404be 100644 --- a/src/Features/Core/Portable/EncapsulateField/IRemoteEncapsulateFieldService.cs +++ b/src/Features/Core/Portable/EncapsulateField/IRemoteEncapsulateFieldService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; diff --git a/src/Features/Core/Portable/ExternalAccess/Pythia/Api/PythiaCompletionProviderBase.cs b/src/Features/Core/Portable/ExternalAccess/Pythia/Api/PythiaCompletionProviderBase.cs index 4983379f1e651..8a725049a7dcf 100644 --- a/src/Features/Core/Portable/ExternalAccess/Pythia/Api/PythiaCompletionProviderBase.cs +++ b/src/Features/Core/Portable/ExternalAccess/Pythia/Api/PythiaCompletionProviderBase.cs @@ -12,7 +12,6 @@ using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.Pythia.Api; diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/IUnitTestingStackTraceServiceAccessor.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/IUnitTestingStackTraceServiceAccessor.cs index 3fe7fe959d471..b043ef3e96381 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/IUnitTestingStackTraceServiceAccessor.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/IUnitTestingStackTraceServiceAccessor.cs @@ -14,5 +14,6 @@ internal interface IUnitTestingStackTraceServiceAccessor : IWorkspaceService Task> TryParseAsync(string input, Workspace workspace, CancellationToken cancellationToken); Task TryFindMethodDefinitionAsync(Workspace workspace, UnitTestingParsedFrameWrapper parsedFrame, CancellationToken cancellationToken); (Document? document, int lineNumber) GetDocumentAndLine(Workspace workspace, UnitTestingParsedFrameWrapper parsedFrame); + (TextDocument? textDocument, int lineNumber) GetTextDocumentAndLine(Workspace workspace, UnitTestingParsedFrameWrapper parsedFrame); Task TryNavigateToAsync(Workspace workspace, UnitTestingDefinitionItemWrapper definitionItem, bool showInPreviewTab, bool activateTab, CancellationToken cancellationToken); } diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/NewUnitTestingIncrementalAnalyzerProvider.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/NewUnitTestingIncrementalAnalyzerProvider.cs index f1cf82d3fe09c..947a2a790761d 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/NewUnitTestingIncrementalAnalyzerProvider.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/NewUnitTestingIncrementalAnalyzerProvider.cs @@ -4,7 +4,6 @@ using Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.SolutionCrawler; using Microsoft.CodeAnalysis.Host; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.Api; diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingInvocationReasons_Constants.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingInvocationReasons_Constants.cs index fe52a29fb9bca..17020653efd37 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingInvocationReasons_Constants.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingInvocationReasons_Constants.cs @@ -2,10 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - -using System.Collections.Immutable; - namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.Api; internal readonly partial struct UnitTestingInvocationReasons diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/AbstractUnitTestingDocumentDifferenceService.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/AbstractUnitTestingDocumentDifferenceService.cs index cc6921ce48d12..39d8e7780b19c 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/AbstractUnitTestingDocumentDifferenceService.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/AbstractUnitTestingDocumentDifferenceService.cs @@ -8,7 +8,6 @@ using Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.Api; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.SolutionCrawler; diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/ExportUnitTestingIncrementalAnalyzerProviderAttribute.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/ExportUnitTestingIncrementalAnalyzerProviderAttribute.cs index 91b2972431612..751cb8ad47b9f 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/ExportUnitTestingIncrementalAnalyzerProviderAttribute.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/ExportUnitTestingIncrementalAnalyzerProviderAttribute.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.Composition; diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/IUnitTestingIncrementalAnalyzer.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/IUnitTestingIncrementalAnalyzer.cs index f8e0c8bef76b5..d8b705fd40085 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/IUnitTestingIncrementalAnalyzer.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/IUnitTestingIncrementalAnalyzer.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.ExternalAccess.UnitTesting.Api; diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingIdleProcessor.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingIdleProcessor.cs index 1852b45b27be3..94ccaba167f4a 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingIdleProcessor.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingIdleProcessor.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.SolutionCrawler; diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingAsyncProjectWorkItemQueue.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingAsyncProjectWorkItemQueue.cs index ba19a19a75adc..0746d6bc4e899 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingAsyncProjectWorkItemQueue.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingAsyncProjectWorkItemQueue.cs @@ -6,7 +6,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Internal.Log; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.SolutionCrawler; diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingLowPriorityProcessor.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingLowPriorityProcessor.cs index a9bf69e2f06c9..4d63273c453cd 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingLowPriorityProcessor.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingLowPriorityProcessor.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.Shared.TestHooks; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.SolutionCrawler; diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.cs index f3850a0e9f046..6b4436bfaa40a 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.SolutionCrawler; diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingStackTraceServiceAccessor.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingStackTraceServiceAccessor.cs index aeb2a32036ddb..394da78f82438 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingStackTraceServiceAccessor.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingStackTraceServiceAccessor.cs @@ -19,9 +19,20 @@ internal sealed class UnitTestingStackTraceServiceAccessor( { private readonly IStackTraceExplorerService _stackTraceExplorerService = stackTraceExplorerService; - public (Document? document, int lineNumber) GetDocumentAndLine(Workspace workspace, UnitTestingParsedFrameWrapper parsedFrame) + public (TextDocument? textDocument, int lineNumber) GetTextDocumentAndLine(Workspace workspace, UnitTestingParsedFrameWrapper parsedFrame) => _stackTraceExplorerService.GetDocumentAndLine(workspace.CurrentSolution, parsedFrame.UnderlyingObject); + public (Document? document, int lineNumber) GetDocumentAndLine(Workspace workspace, UnitTestingParsedFrameWrapper parsedFrame) + { + var (textDocument, lineNumber) = GetTextDocumentAndLine(workspace, parsedFrame); + if (textDocument is Document document) + { + return (document, lineNumber); + } + + return (null, default); + } + public async Task TryFindMethodDefinitionAsync(Workspace workspace, UnitTestingParsedFrameWrapper parsedFrame, CancellationToken cancellationToken) { var definition = await _stackTraceExplorerService.TryFindDefinitionAsync(workspace.CurrentSolution, parsedFrame.UnderlyingObject, StackFrameSymbolPart.Method, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptDiagnosticData.cs b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptDiagnosticData.cs index 24ab7f2ba2dc0..37113a83ad6c9 100644 --- a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptDiagnosticData.cs +++ b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptDiagnosticData.cs @@ -7,7 +7,6 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api; diff --git a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptSignatureHelpProviderBase.cs b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptSignatureHelpProviderBase.cs index a1920c9d3aa03..d0466a9cbb719 100644 --- a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptSignatureHelpProviderBase.cs +++ b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptSignatureHelpProviderBase.cs @@ -4,7 +4,6 @@ using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.SignatureHelp; namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api; diff --git a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptGlyphHelpers.cs b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptGlyphHelpers.cs index d0764122e64e8..1fb17bd0fa40f 100644 --- a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptGlyphHelpers.cs +++ b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptGlyphHelpers.cs @@ -2,10 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript; diff --git a/src/Features/Core/Portable/ExternalAccess/Watch/Api/WatchHotReloadService.cs b/src/Features/Core/Portable/ExternalAccess/Watch/Api/WatchHotReloadService.cs index c6de8f95f817a..2985b5b576ddc 100644 --- a/src/Features/Core/Portable/ExternalAccess/Watch/Api/WatchHotReloadService.cs +++ b/src/Features/Core/Portable/ExternalAccess/Watch/Api/WatchHotReloadService.cs @@ -190,7 +190,9 @@ public async Task GetUpdatesAsync(Solution solution, IImmutableSet instance._sessionId; + + public IEditAndContinueService EncService + => instance._encService; } } #endif diff --git a/src/Features/Core/Portable/ExtractClass/ExtractClassOptions.cs b/src/Features/Core/Portable/ExtractClass/ExtractClassOptions.cs index 7af4fb35e2e08..91fea2f287893 100644 --- a/src/Features/Core/Portable/ExtractClass/ExtractClassOptions.cs +++ b/src/Features/Core/Portable/ExtractClass/ExtractClassOptions.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; namespace Microsoft.CodeAnalysis.ExtractClass; diff --git a/src/Features/Core/Portable/ExtractClass/ExtractClassWithDialogCodeAction.cs b/src/Features/Core/Portable/ExtractClass/ExtractClassWithDialogCodeAction.cs index 335f892d48495..30069eb82a519 100644 --- a/src/Features/Core/Portable/ExtractClass/ExtractClassWithDialogCodeAction.cs +++ b/src/Features/Core/Portable/ExtractClass/ExtractClassWithDialogCodeAction.cs @@ -85,7 +85,8 @@ protected override async Task> ComputeOperation _selectedType.IsRecord, TypeKind.Class, extractClassOptions.TypeName, - typeParameters: ExtractTypeHelpers.GetRequiredTypeParametersForMembers(_selectedType, extractClassOptions.MemberAnalysisResults.Select(m => m.Member))); + typeParameters: ExtractTypeHelpers.GetRequiredTypeParametersForMembers( + _selectedType, extractClassOptions.MemberAnalysisResults.SelectAsArray(m => m.Member))); var containingNamespaceDisplay = namespaceService.GetContainingNamespaceDisplay( _selectedType, diff --git a/src/Features/Core/Portable/ExtractInterface/AbstractExtractInterfaceService.cs b/src/Features/Core/Portable/ExtractInterface/AbstractExtractInterfaceService.cs index 14a5aa1e13e79..a764882369862 100644 --- a/src/Features/Core/Portable/ExtractInterface/AbstractExtractInterfaceService.cs +++ b/src/Features/Core/Portable/ExtractInterface/AbstractExtractInterfaceService.cs @@ -7,7 +7,6 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Linq; -using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeCleanup; @@ -15,7 +14,6 @@ using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -91,13 +89,13 @@ public async Task AnalyzeTypeAtPositionAsync } var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - if (semanticModel.GetDeclaredSymbol(typeNode, cancellationToken) is not INamedTypeSymbol typeToExtractFrom) + if (semanticModel.GetDeclaredSymbol(typeNode, cancellationToken) is not INamedTypeSymbol { TypeKind: not TypeKind.Extension } typeToExtractFrom) { var errorMessage = FeaturesResources.Could_not_extract_interface_colon_The_selection_is_not_inside_a_class_interface_struct; return new ExtractInterfaceTypeAnalysisResult(errorMessage); } - var extractableMembers = typeToExtractFrom.GetMembers().Where(IsExtractableMember); + var extractableMembers = typeToExtractFrom.GetMembers().WhereAsArray(IsExtractableMember); if (!extractableMembers.Any()) { var errorMessage = FeaturesResources.Could_not_extract_interface_colon_The_type_does_not_contain_any_member_that_can_be_extracted_to_an_interface; @@ -256,12 +254,12 @@ private async Task ExtractInterfaceToSameFileAsync( internal static ExtractInterfaceOptionsResult GetExtractInterfaceOptions( Document document, INamedTypeSymbol type, - IEnumerable extractableMembers, + ImmutableArray extractableMembers, string containingNamespace, SyntaxFormattingOptions formattingOptions, CancellationToken cancellationToken) { - var conflictingTypeNames = type.ContainingNamespace.GetAllTypes(cancellationToken).Select(t => t.Name); + var conflictingTypeNames = type.ContainingNamespace.GetAllTypes(cancellationToken).SelectAsArray(t => t.Name); var candidateInterfaceName = type.TypeKind == TypeKind.Interface ? type.Name : "I" + type.Name; var defaultInterfaceName = NameGenerator.GenerateUniqueName(candidateInterfaceName, name => !conflictingTypeNames.Contains(name)); var generatedNameTypeParameterSuffix = ExtractTypeHelpers.GetTypeParameterSuffix(document, formattingOptions, type, extractableMembers, cancellationToken); @@ -269,12 +267,11 @@ internal static ExtractInterfaceOptionsResult GetExtractInterfaceOptions( var service = document.Project.Solution.Services.GetRequiredService(); return service.GetExtractInterfaceOptions( document, - [.. extractableMembers], + extractableMembers, defaultInterfaceName, - [.. conflictingTypeNames], + conflictingTypeNames, containingNamespace, - generatedNameTypeParameterSuffix, - cancellationToken); + generatedNameTypeParameterSuffix); } private static async Task GetFormattedSolutionAsync(Solution unformattedSolution, IEnumerable documentIds, CancellationToken cancellationToken) diff --git a/src/Features/Core/Portable/ExtractInterface/ExtractInterfaceTypeAnalysisResult.cs b/src/Features/Core/Portable/ExtractInterface/ExtractInterfaceTypeAnalysisResult.cs index c043189d7b8ba..9b2631a36edff 100644 --- a/src/Features/Core/Portable/ExtractInterface/ExtractInterfaceTypeAnalysisResult.cs +++ b/src/Features/Core/Portable/ExtractInterface/ExtractInterfaceTypeAnalysisResult.cs @@ -5,6 +5,7 @@ #nullable disable using System.Collections.Generic; +using System.Collections.Immutable; using Microsoft.CodeAnalysis.Formatting; namespace Microsoft.CodeAnalysis.ExtractInterface; @@ -15,7 +16,7 @@ internal sealed class ExtractInterfaceTypeAnalysisResult public readonly Document DocumentToExtractFrom; public readonly SyntaxNode TypeNode; public readonly INamedTypeSymbol TypeToExtractFrom; - public readonly IEnumerable ExtractableMembers; + public readonly ImmutableArray ExtractableMembers; public readonly SyntaxFormattingOptions FormattingOptions; public readonly string ErrorMessage; @@ -23,7 +24,7 @@ public ExtractInterfaceTypeAnalysisResult( Document documentToExtractFrom, SyntaxNode typeNode, INamedTypeSymbol typeToExtractFrom, - IEnumerable extractableMembers, + ImmutableArray extractableMembers, SyntaxFormattingOptions formattingOptions) { CanExtractInterface = true; diff --git a/src/Features/Core/Portable/ExtractInterface/IExtractInterfaceOptionsService.cs b/src/Features/Core/Portable/ExtractInterface/IExtractInterfaceOptionsService.cs index 6281c68a90e76..e420c284e41d5 100644 --- a/src/Features/Core/Portable/ExtractInterface/IExtractInterfaceOptionsService.cs +++ b/src/Features/Core/Portable/ExtractInterface/IExtractInterfaceOptionsService.cs @@ -2,8 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Generic; -using System.Threading; +using System.Collections.Immutable; using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.ExtractInterface; @@ -12,10 +11,9 @@ internal interface IExtractInterfaceOptionsService : IWorkspaceService { ExtractInterfaceOptionsResult GetExtractInterfaceOptions( Document document, - List extractableMembers, + ImmutableArray extractableMembers, string defaultInterfaceName, - List conflictingTypeNames, + ImmutableArray conflictingTypeNames, string defaultNamespace, - string generatedNameTypeParameterSuffix, - CancellationToken cancellationToken); + string generatedNameTypeParameterSuffix); } diff --git a/src/Features/Core/Portable/ExtractMethod/AbstractSyntaxTriviaService.cs b/src/Features/Core/Portable/ExtractMethod/AbstractSyntaxTriviaService.cs index 0137fc6fd450b..b12ececb621d5 100644 --- a/src/Features/Core/Portable/ExtractMethod/AbstractSyntaxTriviaService.cs +++ b/src/Features/Core/Portable/ExtractMethod/AbstractSyntaxTriviaService.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; diff --git a/src/Features/Core/Portable/ExtractMethod/Extensions.cs b/src/Features/Core/Portable/ExtractMethod/Extensions.cs index fbe19e31d10d3..ed7117c77b246 100644 --- a/src/Features/Core/Portable/ExtractMethod/Extensions.cs +++ b/src/Features/Core/Portable/ExtractMethod/Extensions.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Linq; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExtractMethod; diff --git a/src/Features/Core/Portable/ExtractMethod/ExtractMethodFlowControlInformation.cs b/src/Features/Core/Portable/ExtractMethod/ExtractMethodFlowControlInformation.cs index 96320aa1f77d2..7ef992a4f3587 100644 --- a/src/Features/Core/Portable/ExtractMethod/ExtractMethodFlowControlInformation.cs +++ b/src/Features/Core/Portable/ExtractMethod/ExtractMethodFlowControlInformation.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExtractMethod; diff --git a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.Analyzer.cs b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.Analyzer.cs index f0bcd89c04a44..63bef091ccac2 100644 --- a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.Analyzer.cs +++ b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.Analyzer.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; diff --git a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.AnalyzerResult.cs b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.AnalyzerResult.cs index 0e6d7f3bd3e48..c9f6670cbe216 100644 --- a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.AnalyzerResult.cs +++ b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.AnalyzerResult.cs @@ -4,7 +4,6 @@ #nullable disable -using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; diff --git a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.CodeGenerator.cs b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.CodeGenerator.cs index fddabcd7a5f73..4fea5a3cca284 100644 --- a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.CodeGenerator.cs +++ b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.CodeGenerator.cs @@ -4,11 +4,9 @@ #nullable disable -using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; diff --git a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.TypeParameterCollector.cs b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.TypeParameterCollector.cs index 5302d93111925..edb4bfe144ced 100644 --- a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.TypeParameterCollector.cs +++ b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.TypeParameterCollector.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -21,10 +19,10 @@ protected class TypeParameterCollector : SymbolVisitor { private readonly List _typeParameters = []; - public static IEnumerable Collect(ITypeSymbol typeSymbol) + public static IEnumerable Collect(ITypeSymbol? typeSymbol) { var collector = new TypeParameterCollector(); - typeSymbol.Accept(collector); + typeSymbol?.Accept(collector); return collector._typeParameters; } diff --git a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.VariableInfo.cs b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.VariableInfo.cs index a217f5dd0629b..537e58af2e7c9 100644 --- a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.VariableInfo.cs +++ b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.VariableInfo.cs @@ -7,7 +7,6 @@ using System; using System.Linq; using System.Threading; -using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; diff --git a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.cs b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.cs index a65a48fe3c1b2..de90315159099 100644 --- a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.cs +++ b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.cs @@ -4,7 +4,6 @@ #nullable disable -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading; diff --git a/src/Features/Core/Portable/ExtractMethod/OperationStatus.cs b/src/Features/Core/Portable/ExtractMethod/OperationStatus.cs index 028fdf2055d99..b727c06ebaaec 100644 --- a/src/Features/Core/Portable/ExtractMethod/OperationStatus.cs +++ b/src/Features/Core/Portable/ExtractMethod/OperationStatus.cs @@ -2,16 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExtractMethod; internal sealed partial class OperationStatus { - public OperationStatus(bool succeeded, string reason) + public OperationStatus(bool succeeded, string? reason) { Succeeded = succeeded; Reasons = reason == null ? [] : [reason]; diff --git a/src/Features/Core/Portable/ExtractMethod/OperationStatus_Statics.cs b/src/Features/Core/Portable/ExtractMethod/OperationStatus_Statics.cs index 1938f6d573211..9a0bed51fdbf3 100644 --- a/src/Features/Core/Portable/ExtractMethod/OperationStatus_Statics.cs +++ b/src/Features/Core/Portable/ExtractMethod/OperationStatus_Statics.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.ExtractMethod; internal sealed partial class OperationStatus diff --git a/src/Features/Core/Portable/ExtractMethod/OperationStatus`1.cs b/src/Features/Core/Portable/ExtractMethod/OperationStatus`1.cs index f1a621a29d163..e3586a17967f0 100644 --- a/src/Features/Core/Portable/ExtractMethod/OperationStatus`1.cs +++ b/src/Features/Core/Portable/ExtractMethod/OperationStatus`1.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.ExtractMethod; /// diff --git a/src/Features/Core/Portable/ExtractMethod/UniqueNameGenerator.cs b/src/Features/Core/Portable/ExtractMethod/UniqueNameGenerator.cs index b958ef1103e14..fc790e776cf12 100644 --- a/src/Features/Core/Portable/ExtractMethod/UniqueNameGenerator.cs +++ b/src/Features/Core/Portable/ExtractMethod/UniqueNameGenerator.cs @@ -2,10 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Shared.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExtractMethod; diff --git a/src/Features/Core/Portable/FeaturesResources.resx b/src/Features/Core/Portable/FeaturesResources.resx index 48ea3a459fbec..079506c51424e 100644 --- a/src/Features/Core/Portable/FeaturesResources.resx +++ b/src/Features/Core/Portable/FeaturesResources.resx @@ -2553,7 +2553,7 @@ Zero-width positive lookbehind assertions are typically used at the beginning of The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. Apply file header preferences @@ -3153,14 +3153,20 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Semantic search query failed to compile - - The query does not specify '{0}' method or top-level function + + The query does not specify '{0}' top-level function Method '{0}' must be static and non-generic - - Method '{0}' must have a single parameter of type '{1}' and return '{2}' + + The query specifies multiple top-level functions '{1}' + + + Top-level function '{0}' must have a single parameter + + + Type '{0}' is not among supported types: {1} Unable to load type '{0}': '{1}' diff --git a/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService.ProgressAdapter.cs b/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService.ProgressAdapter.cs index 421cf9b778d42..362e59c3fb62f 100644 --- a/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService.ProgressAdapter.cs +++ b/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService.ProgressAdapter.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; diff --git a/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService_FindImplementations.cs b/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService_FindImplementations.cs index c3350662e2f92..287b621957335 100644 --- a/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService_FindImplementations.cs +++ b/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService_FindImplementations.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Classification; diff --git a/src/Features/Core/Portable/FindUsages/DefinitionItem.DefaultDefinitionItem.cs b/src/Features/Core/Portable/FindUsages/DefinitionItem.DefaultDefinitionItem.cs index 90c740c26d18e..b1345c49b226d 100644 --- a/src/Features/Core/Portable/FindUsages/DefinitionItem.DefaultDefinitionItem.cs +++ b/src/Features/Core/Portable/FindUsages/DefinitionItem.DefaultDefinitionItem.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.Navigation; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.FindUsages; diff --git a/src/Features/Core/Portable/FindUsages/DefinitionItem.cs b/src/Features/Core/Portable/FindUsages/DefinitionItem.cs index 2371806d424cd..3589eaa3c5a78 100644 --- a/src/Features/Core/Portable/FindUsages/DefinitionItem.cs +++ b/src/Features/Core/Portable/FindUsages/DefinitionItem.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.Navigation; using Microsoft.CodeAnalysis.Tags; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.FindUsages; diff --git a/src/Features/Core/Portable/FindUsages/DefinitionsAndReferences.cs b/src/Features/Core/Portable/FindUsages/DefinitionsAndReferences.cs index 6ccf57b185286..21a2763990a1e 100644 --- a/src/Features/Core/Portable/FindUsages/DefinitionsAndReferences.cs +++ b/src/Features/Core/Portable/FindUsages/DefinitionsAndReferences.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Immutable; using Roslyn.Utilities; diff --git a/src/Features/Core/Portable/FindUsages/FindUsagesHelpers.cs b/src/Features/Core/Portable/FindUsages/FindUsagesHelpers.cs index 1a2d3910fcd87..207c7ba1e36db 100644 --- a/src/Features/Core/Portable/FindUsages/FindUsagesHelpers.cs +++ b/src/Features/Core/Portable/FindUsages/FindUsagesHelpers.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.FindSymbols; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SymbolMapping; @@ -18,25 +19,40 @@ internal static class FindUsagesHelpers public static string GetDisplayName(ISymbol symbol) => symbol.IsConstructor() ? symbol.ContainingType.Name : symbol.Name; + public static Task<(ISymbol symbol, Project project)?> GetRelevantSymbolAndProjectAtPositionAsync( + Document document, int position, CancellationToken cancellationToken) + => GetRelevantSymbolAndProjectAtPositionAsync(document, position, preferPrimaryConstructor: false, cancellationToken); + /// - /// Common helper for both the synchronous and streaming versions of FAR. - /// It returns the symbol we want to search for and the solution we should - /// be searching. - /// - /// Note that the returned may absolutely *not* be - /// the same as document.Project.Solution. This is because - /// there may be symbol mapping involved (for example in Metadata-As-Source - /// scenarios). + /// Common helper for both the synchronous and streaming versions of FAR. It returns the symbol we want to search + /// for and the solution we should be searching. + /// Note that the returned may absolutely *not* be the same as + /// document.Project.Solution. This is because there may be symbol mapping involved (for example in + /// Metadata-As-Source scenarios). /// + /// Whether the named type or primary constructor should be preferred if the + /// position is on a type-header fof a type declaration that has primary constructor parameters. public static async Task<(ISymbol symbol, Project project)?> GetRelevantSymbolAndProjectAtPositionAsync( - Document document, int position, CancellationToken cancellationToken) + Document document, int position, bool preferPrimaryConstructor, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - var symbol = await SymbolFinder.FindSymbolAtPositionAsync(document, position, cancellationToken: cancellationToken).ConfigureAwait(false); + var symbol = await SymbolFinder.FindSymbolAtPositionAsync(document, position, cancellationToken).ConfigureAwait(false); if (symbol == null) return null; + if (preferPrimaryConstructor && symbol is INamedTypeSymbol namedType) + { + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var headerFacts = document.GetRequiredLanguageService(); + var semanticFacts = document.GetRequiredLanguageService(); + if (headerFacts.IsOnTypeHeader(root, position, out _) && + semanticFacts.TryGetPrimaryConstructor(namedType, out var primaryConstructor)) + { + symbol = primaryConstructor; + } + } + // If this document is not in the primary workspace, we may want to search for results // in a solution different from the one we started in. Use the starting workspace's // ISymbolMappingService to get a context for searching in the proper solution. diff --git a/src/Features/Core/Portable/FindUsages/IRemoteFindUsagesService.cs b/src/Features/Core/Portable/FindUsages/IRemoteFindUsagesService.cs index 9e9b542e57027..65610abfb1b33 100644 --- a/src/Features/Core/Portable/FindUsages/IRemoteFindUsagesService.cs +++ b/src/Features/Core/Portable/FindUsages/IRemoteFindUsagesService.cs @@ -17,7 +17,6 @@ using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.FindUsages; diff --git a/src/Features/Core/Portable/FindUsages/SourceReferenceItem.cs b/src/Features/Core/Portable/FindUsages/SourceReferenceItem.cs index 56344da89e667..e84a08fa19d73 100644 --- a/src/Features/Core/Portable/FindUsages/SourceReferenceItem.cs +++ b/src/Features/Core/Portable/FindUsages/SourceReferenceItem.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using Microsoft.CodeAnalysis.Classification; diff --git a/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyService.cs b/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyService.cs index b23221d2d3f9e..e743bde9072fe 100644 --- a/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyService.cs +++ b/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyService.cs @@ -15,7 +15,6 @@ using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.LanguageService; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Features/Core/Portable/GenerateComparisonOperators/GenerateComparisonOperatorsCodeRefactoringProvider.cs b/src/Features/Core/Portable/GenerateComparisonOperators/GenerateComparisonOperatorsCodeRefactoringProvider.cs index ac299b49b2e62..036250273f867 100644 --- a/src/Features/Core/Portable/GenerateComparisonOperators/GenerateComparisonOperatorsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/GenerateComparisonOperators/GenerateComparisonOperatorsCodeRefactoringProvider.cs @@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.GenerateComparisonOperators; diff --git a/src/Features/Core/Portable/GenerateConstructors/AbstractGenerateConstructorsCodeRefactoringProvider.ConstructorDelegatingCodeAction.cs b/src/Features/Core/Portable/GenerateConstructors/AbstractGenerateConstructorsCodeRefactoringProvider.ConstructorDelegatingCodeAction.cs index a6eeb8b1b2547..07117719bc0ec 100644 --- a/src/Features/Core/Portable/GenerateConstructors/AbstractGenerateConstructorsCodeRefactoringProvider.ConstructorDelegatingCodeAction.cs +++ b/src/Features/Core/Portable/GenerateConstructors/AbstractGenerateConstructorsCodeRefactoringProvider.ConstructorDelegatingCodeAction.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.Immutable; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -12,7 +11,6 @@ using Microsoft.CodeAnalysis.GenerateFromMembers; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.GenerateConstructors; diff --git a/src/Features/Core/Portable/GenerateConstructors/AbstractGenerateConstructorsCodeRefactoringProvider.GenerateConstructorWithDialogCodeAction.cs b/src/Features/Core/Portable/GenerateConstructors/AbstractGenerateConstructorsCodeRefactoringProvider.GenerateConstructorWithDialogCodeAction.cs index 49de2af49508f..8c1468578f1f6 100644 --- a/src/Features/Core/Portable/GenerateConstructors/AbstractGenerateConstructorsCodeRefactoringProvider.GenerateConstructorWithDialogCodeAction.cs +++ b/src/Features/Core/Portable/GenerateConstructors/AbstractGenerateConstructorsCodeRefactoringProvider.GenerateConstructorWithDialogCodeAction.cs @@ -9,8 +9,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeGeneration; -using Microsoft.CodeAnalysis.GenerateFromMembers; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PickMembers; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndHashWithDialogCodeAction.cs b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndHashWithDialogCodeAction.cs index 9a1146eadc7d7..968d6cd8f2fb5 100644 --- a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndHashWithDialogCodeAction.cs +++ b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndHashWithDialogCodeAction.cs @@ -9,7 +9,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PickMembers; using Roslyn.Utilities; diff --git a/src/Features/Core/Portable/GenerateFromMembers/GenerateFromMembersHelpers.cs b/src/Features/Core/Portable/GenerateFromMembers/GenerateFromMembersHelpers.cs index 2b3d574956fac..0c627eaa1a961 100644 --- a/src/Features/Core/Portable/GenerateFromMembers/GenerateFromMembersHelpers.cs +++ b/src/Features/Core/Portable/GenerateFromMembers/GenerateFromMembersHelpers.cs @@ -70,10 +70,10 @@ private static bool IsWritableFieldOrProperty(ISymbol symbol) }; private static bool IsViableField(IFieldSymbol field) - => field.AssociatedSymbol == null; + => field is { AssociatedSymbol: null, CanBeReferencedByName: true }; private static bool IsViableProperty(IPropertySymbol property) - => property.Parameters.IsEmpty; + => property is { Parameters.IsEmpty: true, CanBeReferencedByName: true }; /// /// Returns an array of parameter symbols that correspond to selected member symbols. diff --git a/src/Features/Core/Portable/GenerateFromMembers/SelectedMemberInfo.cs b/src/Features/Core/Portable/GenerateFromMembers/SelectedMemberInfo.cs index 260a7e17e3dfd..87b370f02facf 100644 --- a/src/Features/Core/Portable/GenerateFromMembers/SelectedMemberInfo.cs +++ b/src/Features/Core/Portable/GenerateFromMembers/SelectedMemberInfo.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; -using Microsoft.CodeAnalysis.CodeRefactorings; namespace Microsoft.CodeAnalysis.GenerateFromMembers; diff --git a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.CodeAction.cs b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.CodeAction.cs index e7872f4dae9d6..a12d05bd7e66a 100644 --- a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.CodeAction.cs +++ b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.CodeAction.cs @@ -8,7 +8,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.ProjectManagement; @@ -102,7 +101,7 @@ public override object GetOptions(CancellationToken cancellationToken) var generateTypeOptionsService = _document.Project.Solution.Services.GetRequiredService(); var notificationService = _document.Project.Solution.Services.GetService(); var projectManagementService = _document.Project.Solution.Services.GetService(); - var syntaxFactsService = _document.GetLanguageService(); + var syntaxFactsService = _document.GetRequiredLanguageService(); var typeKindValue = GetTypeKindOption(_state); var isPublicOnlyAccessibility = IsPublicOnlyAccessibility(_state, _document.Project); return generateTypeOptionsService.GetGenerateTypeOptions( diff --git a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs index 2712595590208..604a4f3d190f7 100644 --- a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs +++ b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs @@ -19,7 +19,6 @@ using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Microsoft.CodeAnalysis.Utilities; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.GenerateType; diff --git a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.State.cs b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.State.cs index 7c9bf2684747e..03a183873e775 100644 --- a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.State.cs +++ b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.State.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.FindSymbols; diff --git a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.cs b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.cs index 2fb0774c29d1f..13ecc170cc013 100644 --- a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.cs +++ b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.cs @@ -11,7 +11,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Internal.Log; @@ -19,7 +18,6 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; -using Microsoft.CodeAnalysis.Utilities; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.GenerateType; diff --git a/src/Features/Core/Portable/GenerateType/GenerateTypeDialogOptions.cs b/src/Features/Core/Portable/GenerateType/GenerateTypeDialogOptions.cs index 30de33e1b39b4..4ee19f68f6817 100644 --- a/src/Features/Core/Portable/GenerateType/GenerateTypeDialogOptions.cs +++ b/src/Features/Core/Portable/GenerateType/GenerateTypeDialogOptions.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.GenerateType; internal sealed class GenerateTypeDialogOptions( diff --git a/src/Features/Core/Portable/GenerateType/IGenerateTypeOptionService.cs b/src/Features/Core/Portable/GenerateType/IGenerateTypeOptionService.cs index 868e6c9c125c4..4c9325d563ecc 100644 --- a/src/Features/Core/Portable/GenerateType/IGenerateTypeOptionService.cs +++ b/src/Features/Core/Portable/GenerateType/IGenerateTypeOptionService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Notification; @@ -17,7 +15,7 @@ GenerateTypeOptionsResult GetGenerateTypeOptions( string className, GenerateTypeDialogOptions generateTypeDialogOptions, Document document, - INotificationService notificationService, - IProjectManagementService projectManagementService, + INotificationService? notificationService, + IProjectManagementService? projectManagementService, ISyntaxFactsService syntaxFactsService); } diff --git a/src/Features/Core/Portable/GenerateType/IGenerateTypeService.cs b/src/Features/Core/Portable/GenerateType/IGenerateTypeService.cs index 5ee998341958c..a9720dee79cbe 100644 --- a/src/Features/Core/Portable/GenerateType/IGenerateTypeService.cs +++ b/src/Features/Core/Portable/GenerateType/IGenerateTypeService.cs @@ -6,7 +6,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.GenerateType; diff --git a/src/Features/Core/Portable/GenerateType/TypeKindOptions.cs b/src/Features/Core/Portable/GenerateType/TypeKindOptions.cs index 68a6c52a4688a..283744f62ace9 100644 --- a/src/Features/Core/Portable/GenerateType/TypeKindOptions.cs +++ b/src/Features/Core/Portable/GenerateType/TypeKindOptions.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; namespace Microsoft.CodeAnalysis.GenerateType; diff --git a/src/Features/Core/Portable/GoToBase/FindBaseHelpers.cs b/src/Features/Core/Portable/GoToBase/FindBaseHelpers.cs index 7b8b75e598fa3..9b3b673588057 100644 --- a/src/Features/Core/Portable/GoToBase/FindBaseHelpers.cs +++ b/src/Features/Core/Portable/GoToBase/FindBaseHelpers.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Threading; using Microsoft.CodeAnalysis.FindSymbols.FindReferences; diff --git a/src/Features/Core/Portable/GoToDefinition/GoToDefinitionFeatureHelpers.cs b/src/Features/Core/Portable/GoToDefinition/GoToDefinitionFeatureHelpers.cs index fc6f6674cc9ab..cd1f8c77540e6 100644 --- a/src/Features/Core/Portable/GoToDefinition/GoToDefinitionFeatureHelpers.cs +++ b/src/Features/Core/Portable/GoToDefinition/GoToDefinitionFeatureHelpers.cs @@ -18,6 +18,9 @@ internal static class GoToDefinitionFeatureHelpers public static ISymbol? TryGetPreferredSymbol( Solution solution, ISymbol? symbol, CancellationToken cancellationToken) { + if (symbol is null) + return null; + // VB global import aliases have a synthesized SyntaxTree. // We can't go to the definition of the alias, so use the target type. @@ -46,8 +49,13 @@ internal static class GoToDefinitionFeatureHelpers symbol = definition ?? symbol; // If symbol has a partial implementation part, prefer to go to it, since that is where the body is. - symbol = (symbol as IMethodSymbol)?.PartialImplementationPart ?? symbol; - symbol = (symbol as IPropertySymbol)?.PartialImplementationPart ?? symbol; + symbol = symbol switch + { + IMethodSymbol method => method.PartialImplementationPart, + IPropertySymbol property => property.PartialImplementationPart, + IEventSymbol ev => ev.PartialImplementationPart, + _ => symbol, + } ?? symbol; return symbol; } diff --git a/src/Features/Core/Portable/Highlighting/ExportHighlighterAttribute.cs b/src/Features/Core/Portable/Highlighting/ExportHighlighterAttribute.cs index 783b812d13c90..b86a3654a325a 100644 --- a/src/Features/Core/Portable/Highlighting/ExportHighlighterAttribute.cs +++ b/src/Features/Core/Portable/Highlighting/ExportHighlighterAttribute.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.Composition; using System.Diagnostics.CodeAnalysis; diff --git a/src/Features/Core/Portable/Highlighting/HighlightingService.cs b/src/Features/Core/Portable/Highlighting/HighlightingService.cs index 2f35c389ba6a5..c453490a5ed05 100644 --- a/src/Features/Core/Portable/Highlighting/HighlightingService.cs +++ b/src/Features/Core/Portable/Highlighting/HighlightingService.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.Composition; diff --git a/src/Features/Core/Portable/Highlighting/IHighlighter.cs b/src/Features/Core/Portable/Highlighting/IHighlighter.cs index d71022d82d6fc..d74cb3cacd135 100644 --- a/src/Features/Core/Portable/Highlighting/IHighlighter.cs +++ b/src/Features/Core/Portable/Highlighting/IHighlighter.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.Threading; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/Core/Portable/Highlighting/IHighlightingService.cs b/src/Features/Core/Portable/Highlighting/IHighlightingService.cs index 334cbe3935bba..454c0918e5137 100644 --- a/src/Features/Core/Portable/Highlighting/IHighlightingService.cs +++ b/src/Features/Core/Portable/Highlighting/IHighlightingService.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.Threading; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/Core/Portable/InitializeParameter/AbstractAddParameterCheckCodeRefactoringProvider.cs b/src/Features/Core/Portable/InitializeParameter/AbstractAddParameterCheckCodeRefactoringProvider.cs index 627d67cd72741..d0fa8ba6bfb07 100644 --- a/src/Features/Core/Portable/InitializeParameter/AbstractAddParameterCheckCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/InitializeParameter/AbstractAddParameterCheckCodeRefactoringProvider.cs @@ -10,7 +10,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Operations; @@ -19,7 +18,6 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.InitializeParameter; @@ -43,6 +41,17 @@ internal abstract class AbstractAddParameterCheckCodeRefactoringProvider< where TBinaryExpressionSyntax : TExpressionSyntax where TSimplifierOptions : SimplifierOptions { + private const string s_isPrefix = "Is"; + private const string s_throwIfPrefix = "ThrowIf"; + + private const string s_nullSuffix = "Null"; + private const string s_nullOrEmptySuffix = "NullOrEmpty"; + private const string s_nullOrWhiteSpaceSuffix = "NullOrWhiteSpace"; + + private const string s_throwIfNullName = s_throwIfPrefix + s_nullSuffix; + private const string s_throwIfNullOrEmptyName = s_throwIfPrefix + s_nullOrEmptySuffix; + private const string s_throwIfNullOrWhiteSpaceName = s_throwIfPrefix + s_nullOrWhiteSpaceSuffix; + protected abstract bool CanOffer(SyntaxNode body); protected abstract bool PrefersThrowExpression(TSimplifierOptions options); protected abstract string EscapeResourceString(string input); @@ -109,12 +118,12 @@ protected override async Task> GetRefactoringsForSing { result.Add(CodeAction.Create( FeaturesResources.Add_string_IsNullOrEmpty_check, - cancellationToken => AddStringCheckAsync(document, parameter, functionDeclaration, methodSymbol, blockStatementOpt, nameof(string.IsNullOrEmpty), simplifierOptions, cancellationToken), + cancellationToken => AddStringCheckAsync(document, parameter, functionDeclaration, methodSymbol, blockStatementOpt, s_nullOrEmptySuffix, simplifierOptions, cancellationToken), nameof(FeaturesResources.Add_string_IsNullOrEmpty_check))); result.Add(CodeAction.Create( FeaturesResources.Add_string_IsNullOrWhiteSpace_check, - cancellationToken => AddStringCheckAsync(document, parameter, functionDeclaration, methodSymbol, blockStatementOpt, nameof(string.IsNullOrWhiteSpace), simplifierOptions, cancellationToken), + cancellationToken => AddStringCheckAsync(document, parameter, functionDeclaration, methodSymbol, blockStatementOpt, s_nullOrWhiteSpaceSuffix, simplifierOptions, cancellationToken), nameof(FeaturesResources.Add_string_IsNullOrWhiteSpace_check))); } @@ -159,7 +168,7 @@ private async Task UpdateDocumentForRefactoringAsync( // commonly used in this regard according to telemetry and UX testing. if (parameter.Type.SpecialType == SpecialType.System_String) { - document = await AddStringCheckAsync(document, parameter, functionDeclaration, (IMethodSymbol)parameter.ContainingSymbol, blockStatementOpt, nameof(string.IsNullOrEmpty), lazySimplifierOptions, cancellationToken).ConfigureAwait(false); + document = await AddStringCheckAsync(document, parameter, functionDeclaration, (IMethodSymbol)parameter.ContainingSymbol, blockStatementOpt, s_nullOrEmptySuffix, lazySimplifierOptions, cancellationToken).ConfigureAwait(false); continue; } @@ -279,6 +288,9 @@ protected bool ParameterValidForNullCheck(Document document, IParameterSymbol pa if (IsIfNullCheck(statement, parameter)) return false; + if (IsAnyThrowIfNullInvocation(statement, parameter)) + return false; + if (ContainsNullCoalesceCheck( syntaxFacts, semanticModel, statement, parameter, cancellationToken)) @@ -291,11 +303,32 @@ protected bool ParameterValidForNullCheck(Document document, IParameterSymbol pa return true; } + private static bool IsAnyThrowIfNullInvocation(IOperation statement, IParameterSymbol? parameter) + { + if (statement is IExpressionStatementOperation + { + Operation: IInvocationOperation + { + TargetMethod: + { + ContainingType.Name: nameof(ArgumentNullException) or nameof(ArgumentException), + Name: s_throwIfNullName or s_throwIfNullOrEmptyName or s_throwIfNullOrWhiteSpaceName, + }, + Arguments: [{ Value: var argumentValue }, ..] + } + }) + { + if (argumentValue.UnwrapImplicitConversion() is IParameterReferenceOperation parameterReference) + return parameter is null || parameter.Equals(parameterReference.Parameter); + } + + return false; + } + private static bool IsStringCheck(IOperation condition, IParameterSymbol parameter) { - if (condition is IInvocationOperation invocation && - invocation.Arguments.Length == 1 && - IsParameterReference(invocation.Arguments[0].Value, parameter)) + if (condition is IInvocationOperation { Arguments: [{ Value: var argumentValue }] } invocation && + IsParameterReference(argumentValue, parameter)) { var targetMethod = invocation.TargetMethod; if (targetMethod?.Name is nameof(string.IsNullOrEmpty) or nameof(string.IsNullOrWhiteSpace)) @@ -337,13 +370,13 @@ private async Task AddStringCheckAsync( SyntaxNode functionDeclaration, IMethodSymbol method, IBlockOperation? blockStatementOpt, - string methodName, + string methodNameSuffix, TSimplifierOptions options, CancellationToken cancellationToken) { return await AddNullCheckStatementAsync( document, parameter, functionDeclaration, method, blockStatementOpt, - (s, g) => CreateStringCheckStatement(s.Compilation, g, parameter, methodName, options), + (s, g) => CreateStringCheckStatement(s.Compilation, g, parameter, methodNameSuffix, options), cancellationToken).ConfigureAwait(false); } @@ -383,23 +416,62 @@ private static async Task AddNullCheckStatementAsync( } private TStatementSyntax CreateNullCheckStatement(SemanticModel semanticModel, SyntaxGenerator generator, IParameterSymbol parameter, TSimplifierOptions options) - => CreateParameterCheckIfStatement( + { + var argumentNullExceptionType = semanticModel.Compilation.ArgumentNullExceptionType(); + if (parameter.Type.IsReferenceType && argumentNullExceptionType != null) + { + var throwIfNullMethod = argumentNullExceptionType + .GetMembers(s_throwIfNullName) + .OfType() + .FirstOrDefault(m => m.Parameters is [{ Type.SpecialType: SpecialType.System_Object }, ..]); + if (throwIfNullMethod != null) + { + return (TStatementSyntax)generator.ExpressionStatement(generator.InvocationExpression( + generator.MemberAccessExpression( + generator.TypeExpression(argumentNullExceptionType), + s_throwIfNullName), + generator.IdentifierName(parameter.Name))); + } + } + + return CreateParameterCheckIfStatement( (TExpressionSyntax)generator.CreateNullCheckExpression(generator.SyntaxGeneratorInternal, semanticModel, parameter.Name), (TStatementSyntax)generator.CreateThrowArgumentNullExceptionStatement(semanticModel.Compilation, parameter), options); + } private TStatementSyntax CreateStringCheckStatement( - Compilation compilation, SyntaxGenerator generator, IParameterSymbol parameter, string methodName, TSimplifierOptions options) + Compilation compilation, SyntaxGenerator generator, IParameterSymbol parameter, string methodNameSuffix, TSimplifierOptions options) { + var argumentExceptionType = compilation.ArgumentExceptionType(); + if (argumentExceptionType != null) + { + var throwMethodName = "ThrowIf" + methodNameSuffix; + var throwIfNullMethod = argumentExceptionType + .GetMembers(throwMethodName) + .OfType() + .FirstOrDefault(m => m.Parameters is [{ Type.SpecialType: SpecialType.System_String }, ..]); + if (throwIfNullMethod != null) + { + return (TStatementSyntax)generator.ExpressionStatement(generator.InvocationExpression( + generator.MemberAccessExpression( + generator.TypeExpression(argumentExceptionType), + throwMethodName), + generator.IdentifierName(parameter.Name))); + } + } + var stringType = compilation.GetSpecialType(SpecialType.System_String); // generates: if (string.IsXXX(s)) throw new ArgumentException("message", nameof(s)) + var isMethodName = s_isPrefix + methodNameSuffix; var condition = (TExpressionSyntax)generator.InvocationExpression( - generator.MemberAccessExpression( - generator.TypeExpression(stringType), - generator.IdentifierName(methodName)), - generator.Argument(generator.IdentifierName(parameter.Name))); - var throwStatement = (TStatementSyntax)generator.ThrowStatement(CreateArgumentException(compilation, generator, parameter, methodName)); + generator.MemberAccessExpression( + generator.TypeExpression(stringType), + generator.IdentifierName(isMethodName)), + generator.Argument(generator.IdentifierName(parameter.Name))); + var throwStatement = (TStatementSyntax)generator.ThrowStatement( + CreateArgumentException(compilation, generator, parameter, isMethodName)); return CreateParameterCheckIfStatement(condition, throwStatement, options); } @@ -465,6 +537,14 @@ private TStatementSyntax CreateStringCheckStatement( if (statement.IsImplicit) continue; + if (IsAnyThrowIfNullInvocation(statement, parameter: null)) + { + if (IsAnyThrowIfNullInvocation(statement, parameterSymbol)) + return statement; + + continue; + } + if (statement is IConditionalOperation ifStatement) { if (ContainsParameterReference(semanticModel, ifStatement.Condition, parameterSymbol, cancellationToken)) @@ -473,7 +553,7 @@ private TStatementSyntax CreateStringCheckStatement( continue; } - // Stop hunting after we hit something that isn't an if-statement + // Stop hunting after we hit something that isn't an if-statement or a ThrowIfNull invocation. break; } } diff --git a/src/Features/Core/Portable/InlineHints/AbstractInlineParameterNameHintsService.cs b/src/Features/Core/Portable/InlineHints/AbstractInlineParameterNameHintsService.cs index 77c6e2b33b298..a8624dcfdc22b 100644 --- a/src/Features/Core/Portable/InlineHints/AbstractInlineParameterNameHintsService.cs +++ b/src/Features/Core/Portable/InlineHints/AbstractInlineParameterNameHintsService.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; @@ -11,7 +10,6 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.InlineHints; diff --git a/src/Features/Core/Portable/InlineHints/AbstractInlineTypeHintsService.cs b/src/Features/Core/Portable/InlineHints/AbstractInlineTypeHintsService.cs index b077a2f293c12..e7f24a25ae4a4 100644 --- a/src/Features/Core/Portable/InlineHints/AbstractInlineTypeHintsService.cs +++ b/src/Features/Core/Portable/InlineHints/AbstractInlineTypeHintsService.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Collections.Immutable; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.LanguageService; diff --git a/src/Features/Core/Portable/IntroduceParameter/AbstractIntroduceParameterCodeRefactoringProvider.cs b/src/Features/Core/Portable/IntroduceParameter/AbstractIntroduceParameterCodeRefactoringProvider.cs index d2c0584ca6e04..4a44639ecacef 100644 --- a/src/Features/Core/Portable/IntroduceParameter/AbstractIntroduceParameterCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/IntroduceParameter/AbstractIntroduceParameterCodeRefactoringProvider.cs @@ -9,7 +9,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.FindSymbols; diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceLocalForExpressionCodeRefactoringProvider.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceLocalForExpressionCodeRefactoringProvider.cs index 7805add83558e..eb2d21aa6251d 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceLocalForExpressionCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceLocalForExpressionCodeRefactoringProvider.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.IntroduceVariable; diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Attribute.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Attribute.cs index 98a8f9c2efd9f..f43833a972a0c 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Attribute.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Attribute.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.IntroduceVariable; internal abstract partial class AbstractIntroduceVariableService diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Block.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Block.cs index 1ce33eceba825..878de27cc3640 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Block.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Block.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Linq; using System.Threading; using Microsoft.CodeAnalysis; diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_ConstructorInitializer.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_ConstructorInitializer.cs index d42bc25f47d16..bb9d8cc65d4e3 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_ConstructorInitializer.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_ConstructorInitializer.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Linq; using System.Threading; using Microsoft.CodeAnalysis; diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Field.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Field.cs index 602cadea361dc..b9dfe663da057 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Field.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Field.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Linq; using System.Threading; using Microsoft.CodeAnalysis; diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Parameter.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Parameter.cs index 281e88446b152..ef98fa21910bf 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Parameter.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Parameter.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Linq; using System.Threading; using Microsoft.CodeAnalysis; diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Query.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Query.cs index da5378e493828..4a276a44a3df2 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Query.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Query.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Linq; using System.Threading; using Microsoft.CodeAnalysis; diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.cs index 90a727ecad74c..e109d42cf8e86 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.cs @@ -13,8 +13,6 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Operations; diff --git a/src/Features/Core/Portable/IntroduceVariable/IIntroduceVariableService.cs b/src/Features/Core/Portable/IntroduceVariable/IIntroduceVariableService.cs index 9a6554d449a40..36e653bccb636 100644 --- a/src/Features/Core/Portable/IntroduceVariable/IIntroduceVariableService.cs +++ b/src/Features/Core/Portable/IntroduceVariable/IIntroduceVariableService.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.CodeActions; diff --git a/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/ISymbolDisplayService.cs b/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/ISymbolDisplayService.cs index 44eea00d4f175..977b8a461507f 100644 --- a/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/ISymbolDisplayService.cs +++ b/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/ISymbolDisplayService.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; diff --git a/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/SymbolDescriptionGroups.cs b/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/SymbolDescriptionGroups.cs index ef15c0ef3fb44..c00e3548a2b4b 100644 --- a/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/SymbolDescriptionGroups.cs +++ b/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/SymbolDescriptionGroups.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; namespace Microsoft.CodeAnalysis.LanguageService; diff --git a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.AbstractWrappedNamespaceOrTypeSymbol.cs b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.AbstractWrappedNamespaceOrTypeSymbol.cs index e45cdc2916e9a..b245b5fc50205 100644 --- a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.AbstractWrappedNamespaceOrTypeSymbol.cs +++ b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.AbstractWrappedNamespaceOrTypeSymbol.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using Microsoft.CodeAnalysis.DocumentationComments; diff --git a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedEventSymbol.cs b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedEventSymbol.cs index ddb01cd12a000..28ea01f224172 100644 --- a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedEventSymbol.cs +++ b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedEventSymbol.cs @@ -32,5 +32,8 @@ public ImmutableArray ExplicitInterfaceImplementations public IMethodSymbol? RemoveMethod => _symbol.RemoveMethod; public ITypeSymbol Type => _symbol.Type; public NullableAnnotation NullableAnnotation => _symbol.NullableAnnotation; + public IEventSymbol? PartialDefinitionPart => _symbol.PartialDefinitionPart; + public IEventSymbol? PartialImplementationPart => _symbol.PartialImplementationPart; + public bool IsPartialDefinition => _symbol.IsPartialDefinition; } } diff --git a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedNamedTypeSymbol.cs b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedNamedTypeSymbol.cs index 336e01d4dfa18..716d3f4136238 100644 --- a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedNamedTypeSymbol.cs +++ b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedNamedTypeSymbol.cs @@ -9,7 +9,6 @@ using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis.DocumentationComments; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.MetadataAsSource; @@ -144,6 +143,10 @@ public ImmutableArray ToMinimalDisplayParts(SemanticModel sem public bool IsNativeIntegerType => _symbol.IsNativeIntegerType; + public bool IsExtension => _symbol.IsExtension; + + public IParameterSymbol ExtensionParameter => _symbol.ExtensionParameter; + public bool IsFileLocal => _symbol.IsFileLocal; public INamedTypeSymbol NativeIntegerUnderlyingType => _symbol.NativeIntegerUnderlyingType; diff --git a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.cs b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.cs index 3a03e5aebe762..e62bd83955cff 100644 --- a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.cs +++ b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; @@ -14,7 +13,6 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.MetadataAsSource; diff --git a/src/Features/Core/Portable/MetadataAsSource/DocumentationCommentUtilities.cs b/src/Features/Core/Portable/MetadataAsSource/DocumentationCommentUtilities.cs index 8615e35053ce9..66201cd2313ec 100644 --- a/src/Features/Core/Portable/MetadataAsSource/DocumentationCommentUtilities.cs +++ b/src/Features/Core/Portable/MetadataAsSource/DocumentationCommentUtilities.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.IO; diff --git a/src/Features/Core/Portable/MetadataAsSource/IMetadataAsSourceFileProvider.cs b/src/Features/Core/Portable/MetadataAsSource/IMetadataAsSourceFileProvider.cs index c06d750ebcc7b..693b09389f449 100644 --- a/src/Features/Core/Portable/MetadataAsSource/IMetadataAsSourceFileProvider.cs +++ b/src/Features/Core/Portable/MetadataAsSource/IMetadataAsSourceFileProvider.cs @@ -5,7 +5,6 @@ using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Structure; using Microsoft.CodeAnalysis.SymbolMapping; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/Core/Portable/MetadataAsSource/IMetadataAsSourceFileService.cs b/src/Features/Core/Portable/MetadataAsSource/IMetadataAsSourceFileService.cs index bf42a4c73fc68..db51360a23f40 100644 --- a/src/Features/Core/Portable/MetadataAsSource/IMetadataAsSourceFileService.cs +++ b/src/Features/Core/Portable/MetadataAsSource/IMetadataAsSourceFileService.cs @@ -5,7 +5,6 @@ using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.MetadataAsSource; diff --git a/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceFile.cs b/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceFile.cs index f8f9b6a167482..05c86a4005c33 100644 --- a/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceFile.cs +++ b/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceFile.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.MetadataAsSource; internal sealed class MetadataAsSourceFile diff --git a/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceHelpers.cs b/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceHelpers.cs index 3baf7b5df636e..f591c01b808d8 100644 --- a/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceHelpers.cs +++ b/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceHelpers.cs @@ -7,7 +7,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.MetadataAsSource; diff --git a/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj b/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj index c3729dd724429..237de95690587 100644 --- a/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj +++ b/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj @@ -48,6 +48,7 @@ + @@ -96,6 +97,7 @@ + diff --git a/src/Features/Core/Portable/MoveDeclarationNearReference/AbstractMoveDeclarationNearReferenceCodeRefactoringProvider.cs b/src/Features/Core/Portable/MoveDeclarationNearReference/AbstractMoveDeclarationNearReferenceCodeRefactoringProvider.cs index 78e6882f40b32..852a0581718f6 100644 --- a/src/Features/Core/Portable/MoveDeclarationNearReference/AbstractMoveDeclarationNearReferenceCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/MoveDeclarationNearReference/AbstractMoveDeclarationNearReferenceCodeRefactoringProvider.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.Composition; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; diff --git a/src/Features/Core/Portable/MoveStaticMembers/MoveStaticMembersWithDialogCodeAction.cs b/src/Features/Core/Portable/MoveStaticMembers/MoveStaticMembersWithDialogCodeAction.cs index d5bd227589e2a..941fe57932d2d 100644 --- a/src/Features/Core/Portable/MoveStaticMembers/MoveStaticMembersWithDialogCodeAction.cs +++ b/src/Features/Core/Portable/MoveStaticMembers/MoveStaticMembersWithDialogCodeAction.cs @@ -127,7 +127,7 @@ protected override async Task> ComputeOperation var members = memberNodes .Select(node => root.GetCurrentNode(node)) .WhereNotNull() - .SelectAsArray(node => (semanticModel.GetDeclaredSymbol(node, cancellationToken), false)); + .SelectAsArray(node => (semanticModel.GetRequiredDeclaredSymbol(node, cancellationToken), false)); var pullMembersUpOptions = PullMembersUpOptionsBuilder.BuildPullMembersUpOptions(newType, members); var movedSolution = await MembersPuller.PullMembersUpAsync(sourceDoc, pullMembersUpOptions, cancellationToken).ConfigureAwait(false); @@ -202,7 +202,7 @@ private static async Task RefactorAndMoveAsync( var members = oldMemberNodes .Select(node => root.GetCurrentNode(node)) .WhereNotNull() - .SelectAsArray(node => (semanticModel.GetDeclaredSymbol(node, cancellationToken), false)); + .SelectAsArray(node => (semanticModel.GetRequiredDeclaredSymbol(node, cancellationToken), false)); newTypeDoc = solutionWithFixedReferences.GetRequiredDocument(newTypeDoc.Id); newTypeRoot = await newTypeDoc.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceService.cs b/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceService.cs index a9dd06c4ec693..fdffff0191d32 100644 --- a/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceService.cs +++ b/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -40,6 +38,7 @@ internal abstract class AbstractMoveToNamespaceService AnalyzeTypeAtPositionAsync( int position, CancellationToken cancellationToken) { - var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var token = root.FindToken(position); var node = token.Parent; + if (node is null) + { + return MoveToNamespaceAnalysisResult.Invalid; + } var moveToNamespaceAnalysisResult = await TryAnalyzeNamespaceAsync(document, node, position, cancellationToken).ConfigureAwait(false); @@ -81,8 +84,7 @@ public async Task AnalyzeTypeAtPositionAsync( moveToNamespaceAnalysisResult = await TryAnalyzeNamedTypeAsync(document, node, cancellationToken).ConfigureAwait(false); return moveToNamespaceAnalysisResult ?? MoveToNamespaceAnalysisResult.Invalid; } - - private async Task TryAnalyzeNamespaceAsync( + private async Task TryAnalyzeNamespaceAsync( Document document, SyntaxNode node, int position, CancellationToken cancellationToken) { var declarationSyntax = node.FirstAncestorOrSelf(); @@ -94,7 +96,7 @@ private async Task TryAnalyzeNamespaceAsync( // The underlying ChangeNamespace service doesn't support nested namespace declaration. if (GetNamespaceInSpineCount(declarationSyntax) == 1) { - var changeNamespaceService = document.GetLanguageService(); + var changeNamespaceService = document.GetRequiredLanguageService(); if (await changeNamespaceService.CanChangeNamespaceAsync(document, declarationSyntax, cancellationToken).ConfigureAwait(false)) { var namespaceName = GetNamespaceName(declarationSyntax); @@ -118,14 +120,14 @@ private async Task TryAnalyzeNamedTypeAsync( return MoveToNamespaceAnalysisResult.Invalid; } - SyntaxNode container = null; + SyntaxNode? container = null; // Moving one of the many members declared in global namespace is not currently supported, // but if it's the only member declared, then that's fine. if (namespaceInSpineCount == 0) { - container = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var syntaxFacts = document.GetLanguageService(); + container = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var syntaxFacts = document.GetRequiredLanguageService(); if (syntaxFacts.GetMembersOfCompilationUnit(container).Count > 1) { @@ -133,23 +135,30 @@ private async Task TryAnalyzeNamedTypeAsync( } } - if (node is TNamedTypeDeclarationSyntax namedTypeDeclarationSyntax) + var namedTypeDeclarationSyntax = GetNamedTypeDeclarationSyntax(node); + if (namedTypeDeclarationSyntax is null) { - // If we are inside a namespace declaration, then find it as the container. - container ??= GetContainingNamespace(namedTypeDeclarationSyntax); - var changeNamespaceService = document.GetLanguageService(); + return MoveToNamespaceAnalysisResult.Invalid; + } - if (await changeNamespaceService.CanChangeNamespaceAsync(document, container, cancellationToken).ConfigureAwait(false)) - { - var namespaces = await GetNamespacesAsync(document, cancellationToken).ConfigureAwait(false); - return new MoveToNamespaceAnalysisResult(document, namedTypeDeclarationSyntax, GetNamespaceName(container), [.. namespaces], MoveToNamespaceAnalysisResult.ContainerType.NamedType); - } + // If we are inside a namespace declaration, then find it as the container. + container ??= GetContainingNamespace(namedTypeDeclarationSyntax); + if (container is null) + { + return MoveToNamespaceAnalysisResult.Invalid; + } + + var changeNamespaceService = document.GetRequiredLanguageService(); + if (await changeNamespaceService.CanChangeNamespaceAsync(document, container, cancellationToken).ConfigureAwait(false)) + { + var namespaces = await GetNamespacesAsync(document, cancellationToken).ConfigureAwait(false); + return new MoveToNamespaceAnalysisResult(document, namedTypeDeclarationSyntax, GetNamespaceName(container), [.. namespaces], MoveToNamespaceAnalysisResult.ContainerType.NamedType); } return MoveToNamespaceAnalysisResult.Invalid; } - private static TNamespaceDeclarationSyntax GetContainingNamespace(TNamedTypeDeclarationSyntax namedTypeSyntax) + private static TNamespaceDeclarationSyntax? GetContainingNamespace(TNamedTypeDeclarationSyntax namedTypeSyntax) => namedTypeSyntax.FirstAncestorOrSelf(); private static int GetNamespaceInSpineCount(SyntaxNode node) @@ -176,20 +185,26 @@ public Task MoveToNamespaceAsync( private static async Task> GetMemberSymbolsAsync(Document document, SyntaxNode container, CancellationToken cancellationToken) { - var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var syntaxFacts = document.GetLanguageService(); + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var syntaxFacts = document.GetRequiredLanguageService(); switch (container) { case TNamespaceDeclarationSyntax namespaceNode: var namespaceMembers = syntaxFacts.GetMembersOfBaseNamespaceDeclaration(namespaceNode); - return namespaceMembers.SelectAsArray(member => semanticModel.GetDeclaredSymbol(member, cancellationToken)); + return namespaceMembers + .Select(member => semanticModel.GetDeclaredSymbol(member, cancellationToken)) + .WhereNotNull() + .ToImmutableArray(); case TCompilationUnitSyntax compilationUnit: var compilationUnitMembers = syntaxFacts.GetMembersOfCompilationUnit(compilationUnit); // We are trying to move a selected type from global namespace to the target namespace. // This is supported if the selected type is the only member declared in the global namespace in this document. // (See `TryAnalyzeNamedTypeAsync`) Debug.Assert(compilationUnitMembers.Count == 1); - return compilationUnitMembers.SelectAsArray(member => semanticModel.GetDeclaredSymbol(member, cancellationToken)); + return compilationUnitMembers + .Select(member => semanticModel.GetDeclaredSymbol(member, cancellationToken)) + .WhereNotNull() + .ToImmutableArray(); default: throw ExceptionUtilities.UnexpectedValue(container); @@ -236,15 +251,15 @@ private static async Task MoveTypeToNamespaceAsync( moveSpan, MoveTypeOperationKind.MoveTypeNamespaceScope, cancellationToken).ConfigureAwait(false); - var modifiedDocument = modifiedSolution.GetDocument(document.Id); + var modifiedDocument = modifiedSolution.GetRequiredDocument(document.Id); // Since MoveTypeService doesn't handle linked files, we need to merge the diff ourselves, // otherwise, we will end up with multiple linked documents with different content. var formattingOptions = await document.GetSyntaxFormattingOptionsAsync(cancellationToken).ConfigureAwait(false); var mergedSolution = await PropagateChangeToLinkedDocumentsAsync(modifiedDocument, formattingOptions, cancellationToken).ConfigureAwait(false); - var mergedDocument = mergedSolution.GetDocument(document.Id); + var mergedDocument = mergedSolution.GetRequiredDocument(document.Id); - var syntaxRoot = await mergedDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var syntaxRoot = await mergedDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var syntaxNode = syntaxRoot.GetAnnotatedNodes(AbstractMoveTypeService.NamespaceScopeMovedAnnotation).SingleOrDefault(); // The type might be declared in global namespace @@ -289,7 +304,7 @@ protected static string GetQualifiedName(INamespaceSymbol namespaceSymbol) private static async Task> GetNamespacesAsync(Document document, CancellationToken cancellationToken) { - var compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); + var compilation = await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); return compilation.GlobalNamespace.GetAllNamespaces(cancellationToken) .Where(n => n.NamespaceKind == NamespaceKind.Module && n.ContainingAssembly == compilation.Assembly) @@ -301,7 +316,7 @@ public MoveToNamespaceOptionsResult GetChangeNamespaceOptions( string defaultNamespace, ImmutableArray namespaces) { - var syntaxFactsService = document.GetLanguageService(); + var syntaxFactsService = document.GetRequiredLanguageService(); return OptionsService.GetChangeNamespaceOptions( defaultNamespace, diff --git a/src/Features/Core/Portable/MoveToNamespace/IMoveToNamespaceOptionsService.cs b/src/Features/Core/Portable/MoveToNamespace/IMoveToNamespaceOptionsService.cs index cbe2b012e8c8b..3b8ea32faf48e 100644 --- a/src/Features/Core/Portable/MoveToNamespace/IMoveToNamespaceOptionsService.cs +++ b/src/Features/Core/Portable/MoveToNamespace/IMoveToNamespaceOptionsService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.LanguageService; diff --git a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.CachedDocumentSearch.cs b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.CachedDocumentSearch.cs index f43c6f2ca15b6..9113e819be5c8 100644 --- a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.CachedDocumentSearch.cs +++ b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.CachedDocumentSearch.cs @@ -16,6 +16,7 @@ using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Storage; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.NavigateTo; diff --git a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.GeneratedDocumentSearch.cs b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.GeneratedDocumentSearch.cs index 90e55bc5a6137..dfbf67bc3e488 100644 --- a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.GeneratedDocumentSearch.cs +++ b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.GeneratedDocumentSearch.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.PatternMatching; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Shared.Utilities; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.NavigateTo; diff --git a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.NormalSearch.cs b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.NormalSearch.cs index 0cdad427b8d35..430cdf81db059 100644 --- a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.NormalSearch.cs +++ b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.NormalSearch.cs @@ -8,9 +8,15 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PatternMatching; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Remote; +using Microsoft.CodeAnalysis.Shared; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; +using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.NavigateTo; @@ -35,16 +41,16 @@ public async Task SearchDocumentAsync( await client.TryInvokeAsync( document.Project, (service, solutionInfo, callbackId, cancellationToken) => - service.SearchDocumentAsync(solutionInfo, document.Id, searchPattern, [.. kinds], callbackId, cancellationToken), + service.SearchDocumentAndRelatedDocumentsAsync(solutionInfo, document.Id, searchPattern, [.. kinds], callbackId, cancellationToken), callback, cancellationToken).ConfigureAwait(false); return; } - await SearchDocumentInCurrentProcessAsync(document, searchPattern, kinds, onItemsFound, cancellationToken).ConfigureAwait(false); + await SearchDocumentAndRelatedDocumentsInCurrentProcessAsync(document, searchPattern, kinds, onItemsFound, cancellationToken).ConfigureAwait(false); } - public static async Task SearchDocumentInCurrentProcessAsync( + public static async Task SearchDocumentAndRelatedDocumentsInCurrentProcessAsync( Document document, string searchPattern, IImmutableSet kinds, @@ -54,12 +60,85 @@ public static async Task SearchDocumentInCurrentProcessAsync( var (patternName, patternContainerOpt) = PatternMatcher.GetNameAndContainer(searchPattern); var declaredSymbolInfoKindsSet = new DeclaredSymbolInfoKindSet(kinds); - var results = new ConcurrentSet(); - await SearchSingleDocumentAsync( - document, patternName, patternContainerOpt, declaredSymbolInfoKindsSet, t => results.Add(t), cancellationToken).ConfigureAwait(false); + // In parallel, search both the document requested, and any relevant 'related documents' we find for it. For the + // original document, search the entirety of it (by passing 'null' in for the 'spans' argument). For related + // documents, only search the spans of the partial-types/inheriting-types that we find for the types in this + // starting document. + await Task.WhenAll( + SearchDocumentsInCurrentProcessAsync([(document, spans: null)]), + SearchRelatedDocumentsInCurrentProcessAsync()).ConfigureAwait(false); + + Task SearchDocumentsInCurrentProcessAsync(ImmutableArray<(Document document, NormalizedTextSpanCollection? spans)> documentAndSpans) + => ProducerConsumer.RunParallelAsync( + documentAndSpans, + produceItems: static async (documentAndSpan, onItemFound, args, cancellationToken) => + { + var (patternName, patternContainerOpt, declaredSymbolInfoKindsSet, onItemsFound) = args; + await SearchSingleDocumentAsync( + documentAndSpan.document, patternName, patternContainerOpt, declaredSymbolInfoKindsSet, + item => + { + // Ensure that the results found while searching the single document intersect the desired + // subrange of the document we're searching in. For the primary document this will always + // succeed (since we're searching the full document). But for related documents this may fail + // if the results is not in the span of any of the types in those files we're searching. + if (documentAndSpan.spans is null || documentAndSpan.spans.IntersectsWith(item.DeclaredSymbolInfo.Span)) + onItemFound(item); + }, + cancellationToken).ConfigureAwait(false); + }, + consumeItems: static (values, args, cancellationToken) => args.onItemsFound(values, default, cancellationToken), + args: (patternName, patternContainerOpt, declaredSymbolInfoKindsSet, onItemsFound), + cancellationToken); + + async Task SearchRelatedDocumentsInCurrentProcessAsync() + { + var relatedDocuments = await GetRelatedDocumentsAsync().ConfigureAwait(false); + await SearchDocumentsInCurrentProcessAsync(relatedDocuments).ConfigureAwait(false); + } - if (results.Count > 0) - await onItemsFound([.. results], default, cancellationToken).ConfigureAwait(false); + async Task> GetRelatedDocumentsAsync() + { + // For C#/VB we define 'related documents' as those containing types in the inheritance chain of types in + // the originating file (as well as all partial parts of the original and inheritance types). This way a + // user can search for symbols scoped to the 'current document' and still get results for the members found + // in partial parts. + + var solution = document.Project.Solution; + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var semanticModel = await document.GetRequiredNullableDisabledSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var syntaxFacts = document.GetRequiredLanguageService(); + + using var _ = ArrayBuilder.GetInstance(out var topLevelNodes); + syntaxFacts.AddTopLevelMembers(root, topLevelNodes); + + // Keep track of all of the interesting spans in each document we find. Note: we will convert this to a + // NormalizedTextSpanCollection before returning it. That way the span of an outer partial type will + // encompass the span of an inner one and we won't get duplicates for the same symbol. + var documentToTextSpans = new MultiDictionary(); + + foreach (var topLevelMember in topLevelNodes) + { + if (semanticModel.GetDeclaredSymbol(topLevelMember, cancellationToken) is not INamedTypeSymbol namedTypeSymbol) + continue; + + foreach (var type in namedTypeSymbol.GetBaseTypesAndThis()) + { + foreach (var reference in type.DeclaringSyntaxReferences) + { + var relatedDocument = solution.GetDocument(reference.SyntaxTree); + if (relatedDocument is null) + continue; + + documentToTextSpans.Add(relatedDocument, reference.Span); + } + } + } + + // Ensure we don't search the original document we were already searching. + documentToTextSpans.Remove(document); + return documentToTextSpans.SelectAsArray(kvp => (kvp.Key, new NormalizedTextSpanCollection(kvp.Value)))!; + } } public async Task SearchProjectsAsync( diff --git a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.cs b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.cs index c25d5ffd8c675..30d264e854da2 100644 --- a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.cs +++ b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.NavigateTo; diff --git a/src/Features/Core/Portable/NavigateTo/INavigateToSearchResult.cs b/src/Features/Core/Portable/NavigateTo/INavigateToSearchResult.cs index ded2ae3bca7f4..543e7509c2f74 100644 --- a/src/Features/Core/Portable/NavigateTo/INavigateToSearchResult.cs +++ b/src/Features/Core/Portable/NavigateTo/INavigateToSearchResult.cs @@ -6,7 +6,6 @@ using Microsoft.CodeAnalysis.Navigation; using Microsoft.CodeAnalysis.PatternMatching; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.NavigateTo; diff --git a/src/Features/Core/Portable/NavigateTo/IRemoteNavigateToSearchService.cs b/src/Features/Core/Portable/NavigateTo/IRemoteNavigateToSearchService.cs index e50aa7fad8794..2b1d14b7578a3 100644 --- a/src/Features/Core/Portable/NavigateTo/IRemoteNavigateToSearchService.cs +++ b/src/Features/Core/Portable/NavigateTo/IRemoteNavigateToSearchService.cs @@ -11,13 +11,13 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Storage; -using Roslyn.Utilities; +using Microsoft.CodeAnalysis.Threading; namespace Microsoft.CodeAnalysis.NavigateTo; internal interface IRemoteNavigateToSearchService { - ValueTask SearchDocumentAsync(Checksum solutionChecksum, DocumentId documentId, string searchPattern, ImmutableArray kinds, RemoteServiceCallbackId callbackId, CancellationToken cancellationToken); + ValueTask SearchDocumentAndRelatedDocumentsAsync(Checksum solutionChecksum, DocumentId documentId, string searchPattern, ImmutableArray kinds, RemoteServiceCallbackId callbackId, CancellationToken cancellationToken); ValueTask SearchProjectsAsync(Checksum solutionChecksum, ImmutableArray projectIds, ImmutableArray priorityDocumentIds, string searchPattern, ImmutableArray kinds, RemoteServiceCallbackId callbackId, CancellationToken cancellationToken); ValueTask SearchGeneratedDocumentsAsync(Checksum solutionChecksum, ImmutableArray projectIds, string searchPattern, ImmutableArray kinds, RemoteServiceCallbackId callbackId, CancellationToken cancellationToken); diff --git a/src/Features/Core/Portable/NavigateTo/NavigateToItemKind.cs b/src/Features/Core/Portable/NavigateTo/NavigateToItemKind.cs index e48ea91550f3d..03e5b0805f5ca 100644 --- a/src/Features/Core/Portable/NavigateTo/NavigateToItemKind.cs +++ b/src/Features/Core/Portable/NavigateTo/NavigateToItemKind.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.NavigateTo; internal static class NavigateToItemKind diff --git a/src/Features/Core/Portable/Navigation/NavigableItemFactory.cs b/src/Features/Core/Portable/Navigation/NavigableItemFactory.cs index 7853327f30496..b4f4f5024132a 100644 --- a/src/Features/Core/Portable/Navigation/NavigableItemFactory.cs +++ b/src/Features/Core/Portable/Navigation/NavigableItemFactory.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.Linq; diff --git a/src/Features/Core/Portable/NavigationBar/IRemoteNavigationBarItemService.cs b/src/Features/Core/Portable/NavigationBar/IRemoteNavigationBarItemService.cs index 65e8247a559a1..341d4358e20cc 100644 --- a/src/Features/Core/Portable/NavigationBar/IRemoteNavigationBarItemService.cs +++ b/src/Features/Core/Portable/NavigationBar/IRemoteNavigationBarItemService.cs @@ -6,7 +6,6 @@ using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; -using Roslyn.Utilities; using static Microsoft.CodeAnalysis.NavigationBar.RoslynNavigationBarItem; namespace Microsoft.CodeAnalysis.NavigationBar; diff --git a/src/Features/Core/Portable/Notification/INotificationServiceCallback.cs b/src/Features/Core/Portable/Notification/INotificationServiceCallback.cs index 02b40654504cf..cdfa6cdf8372d 100644 --- a/src/Features/Core/Portable/Notification/INotificationServiceCallback.cs +++ b/src/Features/Core/Portable/Notification/INotificationServiceCallback.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; namespace Microsoft.CodeAnalysis.Notification; diff --git a/src/Features/Core/Portable/Organizing/AbstractOrganizingService.cs b/src/Features/Core/Portable/Organizing/AbstractOrganizingService.cs index 0bba5b78437f3..043536a0ead73 100644 --- a/src/Features/Core/Portable/Organizing/AbstractOrganizingService.cs +++ b/src/Features/Core/Portable/Organizing/AbstractOrganizingService.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; diff --git a/src/Features/Core/Portable/Organizing/IOrganizingService.cs b/src/Features/Core/Portable/Organizing/IOrganizingService.cs index 46730b8ec98af..f1b34c5f2f9ff 100644 --- a/src/Features/Core/Portable/Organizing/IOrganizingService.cs +++ b/src/Features/Core/Portable/Organizing/IOrganizingService.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.Threading; using System.Threading.Tasks; diff --git a/src/Features/Core/Portable/Organizing/Organizers/AbstractSyntaxNodeOrganizer.cs b/src/Features/Core/Portable/Organizing/Organizers/AbstractSyntaxNodeOrganizer.cs index 0e8055e5f809a..8062a09d6c8af 100644 --- a/src/Features/Core/Portable/Organizing/Organizers/AbstractSyntaxNodeOrganizer.cs +++ b/src/Features/Core/Portable/Organizing/Organizers/AbstractSyntaxNodeOrganizer.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.Threading; diff --git a/src/Features/Core/Portable/Organizing/Organizers/ExportSyntaxNodeOrganizerAttribute.cs b/src/Features/Core/Portable/Organizing/Organizers/ExportSyntaxNodeOrganizerAttribute.cs index 36bdec9c11e7a..66368dad3845c 100644 --- a/src/Features/Core/Portable/Organizing/Organizers/ExportSyntaxNodeOrganizerAttribute.cs +++ b/src/Features/Core/Portable/Organizing/Organizers/ExportSyntaxNodeOrganizerAttribute.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.Composition; diff --git a/src/Features/Core/Portable/Organizing/Organizers/ISyntaxOrganizer.cs b/src/Features/Core/Portable/Organizing/Organizers/ISyntaxOrganizer.cs index 006030c16864e..9f41c91f8c7b3 100644 --- a/src/Features/Core/Portable/Organizing/Organizers/ISyntaxOrganizer.cs +++ b/src/Features/Core/Portable/Organizing/Organizers/ISyntaxOrganizer.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.Threading; diff --git a/src/Features/Core/Portable/PasteTracking/IPasteTrackingService.cs b/src/Features/Core/Portable/PasteTracking/IPasteTrackingService.cs index feb10fc54315c..198a20131f3a1 100644 --- a/src/Features/Core/Portable/PasteTracking/IPasteTrackingService.cs +++ b/src/Features/Core/Portable/PasteTracking/IPasteTrackingService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.PasteTracking; diff --git a/src/Features/Core/Portable/PdbSourceDocument/PdbFileLocatorService.cs b/src/Features/Core/Portable/PdbSourceDocument/PdbFileLocatorService.cs index 69bbcdedc15c1..7362e8f6984fb 100644 --- a/src/Features/Core/Portable/PdbSourceDocument/PdbFileLocatorService.cs +++ b/src/Features/Core/Portable/PdbSourceDocument/PdbFileLocatorService.cs @@ -12,7 +12,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.MetadataAsSource; using Microsoft.CodeAnalysis.Shared.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.PdbSourceDocument; diff --git a/src/Features/Core/Portable/PdbSourceDocument/PdbSourceDocumentMetadataAsSourceFileProvider.cs b/src/Features/Core/Portable/PdbSourceDocument/PdbSourceDocumentMetadataAsSourceFileProvider.cs index 5c47785d67d55..cfab78d978320 100644 --- a/src/Features/Core/Portable/PdbSourceDocument/PdbSourceDocumentMetadataAsSourceFileProvider.cs +++ b/src/Features/Core/Portable/PdbSourceDocument/PdbSourceDocumentMetadataAsSourceFileProvider.cs @@ -15,7 +15,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.ErrorReporting; -using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.MetadataAsSource; @@ -301,7 +300,7 @@ internal sealed class PdbSourceDocumentMetadataAsSourceFileProvider( sourceDescription); var documentTooltip = navigateDocument.FilePath + Environment.NewLine + dllPath; - return new MetadataAsSourceFile(navigateDocument.FilePath, navigateLocation, documentName, documentTooltip); + return new MetadataAsSourceFile(navigateDocument.FilePath!, navigateLocation, documentName, documentTooltip); } private ProjectInfo? CreateProjectInfo(Workspace workspace, Project project, ImmutableDictionary pdbCompilationOptions, string assemblyName, string assemblyVersion, SourceHashAlgorithm checksumAlgorithm) diff --git a/src/Features/Core/Portable/PickMembers/IPickMembersService.cs b/src/Features/Core/Portable/PickMembers/IPickMembersService.cs index 94c2d1120ddab..e7d5953121838 100644 --- a/src/Features/Core/Portable/PickMembers/IPickMembersService.cs +++ b/src/Features/Core/Portable/PickMembers/IPickMembersService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using Microsoft.CodeAnalysis.Host; diff --git a/src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeConstants.cs b/src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeConstants.cs index a14686162bfc3..70f2775787906 100644 --- a/src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeConstants.cs +++ b/src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeConstants.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; namespace Microsoft.CodeAnalysis.PreferFrameworkType; @@ -11,6 +9,6 @@ namespace Microsoft.CodeAnalysis.PreferFrameworkType; internal static class PreferFrameworkTypeConstants { public const string PreferFrameworkType = nameof(PreferFrameworkType); - public static readonly ImmutableDictionary Properties = - ImmutableDictionary.Empty.Add(PreferFrameworkType, ""); + public static readonly ImmutableDictionary Properties = + ImmutableDictionary.Empty.Add(PreferFrameworkType, ""); } diff --git a/src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeDiagnosticAnalyzerBase.cs b/src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeDiagnosticAnalyzerBase.cs index 86c6904057290..4742177544d51 100644 --- a/src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeDiagnosticAnalyzerBase.cs +++ b/src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeDiagnosticAnalyzerBase.cs @@ -5,8 +5,6 @@ using System.Collections.Immutable; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Simplification; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.PreferFrameworkType; diff --git a/src/Features/Core/Portable/ProjectManagement/IProjectManagementService.cs b/src/Features/Core/Portable/ProjectManagement/IProjectManagementService.cs index f66e84d3aa0ef..02a405113328e 100644 --- a/src/Features/Core/Portable/ProjectManagement/IProjectManagementService.cs +++ b/src/Features/Core/Portable/ProjectManagement/IProjectManagementService.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 Microsoft.CodeAnalysis.Host; diff --git a/src/Features/Core/Portable/PullMemberUp/Dialog/IPullMemberUpOptionsService.cs b/src/Features/Core/Portable/PullMemberUp/Dialog/IPullMemberUpOptionsService.cs index 65589de33b85e..d4c8674478659 100644 --- a/src/Features/Core/Portable/PullMemberUp/Dialog/IPullMemberUpOptionsService.cs +++ b/src/Features/Core/Portable/PullMemberUp/Dialog/IPullMemberUpOptionsService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.PullMemberUp; diff --git a/src/Features/Core/Portable/PullMemberUp/Dialog/PullMemberUpWithDialogCodeAction.cs b/src/Features/Core/Portable/PullMemberUp/Dialog/PullMemberUpWithDialogCodeAction.cs index 74fb1bbecc84b..b0fd3c54d02b3 100644 --- a/src/Features/Core/Portable/PullMemberUp/Dialog/PullMemberUpWithDialogCodeAction.cs +++ b/src/Features/Core/Portable/PullMemberUp/Dialog/PullMemberUpWithDialogCodeAction.cs @@ -8,7 +8,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeRefactorings.PullMemberUp.Dialog; using Microsoft.CodeAnalysis.PullMemberUp; diff --git a/src/Features/Core/Portable/PullMemberUp/MemberAnalysisResult.cs b/src/Features/Core/Portable/PullMemberUp/MemberAnalysisResult.cs index 0a34dbd66a608..e55398c3f241d 100644 --- a/src/Features/Core/Portable/PullMemberUp/MemberAnalysisResult.cs +++ b/src/Features/Core/Portable/PullMemberUp/MemberAnalysisResult.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.PullMemberUp; internal readonly struct MemberAnalysisResult( diff --git a/src/Features/Core/Portable/PullMemberUp/PullMembersUpOptions.cs b/src/Features/Core/Portable/PullMemberUp/PullMembersUpOptions.cs index 78b372851381e..06921835c682f 100644 --- a/src/Features/Core/Portable/PullMemberUp/PullMembersUpOptions.cs +++ b/src/Features/Core/Portable/PullMemberUp/PullMembersUpOptions.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Linq; diff --git a/src/Features/Core/Portable/PullMemberUp/PullMembersUpOptionsBuilder.cs b/src/Features/Core/Portable/PullMemberUp/PullMembersUpOptionsBuilder.cs index d2f9b65dfc93b..da24f0ffbfbbf 100644 --- a/src/Features/Core/Portable/PullMemberUp/PullMembersUpOptionsBuilder.cs +++ b/src/Features/Core/Portable/PullMemberUp/PullMembersUpOptionsBuilder.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using Microsoft.CodeAnalysis.PullMemberUp; diff --git a/src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.TokenInfo.cs b/src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.TokenInfo.cs index 90c1d19f2da1c..d6cee9eddc130 100644 --- a/src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.TokenInfo.cs +++ b/src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.TokenInfo.cs @@ -10,7 +10,7 @@ internal abstract partial class CommonSemanticQuickInfoProvider { public readonly struct TokenInformation(ImmutableArray symbols, bool showAwaitReturn = false, NullableFlowState nullableFlowState = NullableFlowState.None) { - public readonly ImmutableArray Symbols = symbols; + public ImmutableArray Symbols => symbols.NullToEmpty(); /// /// True if this quick info came from hovering over an 'await' keyword, which we show the return diff --git a/src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.cs b/src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.cs index 2b3d5c9125e5c..7b981048d818c 100644 --- a/src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.cs +++ b/src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.cs @@ -195,21 +195,16 @@ private TokenInformation BindToken( var syntaxFacts = languageServices.GetRequiredService(); var enclosingType = semanticModel.GetEnclosingNamedType(token.SpanStart, cancellationToken); - var symbols = GetSymbolsFromToken(token, services, semanticModel, cancellationToken); - var bindableParent = syntaxFacts.TryGetBindableParent(token); - var overloads = bindableParent != null - ? semanticModel.GetMemberGroup(bindableParent, cancellationToken) - : []; - symbols = [.. symbols.Where(IsOk) - .Where(s => IsAccessible(s, enclosingType)) - .Concat(overloads) - .Distinct(SymbolEquivalenceComparer.Instance)]; + var symbolSet = new HashSet(SymbolEquivalenceComparer.Instance); + using var _ = ArrayBuilder.GetInstance(out var filteredSymbols); + + AddSymbols(GetSymbolsFromToken(token, services, semanticModel, cancellationToken), checkAccessibility: true); + AddSymbols(bindableParent != null ? semanticModel.GetMemberGroup(bindableParent, cancellationToken) : [], checkAccessibility: false); - if (symbols.Any()) + if (filteredSymbols is [var firstSymbol, ..]) { - var firstSymbol = symbols.First(); var isAwait = syntaxFacts.IsAwaitKeyword(token); var nullableFlowState = NullableFlowState.None; if (bindableParent != null) @@ -217,7 +212,7 @@ private TokenInformation BindToken( nullableFlowState = GetNullabilityAnalysis(semanticModel, firstSymbol, bindableParent, cancellationToken); } - return new TokenInformation(symbols, isAwait, nullableFlowState); + return new TokenInformation(filteredSymbols.ToImmutableAndClear(), isAwait, nullableFlowState); } // Couldn't bind the token to specific symbols. If it's an operator, see if we can at @@ -226,12 +221,25 @@ private TokenInformation BindToken( { var typeInfo = semanticModel.GetTypeInfo(token.Parent!, cancellationToken); if (IsOk(typeInfo.Type)) - { return new TokenInformation([typeInfo.Type]); - } } - return new TokenInformation([]); + return default; + + void AddSymbols(ImmutableArray symbols, bool checkAccessibility) + { + foreach (var symbol in symbols) + { + if (!IsOk(symbol)) + continue; + + if (checkAccessibility && !IsAccessible(symbol, enclosingType)) + continue; + + if (symbolSet.Add(symbol)) + filteredSymbols.Add(symbol); + } + } } private ImmutableArray GetSymbolsFromToken(SyntaxToken token, SolutionServices services, SemanticModel semanticModel, CancellationToken cancellationToken) diff --git a/src/Features/Core/Portable/QuickInfo/OnTheFlyDocsInfo.cs b/src/Features/Core/Portable/QuickInfo/OnTheFlyDocsInfo.cs index c1a69a7d374ff..2e46a28525140 100644 --- a/src/Features/Core/Portable/QuickInfo/OnTheFlyDocsInfo.cs +++ b/src/Features/Core/Portable/QuickInfo/OnTheFlyDocsInfo.cs @@ -13,12 +13,13 @@ namespace Microsoft.CodeAnalysis.QuickInfo; /// the symbol's declaration code /// the language of the symbol /// whether the symbol has comments -internal sealed class OnTheFlyDocsInfo(string symbolSignature, ImmutableArray declarationCode, string language, bool isContentExcluded, bool hasComments = false) +internal sealed class OnTheFlyDocsInfo(string symbolSignature, ImmutableArray declarationCode, string language, bool isContentExcluded, ImmutableArray additionalContext, bool hasComments = false) { public string SymbolSignature { get; } = symbolSignature; - public ImmutableArray DeclarationCode { get; } = declarationCode; + public ImmutableArray DeclarationCode { get; } = declarationCode; public string Language { get; } = language; public bool IsContentExcluded { get; set; } = isContentExcluded; + public ImmutableArray AdditionalContext { get; } = additionalContext; // Added for telemetry collection purposes. public bool HasComments { get; set; } = hasComments; diff --git a/src/Features/Core/Portable/QuickInfo/OnTheFlyDocsLogger.cs b/src/Features/Core/Portable/QuickInfo/OnTheFlyDocsLogger.cs index 36edcf66005c0..89afe7ae5dd56 100644 --- a/src/Features/Core/Portable/QuickInfo/OnTheFlyDocsLogger.cs +++ b/src/Features/Core/Portable/QuickInfo/OnTheFlyDocsLogger.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 Microsoft.CodeAnalysis.Internal.Log; namespace Microsoft.CodeAnalysis.QuickInfo; diff --git a/src/Features/Core/Portable/QuickInfo/OnTheFlyDocsRelevantFileInfo.cs b/src/Features/Core/Portable/QuickInfo/OnTheFlyDocsRelevantFileInfo.cs new file mode 100644 index 0000000000000..aa5390dac3e35 --- /dev/null +++ b/src/Features/Core/Portable/QuickInfo/OnTheFlyDocsRelevantFileInfo.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.QuickInfo; + +internal sealed record OnTheFlyDocsRelevantFileInfo +{ + public Document Document { get; } + public TextSpan TextSpan { get; } + + public OnTheFlyDocsRelevantFileInfo(Document document, TextSpan textSpan) + { + Document = document; + TextSpan = textSpan; + } +} + diff --git a/src/Features/Core/Portable/QuickInfo/Presentation/TaggedTextExtensions.cs b/src/Features/Core/Portable/QuickInfo/Presentation/TaggedTextExtensions.cs index d235efc36a702..1bea570041ff1 100644 --- a/src/Features/Core/Portable/QuickInfo/Presentation/TaggedTextExtensions.cs +++ b/src/Features/Core/Portable/QuickInfo/Presentation/TaggedTextExtensions.cs @@ -7,7 +7,6 @@ using System.Runtime.CompilerServices; using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.Shared.Collections; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.QuickInfo.Presentation; diff --git a/src/Features/Core/Portable/QuickInfo/QuickInfoUtilities.cs b/src/Features/Core/Portable/QuickInfo/QuickInfoUtilities.cs index 865997ee60408..fdb53dfa525e5 100644 --- a/src/Features/Core/Portable/QuickInfo/QuickInfoUtilities.cs +++ b/src/Features/Core/Portable/QuickInfo/QuickInfoUtilities.cs @@ -18,6 +18,11 @@ namespace Microsoft.CodeAnalysis.QuickInfo; internal static class QuickInfoUtilities { + /// + /// Display variable name only. + /// + private static readonly SymbolDisplayFormat s_nullableDisplayFormat = new SymbolDisplayFormat(); + public static Task CreateQuickInfoItemAsync(SolutionServices services, SemanticModel semanticModel, TextSpan span, ImmutableArray symbols, SymbolDescriptionOptions options, CancellationToken cancellationToken) => CreateQuickInfoItemAsync(services, semanticModel, span, symbols, supportedPlatforms: null, showAwaitReturn: false, flowState: NullableFlowState.None, options, onTheFlyDocsInfo: null, cancellationToken); @@ -136,8 +141,8 @@ public static async Task CreateQuickInfoItemAsync( var nullableMessage = flowState switch { - NullableFlowState.MaybeNull => string.Format(FeaturesResources._0_may_be_null_here, symbol.Name), - NullableFlowState.NotNull => string.Format(FeaturesResources._0_is_not_null_here, symbol.Name), + NullableFlowState.MaybeNull => string.Format(FeaturesResources._0_may_be_null_here, symbol.ToDisplayString(s_nullableDisplayFormat)), + NullableFlowState.NotNull => string.Format(FeaturesResources._0_is_not_null_here, symbol.ToDisplayString(s_nullableDisplayFormat)), _ => null }; diff --git a/src/Features/Core/Portable/ReplaceConditionalWithStatements/AbstractReplaceConditionalWithStatementsCodeRefactoringProvider.cs b/src/Features/Core/Portable/ReplaceConditionalWithStatements/AbstractReplaceConditionalWithStatementsCodeRefactoringProvider.cs index 4b9ef9e06ac79..70aec07bdb656 100644 --- a/src/Features/Core/Portable/ReplaceConditionalWithStatements/AbstractReplaceConditionalWithStatementsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ReplaceConditionalWithStatements/AbstractReplaceConditionalWithStatementsCodeRefactoringProvider.cs @@ -12,7 +12,6 @@ using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ReplaceConditionalWithStatements; diff --git a/src/Features/Core/Portable/ReplaceMethodWithProperty/AbstractReplaceMethodWithPropertyService.cs b/src/Features/Core/Portable/ReplaceMethodWithProperty/AbstractReplaceMethodWithPropertyService.cs index a7adaee6ab60c..ee3b5332292fc 100644 --- a/src/Features/Core/Portable/ReplaceMethodWithProperty/AbstractReplaceMethodWithPropertyService.cs +++ b/src/Features/Core/Portable/ReplaceMethodWithProperty/AbstractReplaceMethodWithPropertyService.cs @@ -28,7 +28,7 @@ internal abstract class AbstractReplaceMethodWithPropertyService ReplaceGetMethodsAndRemoveSetMethodsAsync( var setMethodDeclaration = await GetMethodDeclarationAsync(setMethod, cancellationToken).ConfigureAwait(false); var setMethodDocument = updatedSolution.GetDocument(setMethodDeclaration?.SyntaxTree); - if (setMethodDocument?.Id == documentId) + if (setMethodDocument?.Id == documentId && setMethodDeclaration != null) { service.RemoveSetMethod(editor, setMethodDeclaration); } diff --git a/src/Features/Core/Portable/ReplacePropertyWithMethods/AbstractReplacePropertyWithMethodsService.cs b/src/Features/Core/Portable/ReplacePropertyWithMethods/AbstractReplacePropertyWithMethodsService.cs index 5a18b1e68b7a1..b79956802af4a 100644 --- a/src/Features/Core/Portable/ReplacePropertyWithMethods/AbstractReplacePropertyWithMethodsService.cs +++ b/src/Features/Core/Portable/ReplacePropertyWithMethods/AbstractReplacePropertyWithMethodsService.cs @@ -4,10 +4,10 @@ using System; using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.LanguageService; @@ -27,7 +27,7 @@ internal abstract class AbstractReplacePropertyWithMethodsService> GetReplacementMembersAsync( - Document document, IPropertySymbol property, SyntaxNode propertyDeclaration, IFieldSymbol propertyBackingField, string desiredGetMethodName, string desiredSetMethodName, CancellationToken cancellationToken); + Document document, IPropertySymbol property, SyntaxNode propertyDeclaration, IFieldSymbol? propertyBackingField, string desiredGetMethodName, string desiredSetMethodName, CancellationToken cancellationToken); protected abstract TCrefSyntax? TryGetCrefSyntax(TIdentifierNameSyntax identifierName); protected abstract TCrefSyntax CreateCrefSyntax(TCrefSyntax originalCref, SyntaxToken identifierToken, SyntaxNode? parameterType); @@ -54,7 +54,7 @@ protected static SyntaxNode GetFieldReference(SyntaxGenerator generator, IFieldS public async Task ReplaceReferenceAsync( Document document, SyntaxEditor editor, SyntaxNode identifierName, - IPropertySymbol property, IFieldSymbol propertyBackingField, + IPropertySymbol property, IFieldSymbol? propertyBackingField, string desiredGetMethodName, string desiredSetMethodName, CancellationToken cancellationToken) { @@ -79,7 +79,7 @@ private readonly struct ReferenceReplacer private readonly ISemanticFactsService _semanticFacts; private readonly SyntaxEditor _editor; private readonly IPropertySymbol _property; - private readonly IFieldSymbol _propertyBackingField; + private readonly IFieldSymbol? _propertyBackingField; private readonly string _desiredGetMethodName; private readonly string _desiredSetMethodName; @@ -96,7 +96,7 @@ public ReferenceReplacer( SyntaxEditor editor, TIdentifierNameSyntax identifierName, IPropertySymbol property, - IFieldSymbol propertyBackingField, + IFieldSymbol? propertyBackingField, string desiredGetMethodName, string desiredSetMethodName, CancellationToken cancellationToken) @@ -316,12 +316,12 @@ private TCrefSyntax GetCrefReference(TCrefSyntax originalCref) return _service.CreateCrefSyntax(originalCref, newIdentifierToken, parameterType); } - private SyntaxNode QualifyIfAppropriate(SyntaxNode newIdentifierName) + private SyntaxNode QualifyIfAppropriate(IFieldSymbol propertyBackingField, SyntaxNode newIdentifierName) { // See if already qualified appropriate. if (_expression is TIdentifierNameSyntax) { - var container = _propertyBackingField.IsStatic + var container = propertyBackingField.IsStatic ? Generator.TypeExpression(_property.ContainingType) : Generator.ThisExpression(); @@ -338,7 +338,7 @@ private TExpressionSyntax GetReadExpression( if (ShouldReadFromBackingField()) { var newIdentifierToken = AddConflictAnnotation(Generator.Identifier(_propertyBackingField.Name), conflictMessage); - var newIdentifierName = QualifyIfAppropriate(Generator.IdentifierName(newIdentifierToken)); + var newIdentifierName = QualifyIfAppropriate(_propertyBackingField, Generator.IdentifierName(newIdentifierToken)); if (keepTrivia) { @@ -361,7 +361,7 @@ private SyntaxNode GetWriteExpression( if (ShouldWriteToBackingField()) { var newIdentifierToken = AddConflictAnnotation(Generator.Identifier(_propertyBackingField.Name), conflictMessage); - var newIdentifierName = QualifyIfAppropriate(Generator.IdentifierName(newIdentifierToken)); + var newIdentifierName = QualifyIfAppropriate(_propertyBackingField, Generator.IdentifierName(newIdentifierToken)); if (keepTrivia) { @@ -411,6 +411,7 @@ private TExpressionSyntax GetInvocationExpression( return (TExpressionSyntax)invocation; } + [MemberNotNullWhen(true, nameof(_propertyBackingField))] private bool ShouldReadFromBackingField() => _propertyBackingField != null && _property.GetMethod == null; @@ -423,6 +424,7 @@ private SyntaxNode GetSetInvocationExpression( conflictMessage: conflictMessage); } + [MemberNotNullWhen(true, nameof(_propertyBackingField))] private bool ShouldWriteToBackingField() => _propertyBackingField != null && _property.SetMethod == null; diff --git a/src/Features/Core/Portable/ReplacePropertyWithMethods/IReplacePropertyWithMethodsService.cs b/src/Features/Core/Portable/ReplacePropertyWithMethods/IReplacePropertyWithMethodsService.cs index 2c5511e7d5289..9e28e79a9d7c2 100644 --- a/src/Features/Core/Portable/ReplacePropertyWithMethods/IReplacePropertyWithMethodsService.cs +++ b/src/Features/Core/Portable/ReplacePropertyWithMethods/IReplacePropertyWithMethodsService.cs @@ -2,12 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Host; @@ -16,19 +13,19 @@ namespace Microsoft.CodeAnalysis.ReplacePropertyWithMethods; internal interface IReplacePropertyWithMethodsService : ILanguageService { - Task GetPropertyDeclarationAsync(CodeRefactoringContext context); + Task GetPropertyDeclarationAsync(CodeRefactoringContext context); Task ReplaceReferenceAsync( Document document, SyntaxEditor editor, SyntaxNode identifierName, - IPropertySymbol property, IFieldSymbol propertyBackingField, + IPropertySymbol property, IFieldSymbol? propertyBackingField, string desiredGetMethodName, string desiredSetMethodName, CancellationToken cancellationToken); Task> GetReplacementMembersAsync( Document document, IPropertySymbol property, SyntaxNode propertyDeclaration, - IFieldSymbol propertyBackingField, + IFieldSymbol? propertyBackingField, string desiredGetMethodName, string desiredSetMethodName, CancellationToken cancellationToken); diff --git a/src/Features/Core/Portable/SemanticSearch/AbstractSemanticSearchService.cs b/src/Features/Core/Portable/SemanticSearch/AbstractSemanticSearchService.cs index 81a53d7d5c53f..f462ab458ac68 100644 --- a/src/Features/Core/Portable/SemanticSearch/AbstractSemanticSearchService.cs +++ b/src/Features/Core/Portable/SemanticSearch/AbstractSemanticSearchService.cs @@ -12,6 +12,7 @@ using System.IO; using System.Linq; using System.Reflection; +using System.Runtime.CompilerServices; using System.Runtime.Loader; using System.Text; using System.Text.RegularExpressions; @@ -26,9 +27,11 @@ using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; +using Microsoft.CodeAnalysis.NavigateTo; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Tags; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -48,12 +51,17 @@ protected override IntPtr LoadUnmanagedDll(string unmanagedDllName) => IntPtr.Zero; } - private static readonly FindReferencesSearchOptions s_findReferencesSearchOptions = new() - { - DisplayAllDefinitions = true, - }; - - private const int StackDisplayDepthLimit = 32; + /// + /// Mapping from the parameter type of the Find method to the value. + /// + private static readonly ImmutableDictionary s_queryKindByParameterType = ImmutableDictionary.Empty + .Add(typeof(Compilation), QueryKind.Compilation) + .Add(typeof(INamespaceSymbol), QueryKind.Namespace) + .Add(typeof(INamedTypeSymbol), QueryKind.NamedType) + .Add(typeof(IMethodSymbol), QueryKind.Method) + .Add(typeof(IFieldSymbol), QueryKind.Field) + .Add(typeof(IPropertySymbol), QueryKind.Property) + .Add(typeof(IEventSymbol), QueryKind.Event); protected abstract Compilation CreateCompilation(SourceText query, IEnumerable references, SolutionServices services, out SyntaxTree queryTree, CancellationToken cancellationToken); @@ -134,87 +142,26 @@ await observer.OnCompilationFailureAsync( Contract.ThrowIfNull(moduleCancellationTokenField); moduleCancellationTokenField.SetValue(null, cancellationToken); - if (!TryGetFindMethod(queryAssembly, out var findMethod, out var errorMessage, out var errorMessageArgs)) + if (!TryGetFindMethod(queryAssembly, out var findMethod, out var queryKind, out var errorMessage, out var errorMessageArgs)) { traceSource.TraceInformation($"Semantic search failed: {errorMessage}"); return CreateResult(errorMessage, errorMessageArgs); } - var executionTimeStopWatch = new Stopwatch(); - - foreach (var project in solution.Projects) + var invocationContext = new QueryExecutionContext(queryText, findMethod, observer, classificationOptions, traceSource); + try { - cancellationToken.ThrowIfCancellationRequested(); - - var compilation = await project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); - - cancellationToken.ThrowIfCancellationRequested(); + await invocationContext.InvokeAsync(solution, queryKind, cancellationToken).ConfigureAwait(false); - try + if (invocationContext.TerminatedWithException) { - executionTimeStopWatch.Start(); - - try - { - var symbols = (IEnumerable?)findMethod.Invoke(null, [compilation]) ?? []; - - foreach (var symbol in symbols) - { - cancellationToken.ThrowIfCancellationRequested(); - - if (symbol != null) - { - executionTimeStopWatch.Stop(); - - try - { - var definitionItem = await symbol.ToClassifiedDefinitionItemAsync( - classificationOptions, solution, s_findReferencesSearchOptions, isPrimary: true, includeHiddenLocations: false, cancellationToken).ConfigureAwait(false); - - await observer.OnDefinitionFoundAsync(definitionItem, cancellationToken).ConfigureAwait(false); - } - catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) - { - // skip symbol - } - - executionTimeStopWatch.Start(); - } - } - } - finally - { - executionTimeStopWatch.Stop(); - executionTime = executionTimeStopWatch.Elapsed; - } - } - catch (Exception e) when (e is not OperationCanceledException) - { - // exception from user code - - if (e is TargetInvocationException { InnerException: { } innerException }) - { - e = innerException; - } - - var (projectName, projectFlavor) = project.State.NameAndFlavor; - projectName ??= project.Name; - var projectDisplay = string.IsNullOrEmpty(projectFlavor) ? projectName : $"{projectName} ({projectFlavor})"; - - FormatStackTrace(e, queryAssembly, out var position, out var stackTraceTaggedText); - var span = queryText.Lines.GetTextSpan(new LinePositionSpan(position, position)); - - var exceptionNameTaggedText = GetExceptionTypeTaggedText(e, compilation); - - await observer.OnUserCodeExceptionAsync(new UserCodeExceptionInfo(projectDisplay, e.Message, exceptionNameTaggedText, stackTraceTaggedText, span), cancellationToken).ConfigureAwait(false); - - traceSource.TraceInformation($"Semantic query execution failed due to user code exception: {e}"); return CreateResult(FeaturesResources.Semantic_search_query_terminated_with_exception); } - - // complete project progress item: - remainingProgressItemCount--; - await observer.ItemsCompletedAsync(1, cancellationToken).ConfigureAwait(false); + } + finally + { + executionTime = new TimeSpan(invocationContext.ExecutionTime); + remainingProgressItemCount -= invocationContext.ProcessedProjectCount; } } finally @@ -239,96 +186,12 @@ ExecuteQueryResult CreateResult(string? errorMessage, params string[]? args) } } - private static ImmutableArray GetExceptionTypeTaggedText(Exception e, Compilation compilation) - => e.GetType().FullName is { } exceptionTypeName - ? compilation.GetTypeByMetadataName(exceptionTypeName) is { } exceptionTypeSymbol - ? exceptionTypeSymbol.ToDisplayParts(SymbolDisplayFormat.MinimallyQualifiedFormat).ToTaggedText() - : [new TaggedText(WellKnownTags.Class, exceptionTypeName)] - : [new TaggedText(WellKnownTags.Class, nameof(Exception))]; - - private static void FormatStackTrace(Exception e, Assembly queryAssembly, out LinePosition position, out ImmutableArray formattedTrace) - { - position = default; - - try - { - var trace = new StackTrace(e, fNeedFileInfo: true); - var frames = trace.GetFrames(); - var displayFrames = frames; - var skippedFrameCount = 0; - - try - { - var hostAssembly = typeof(AbstractSemanticSearchService).Assembly; - var displayFramesEnd = frames.Length; - var foundPosition = false; - for (var i = 0; i < frames.Length; i++) - { - var frame = frames[i]; - - if (frame.GetMethod() is { } method) - { - var frameAssembly = method.DeclaringType?.Assembly; - if (frameAssembly == hostAssembly) - { - displayFramesEnd = i; - break; - } - - if (!foundPosition && - frameAssembly == queryAssembly && - frame.GetFileName() is { } fileName && - frame.GetFileLineNumber() is > 0 and var line && - frame.GetFileColumnNumber() is > 0 and var column) - { - position = new LinePosition(line - 1, column - 1); - foundPosition = true; - } - } - } - - // display last StackDisplayDepthLimit frames preceding the host frame: - skippedFrameCount = Math.Max(0, displayFramesEnd - StackDisplayDepthLimit); - displayFrames = frames[skippedFrameCount..displayFramesEnd]; - } - catch - { - // nop - } - - formattedTrace = - [ - new TaggedText(tag: TextTags.Text, (skippedFrameCount > 0 ? " ..." + Environment.NewLine : "") + GetStackTraceText(displayFrames)) - ]; - } - catch - { - formattedTrace = []; - } - } - - private static string GetStackTraceText(IEnumerable frames) + private static bool TryGetFindMethod(Assembly queryAssembly, [NotNullWhen(true)] out MethodInfo? method, out QueryKind queryKind, out string? error, out string[]? errorMessageArgs) { -#if NET8_0_OR_GREATER - return new StackTrace(frames).ToString(); -#else - var builder = new StringBuilder(); - foreach (var frame in frames) - { - builder.Append(new StackTrace(frame).ToString()); - } - - return builder.ToString(); -#endif - } - - private static bool TryGetFindMethod(Assembly queryAssembly, [NotNullWhen(true)] out MethodInfo? method, out string? error, out string[]? errorMessageArgs) - { - // TODO: Use Compilation APIs to find the method - method = null; error = null; errorMessageArgs = null; + queryKind = default; Type? program; try @@ -346,45 +209,23 @@ private static bool TryGetFindMethod(Assembly queryAssembly, [NotNullWhen(true)] { try { - method = GetFindMethod(program, allowLocalFunction: true, ref error); + (method, queryKind) = GetFindMethod(program, ref error); } catch { } - - if (method != null) - { - return true; - } } - Type[] types; - try - { - types = queryAssembly.GetTypes(); - } - catch (TypeLoadException e) + if (method != null) { - error = FeaturesResources.Unable_to_load_type_0_1; - errorMessageArgs = [e.TypeName, e.Message]; - method = null; - return false; + return true; } - foreach (var type in types) - { - method = GetFindMethod(type, allowLocalFunction: false, ref error); - if (method != null) - { - return true; - } - } - - error ??= string.Format(FeaturesResources.The_query_does_not_specify_0_method_or_top_level_function, SemanticSearchUtilities.FindMethodName); + error ??= string.Format(FeaturesResources.The_query_does_not_specify_0_top_level_function, SemanticSearchUtilities.FindMethodName); return false; } - private static MethodInfo? GetFindMethod(Type type, bool allowLocalFunction, ref string? error) + private static (MethodInfo? method, QueryKind queryKind) GetFindMethod(Type type, ref string? error) { try { @@ -392,8 +233,7 @@ private static bool TryGetFindMethod(Assembly queryAssembly, [NotNullWhen(true)] foreach (var candidate in type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance)) { - if (candidate.Name == SemanticSearchUtilities.FindMethodName || - allowLocalFunction && candidate.Name.StartsWith($"<{WellKnownMemberNames.TopLevelStatementsEntryPointMethodName}>g__{SemanticSearchUtilities.FindMethodName}|")) + if (candidate.Name.StartsWith($"<{WellKnownMemberNames.TopLevelStatementsEntryPointMethodName}>g__{SemanticSearchUtilities.FindMethodName}|")) { candidates.Add(candidate); } @@ -401,35 +241,45 @@ private static bool TryGetFindMethod(Assembly queryAssembly, [NotNullWhen(true)] if (candidates is []) { - error = string.Format(FeaturesResources.The_query_does_not_specify_0_method_or_top_level_function, SemanticSearchUtilities.FindMethodName); - return null; + error = string.Format(FeaturesResources.The_query_does_not_specify_0_top_level_function, SemanticSearchUtilities.FindMethodName); + return default; } candidates.RemoveAll(candidate => candidate.IsGenericMethod || !candidate.IsStatic); if (candidates is []) { error = string.Format(FeaturesResources.Method_0_must_be_static_and_non_generic, SemanticSearchUtilities.FindMethodName); - return null; + return default; } - candidates.RemoveAll(candidate => !( - typeof(IEnumerable).IsAssignableFrom(candidate.ReturnType) && - candidate.GetParameters() is [{ ParameterType: var paramType }] && - typeof(Compilation).IsAssignableFrom(paramType))); + if (candidates is not [var method]) + { + error = string.Format(FeaturesResources.The_query_specifies_multiple_top_level_functions_1, SemanticSearchUtilities.FindMethodName); + return default; + } - if (candidates is []) + if (method.GetParameters() is not [var parameter]) { - error = string.Format(FeaturesResources.Method_0_must_have_a_single_parameter_of_type_1_and_return_2, SemanticSearchUtilities.FindMethodName, nameof(Compilation)); - return null; + error = string.Format(FeaturesResources.The_query_specifies_multiple_top_level_functions_1, SemanticSearchUtilities.FindMethodName); + return default; + } + + if (!s_queryKindByParameterType.TryGetValue(parameter.ParameterType, out var entity)) + { + error = string.Format( + FeaturesResources.Type_0_is_not_among_supported_types_1, + SemanticSearchUtilities.FindMethodName, + string.Join(", ", s_queryKindByParameterType.Keys.Select(t => $"'{t.Name}'"))); + + return default; } - Debug.Assert(candidates.Count == 1); - return candidates[0]; + return (method, entity); } catch (Exception e) { error = e.Message; - return null; + return default; } } } diff --git a/src/Features/Core/Portable/SemanticSearch/ISemanticSearchCopilotService.cs b/src/Features/Core/Portable/SemanticSearch/ISemanticSearchCopilotService.cs new file mode 100644 index 0000000000000..895018ce8d485 --- /dev/null +++ b/src/Features/Core/Portable/SemanticSearch/ISemanticSearchCopilotService.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.Threading; +using System.Threading.Tasks; + +namespace Microsoft.CodeAnalysis.SemanticSearch; + +internal interface ISemanticSearchCopilotService +{ + bool IsAvailable { get; } + + /// + /// Translates natural language to C# query. + /// + ValueTask TryGetQueryAsync(string text, SemanticSearchCopilotContext context, CancellationToken cancellationToken); +} diff --git a/src/Features/Core/Portable/SemanticSearch/QueryExecutionContext.cs b/src/Features/Core/Portable/SemanticSearch/QueryExecutionContext.cs new file mode 100644 index 0000000000000..5a96aa7037962 --- /dev/null +++ b/src/Features/Core/Portable/SemanticSearch/QueryExecutionContext.cs @@ -0,0 +1,289 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +#if NET6_0_OR_GREATER + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Classification; +using Microsoft.CodeAnalysis.ErrorReporting; +using Microsoft.CodeAnalysis.FindSymbols; +using Microsoft.CodeAnalysis.FindUsages; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Tags; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.SemanticSearch; + +internal sealed class QueryExecutionContext( + SourceText queryText, + MethodInfo method, + ISemanticSearchResultsObserver resultsObserver, + OptionsProvider classificationOptions, + TraceSource traceSource) +{ + private static readonly FindReferencesSearchOptions s_findReferencesSearchOptions = new() + { + DisplayAllDefinitions = true, + }; + + private const int StackDisplayDepthLimit = 32; + + private long _executionTime; + private int _processedProjectCount; + public bool TerminatedWithException { get; private set; } + + public long ExecutionTime => _executionTime; + public int ProcessedProjectCount => _processedProjectCount; + + public async Task InvokeAsync(Solution solution, QueryKind targetEntity, CancellationToken cancellationToken) + { + // Invoke query on projects and types in parallel and on members serially. + // Cancel execution if the query throws an exception. + + using var symbolEnumerationCancellationSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + + try + { + await Parallel.ForEachAsync(solution.Projects, symbolEnumerationCancellationSource.Token, async (project, cancellationToken) => + { + try + { + var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); + if (compilation == null) + { + return; + } + + // only search source symbols: + var rootNamespace = compilation.Assembly.GlobalNamespace; + + switch (targetEntity) + { + case QueryKind.Compilation: + await InvokeAsync(project, compilation, entity: compilation, symbolEnumerationCancellationSource, cancellationToken).ConfigureAwait(false); + break; + + case QueryKind.Namespace: + await Parallel.ForEachAsync(rootNamespace.GetAllNamespaces(cancellationToken), cancellationToken, async (namespaceSymbol, cancellationToken) => + { + await InvokeAsync(project, compilation, entity: namespaceSymbol, symbolEnumerationCancellationSource, cancellationToken).ConfigureAwait(false); + }).ConfigureAwait(false); + break; + + case QueryKind.NamedType: + case QueryKind.Field: + case QueryKind.Method: + case QueryKind.Property: + case QueryKind.Event: + + var kind = GetSymbolKind(targetEntity); + + await Parallel.ForEachAsync(rootNamespace.GetAllTypes(cancellationToken), async (type, cancellationToken) => + { + if (kind == SymbolKind.NamedType) + { + await InvokeAsync(project, compilation, entity: type, symbolEnumerationCancellationSource, cancellationToken).ConfigureAwait(false); + } + else + { + foreach (var member in type.GetMembers()) + { + if (member.Kind == kind) + { + await InvokeAsync(project, compilation, entity: member, symbolEnumerationCancellationSource, cancellationToken).ConfigureAwait(false); + } + } + } + }).ConfigureAwait(false); + break; + } + } + finally + { + // complete project progress item: + Interlocked.Increment(ref _processedProjectCount); + await resultsObserver.ItemsCompletedAsync(1, cancellationToken).ConfigureAwait(false); + } + }).ConfigureAwait(false); + } + catch (OperationCanceledException) when (symbolEnumerationCancellationSource.IsCancellationRequested && !cancellationToken.IsCancellationRequested) + { + // enumeration terminated due to exception in user code + } + } + + private async ValueTask InvokeAsync(Project project, Compilation compilation, object entity, CancellationTokenSource symbolEnumerationCancellationSource, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + + var executionTime = TimeSpan.Zero; + + try + { + var executionStart = Stopwatch.GetTimestamp(); + + try + { + var symbols = (IEnumerable?)method.Invoke(null, [entity]) ?? []; + + foreach (var symbol in symbols) + { + cancellationToken.ThrowIfCancellationRequested(); + + if (symbol != null) + { + executionTime += Stopwatch.GetElapsedTime(executionStart); + + try + { + var definitionItem = await symbol.ToClassifiedDefinitionItemAsync( + classificationOptions, project.Solution, s_findReferencesSearchOptions, isPrimary: true, includeHiddenLocations: false, cancellationToken).ConfigureAwait(false); + + await resultsObserver.OnDefinitionFoundAsync(definitionItem, cancellationToken).ConfigureAwait(false); + } + catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) + { + // skip symbol + } + + executionStart = Stopwatch.GetTimestamp(); + } + } + } + finally + { + executionTime += Stopwatch.GetElapsedTime(executionStart); + } + } + catch (Exception e) when (e is not OperationCanceledException) + { + // exception from user code + TerminatedWithException = true; + + if (e is TargetInvocationException { InnerException: { } innerException }) + { + e = innerException; + } + + var (projectName, projectFlavor) = project.State.NameAndFlavor; + projectName ??= project.Name; + var projectDisplay = string.IsNullOrEmpty(projectFlavor) ? projectName : $"{projectName} ({projectFlavor})"; + + Contract.ThrowIfNull(method.DeclaringType); + FormatStackTrace(e, method.DeclaringType.Assembly, out var position, out var stackTraceTaggedText); + var span = queryText.Lines.GetTextSpan(new LinePositionSpan(position, position)); + + var exceptionNameTaggedText = GetExceptionTypeTaggedText(e, compilation); + + await resultsObserver.OnUserCodeExceptionAsync(new UserCodeExceptionInfo(projectDisplay, e.Message, exceptionNameTaggedText, stackTraceTaggedText, span), cancellationToken).ConfigureAwait(false); + + traceSource.TraceInformation($"Semantic query execution failed due to user code exception: {e}"); + + symbolEnumerationCancellationSource.Cancel(); + } + + Interlocked.Add(ref _executionTime, executionTime.Ticks); + } + + private static SymbolKind GetSymbolKind(QueryKind targetEntity) + => targetEntity switch + { + QueryKind.Field => SymbolKind.Field, + QueryKind.Method => SymbolKind.Method, + QueryKind.Property => SymbolKind.Property, + QueryKind.Event => SymbolKind.Event, + QueryKind.NamedType => SymbolKind.NamedType, + QueryKind.Namespace => SymbolKind.Namespace, + _ => default + }; + + private static ImmutableArray GetExceptionTypeTaggedText(Exception e, Compilation compilation) + => e.GetType().FullName is { } exceptionTypeName + ? compilation.GetTypeByMetadataName(exceptionTypeName) is { } exceptionTypeSymbol + ? exceptionTypeSymbol.ToDisplayParts(SymbolDisplayFormat.MinimallyQualifiedFormat).ToTaggedText() + : [new TaggedText(WellKnownTags.Class, exceptionTypeName)] + : [new TaggedText(WellKnownTags.Class, nameof(Exception))]; + + private static void FormatStackTrace(Exception e, Assembly queryAssembly, out LinePosition position, out ImmutableArray formattedTrace) + { + position = default; + + try + { + var trace = new StackTrace(e, fNeedFileInfo: true); + var frames = trace.GetFrames(); + var displayFrames = frames; + var skippedFrameCount = 0; + + try + { + var hostAssembly = typeof(AbstractSemanticSearchService).Assembly; + var displayFramesEnd = frames.Length; + var foundPosition = false; + for (var i = 0; i < frames.Length; i++) + { + var frame = frames[i]; + + if (frame.GetMethod() is { } method) + { + var frameAssembly = method.DeclaringType?.Assembly; + if (frameAssembly == hostAssembly) + { + displayFramesEnd = i; + break; + } + + if (!foundPosition && + frameAssembly == queryAssembly && + frame.GetFileName() is { } fileName && + frame.GetFileLineNumber() is > 0 and var line && + frame.GetFileColumnNumber() is > 0 and var column) + { + position = new LinePosition(line - 1, column - 1); + foundPosition = true; + } + } + } + + // display last StackDisplayDepthLimit frames preceding the host frame: + skippedFrameCount = Math.Max(0, displayFramesEnd - StackDisplayDepthLimit); + displayFrames = frames[skippedFrameCount..displayFramesEnd]; + } + catch + { + // nop + } + + formattedTrace = + [ + new TaggedText(tag: TextTags.Text, (skippedFrameCount > 0 ? " ..." + Environment.NewLine : "") + GetStackTraceText(displayFrames)) + ]; + } + catch + { + formattedTrace = []; + } + } + + private static string GetStackTraceText(IEnumerable frames) + { +#if NET8_0_OR_GREATER + return new StackTrace(frames).ToString(); +#else + var builder = new StringBuilder(); + foreach (var frame in frames) + { + builder.Append(new StackTrace(frame).ToString()); + } + + return builder.ToString(); +#endif + } +} +#endif diff --git a/src/Features/Core/Portable/SemanticSearch/QueryKind.cs b/src/Features/Core/Portable/SemanticSearch/QueryKind.cs new file mode 100644 index 0000000000000..b172ce0626c6b --- /dev/null +++ b/src/Features/Core/Portable/SemanticSearch/QueryKind.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. +#if NET6_0_OR_GREATER + +namespace Microsoft.CodeAnalysis.SemanticSearch; + +internal enum QueryKind +{ + Compilation, + Namespace, + NamedType, + Method, + Field, + Property, + Event +} +#endif diff --git a/src/Features/Core/Portable/SemanticSearch/SemanticSearchCopilotContext.cs b/src/Features/Core/Portable/SemanticSearch/SemanticSearchCopilotContext.cs new file mode 100644 index 0000000000000..dcdfd21810a39 --- /dev/null +++ b/src/Features/Core/Portable/SemanticSearch/SemanticSearchCopilotContext.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; + +namespace Microsoft.CodeAnalysis.SemanticSearch; + +/// +/// Context necessary to generate Copilot prompt for semantic search query. +/// +internal sealed class SemanticSearchCopilotContext +{ + public required string ModelName { get; init; } + + /// + /// List of package names and versions that to include in the prompt. + /// + public required IEnumerable<(string name, Version version)> AvailablePackages { get; init; } +} + +internal readonly struct SemanticSearchCopilotGeneratedQuery +{ + /// + /// The generated code or an error message. + /// + public required string Text { get; init; } + + /// + /// True if is an error message. + /// + public required bool IsError { get; init; } +} + diff --git a/src/Features/Core/Portable/Shared/Extensions/DocumentExtensions.cs b/src/Features/Core/Portable/Shared/Extensions/DocumentExtensions.cs index e1dbba9c7589e..236e180050fdd 100644 --- a/src/Features/Core/Portable/Shared/Extensions/DocumentExtensions.cs +++ b/src/Features/Core/Portable/Shared/Extensions/DocumentExtensions.cs @@ -8,10 +8,8 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.Shared.Naming; using Roslyn.Utilities; using static Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles.SymbolSpecification; diff --git a/src/Features/Core/Portable/Shared/Extensions/ISymbolExtensions_2.cs b/src/Features/Core/Portable/Shared/Extensions/ISymbolExtensions_2.cs index 0b78a77b904cb..71b8b98c413aa 100644 --- a/src/Features/Core/Portable/Shared/Extensions/ISymbolExtensions_2.cs +++ b/src/Features/Core/Portable/Shared/Extensions/ISymbolExtensions_2.cs @@ -57,6 +57,7 @@ public static Glyph GetGlyph(this ISymbol symbol) { switch (((INamedTypeSymbol)symbol).TypeKind) { + case TypeKind.Extension: case TypeKind.Class: publicIcon = Glyph.ClassPublic; break; diff --git a/src/Features/Core/Portable/Shared/Extensions/ProjectExtensions.cs b/src/Features/Core/Portable/Shared/Extensions/ProjectExtensions.cs index 1721fbd6e0f25..f83adff01ea0d 100644 --- a/src/Features/Core/Portable/Shared/Extensions/ProjectExtensions.cs +++ b/src/Features/Core/Portable/Shared/Extensions/ProjectExtensions.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.Shared.Extensions; internal static class ProjectExtensions diff --git a/src/Features/Core/Portable/Shared/Extensions/SyntaxTokenListExtensions.cs b/src/Features/Core/Portable/Shared/Extensions/SyntaxTokenListExtensions.cs index 58a720314eb7c..0d2d7404539ff 100644 --- a/src/Features/Core/Portable/Shared/Extensions/SyntaxTokenListExtensions.cs +++ b/src/Features/Core/Portable/Shared/Extensions/SyntaxTokenListExtensions.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Features/Core/Portable/Shared/IDocumentSupportsFeatureService.cs b/src/Features/Core/Portable/Shared/IDocumentSupportsFeatureService.cs index 6e4e21b57f012..a34876f4af3a5 100644 --- a/src/Features/Core/Portable/Shared/IDocumentSupportsFeatureService.cs +++ b/src/Features/Core/Portable/Shared/IDocumentSupportsFeatureService.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.Composition; using Microsoft.CodeAnalysis.Host; diff --git a/src/Features/Core/Portable/Shared/TestHooks/Legacy/ListenerForwarders.cs b/src/Features/Core/Portable/Shared/TestHooks/Legacy/ListenerForwarders.cs index 64f1070acbd09..60847b4fb7530 100644 --- a/src/Features/Core/Portable/Shared/TestHooks/Legacy/ListenerForwarders.cs +++ b/src/Features/Core/Portable/Shared/TestHooks/Legacy/ListenerForwarders.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.Runtime.CompilerServices; [assembly: TypeForwardedTo(typeof(Microsoft.CodeAnalysis.Shared.TestHooks.AsynchronousOperationListener))] diff --git a/src/Features/Core/Portable/Shared/Utilities/ExtractTypeHelpers.cs b/src/Features/Core/Portable/Shared/Utilities/ExtractTypeHelpers.cs index 56278394a7f2b..4b472a4b56f8f 100644 --- a/src/Features/Core/Portable/Shared/Utilities/ExtractTypeHelpers.cs +++ b/src/Features/Core/Portable/Shared/Utilities/ExtractTypeHelpers.cs @@ -112,7 +112,8 @@ internal static class ExtractTypeHelpers return (formattedDocument, typeAnnotation); } - public static string GetTypeParameterSuffix(Document document, SyntaxFormattingOptions formattingOptions, INamedTypeSymbol type, IEnumerable extractableMembers, CancellationToken cancellationToken) + public static string GetTypeParameterSuffix( + Document document, SyntaxFormattingOptions formattingOptions, INamedTypeSymbol type, ImmutableArray extractableMembers, CancellationToken cancellationToken) { var typeParameters = GetRequiredTypeParametersForMembers(type, extractableMembers); @@ -127,7 +128,8 @@ public static string GetTypeParameterSuffix(Document document, SyntaxFormattingO return Formatter.Format(syntaxGenerator.SyntaxGeneratorInternal.TypeParameterList(typeParameterNames), document.Project.Solution.Services, formattingOptions, cancellationToken).ToString(); } - public static ImmutableArray GetRequiredTypeParametersForMembers(INamedTypeSymbol type, IEnumerable includedMembers) + public static ImmutableArray GetRequiredTypeParametersForMembers( + INamedTypeSymbol type, ImmutableArray includedMembers) { var potentialTypeParameters = GetPotentialTypeParameters(type); @@ -181,7 +183,8 @@ private static ImmutableArray GetPotentialTypeParameters(I return typeParameters.ToImmutableAndClear(); } - private static ImmutableArray GetDirectlyReferencedTypeParameters(IEnumerable potentialTypeParameters, IEnumerable includedMembers) + private static ImmutableArray GetDirectlyReferencedTypeParameters( + ImmutableArray potentialTypeParameters, ImmutableArray includedMembers) { using var _ = ArrayBuilder.GetInstance(out var directlyReferencedTypeParameters); foreach (var typeParameter in potentialTypeParameters) diff --git a/src/Features/Core/Portable/SignatureHelp/SignatureHelpTriggerInfo.cs b/src/Features/Core/Portable/SignatureHelp/SignatureHelpTriggerInfo.cs index dacb61904988c..c1c203859338e 100644 --- a/src/Features/Core/Portable/SignatureHelp/SignatureHelpTriggerInfo.cs +++ b/src/Features/Core/Portable/SignatureHelp/SignatureHelpTriggerInfo.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Roslyn.Utilities; - namespace Microsoft.CodeAnalysis.SignatureHelp; internal readonly struct SignatureHelpTriggerInfo diff --git a/src/Features/Core/Portable/Snippets/AbstractSnippetService.cs b/src/Features/Core/Portable/Snippets/AbstractSnippetService.cs index 985c9e525d990..ae14a9d926fa8 100644 --- a/src/Features/Core/Portable/Snippets/AbstractSnippetService.cs +++ b/src/Features/Core/Portable/Snippets/AbstractSnippetService.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Snippets.SnippetProviders; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Snippets; diff --git a/src/Features/Core/Portable/Snippets/ISnippetInfoService.cs b/src/Features/Core/Portable/Snippets/ISnippetInfoService.cs index 61cc2c77f5dfe..8f557d7612c01 100644 --- a/src/Features/Core/Portable/Snippets/ISnippetInfoService.cs +++ b/src/Features/Core/Portable/Snippets/ISnippetInfoService.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 Microsoft.CodeAnalysis.Host; @@ -12,6 +10,6 @@ namespace Microsoft.CodeAnalysis.Snippets; internal interface ISnippetInfoService : ILanguageService { IEnumerable GetSnippetsIfAvailable(); - bool SnippetShortcutExists_NonBlocking(string shortcut); + bool SnippetShortcutExists_NonBlocking(string? shortcut); bool ShouldFormatSnippet(SnippetInfo snippetInfo); } diff --git a/src/Features/Core/Portable/Snippets/RoslynLSPSnippetConverter.cs b/src/Features/Core/Portable/Snippets/RoslynLSPSnippetConverter.cs index 7052c0a1bb86b..98d034daaaa42 100644 --- a/src/Features/Core/Portable/Snippets/RoslynLSPSnippetConverter.cs +++ b/src/Features/Core/Portable/Snippets/RoslynLSPSnippetConverter.cs @@ -10,7 +10,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Snippets; diff --git a/src/Features/Core/Portable/Snippets/SnippetInfo.cs b/src/Features/Core/Portable/Snippets/SnippetInfo.cs index 3f84621858ba2..a2a84efb42060 100644 --- a/src/Features/Core/Portable/Snippets/SnippetInfo.cs +++ b/src/Features/Core/Portable/Snippets/SnippetInfo.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.Snippets; internal sealed class SnippetInfo(string shortcut, string title, string description, string path) diff --git a/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractConsoleSnippetProvider.cs b/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractConsoleSnippetProvider.cs index 574930fcbf3a3..cff1abe841c67 100644 --- a/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractConsoleSnippetProvider.cs +++ b/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractConsoleSnippetProvider.cs @@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Snippets.SnippetProviders; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Snippets; diff --git a/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractUsingSnippetProvider.cs b/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractUsingSnippetProvider.cs new file mode 100644 index 0000000000000..f64d64c1af24b --- /dev/null +++ b/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractUsingSnippetProvider.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.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Shared.Utilities; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Snippets.SnippetProviders; + +internal abstract class AbstractUsingSnippetProvider : AbstractStatementSnippetProvider + where TUsingStatementSyntax : SyntaxNode +{ + protected sealed override async Task GenerateSnippetTextChangeAsync(Document document, int position, CancellationToken cancellationToken) + { + var generator = SyntaxGenerator.GetGenerator(document); + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var identifierName = NameGenerator.GenerateUniqueName("resource", + n => semanticModel.LookupSymbols(position, name: n).IsEmpty); + var statement = generator.UsingStatement(generator.IdentifierName(identifierName), statements: []); + return new TextChange(TextSpan.FromBounds(position, position), statement.NormalizeWhitespace().ToFullString()); + } +} diff --git a/src/Features/Core/Portable/SolutionCrawler/AbstractDocumentDifferenceService.cs b/src/Features/Core/Portable/SolutionCrawler/AbstractDocumentDifferenceService.cs index fc434d7a511e2..bb386db8118ec 100644 --- a/src/Features/Core/Portable/SolutionCrawler/AbstractDocumentDifferenceService.cs +++ b/src/Features/Core/Portable/SolutionCrawler/AbstractDocumentDifferenceService.cs @@ -9,12 +9,13 @@ using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.SolutionCrawler; internal abstract class AbstractDocumentDifferenceService : IDocumentDifferenceService { + protected abstract bool IsContainedInMemberBody(SyntaxNode oldMember, TextSpan span); + public async Task GetChangedMemberAsync(Document oldDocument, Document newDocument, CancellationToken cancellationToken) { try @@ -100,7 +101,7 @@ internal abstract class AbstractDocumentDifferenceService : IDocumentDifferenceS } } - private static SyntaxNode? GetChangedMember( + private SyntaxNode? GetChangedMember( ISyntaxFactsService syntaxFactsService, SyntaxNode oldRoot, SyntaxNode newRoot, TextChangeRange range) { // if either old or new tree contains skipped text, re-analyze whole document @@ -119,7 +120,7 @@ internal abstract class AbstractDocumentDifferenceService : IDocumentDifferenceS } // member doesn't contain the change - if (!syntaxFactsService.ContainsInMemberBody(oldMember, range.Span)) + if (!IsContainedInMemberBody(oldMember, range.Span)) { return null; } diff --git a/src/Features/Core/Portable/SplitOrMergeIfStatements/AbstractMergeIfStatementsCodeRefactoringProvider.cs b/src/Features/Core/Portable/SplitOrMergeIfStatements/AbstractMergeIfStatementsCodeRefactoringProvider.cs index b4516fb56f5ca..8cf3421b36ab4 100644 --- a/src/Features/Core/Portable/SplitOrMergeIfStatements/AbstractMergeIfStatementsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/SplitOrMergeIfStatements/AbstractMergeIfStatementsCodeRefactoringProvider.cs @@ -6,7 +6,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; diff --git a/src/Features/Core/Portable/SplitOrMergeIfStatements/Consecutive/AbstractSplitIntoConsecutiveIfStatementsCodeRefactoringProvider.cs b/src/Features/Core/Portable/SplitOrMergeIfStatements/Consecutive/AbstractSplitIntoConsecutiveIfStatementsCodeRefactoringProvider.cs index 923d54b3e98d0..49e37866eaad9 100644 --- a/src/Features/Core/Portable/SplitOrMergeIfStatements/Consecutive/AbstractSplitIntoConsecutiveIfStatementsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/SplitOrMergeIfStatements/Consecutive/AbstractSplitIntoConsecutiveIfStatementsCodeRefactoringProvider.cs @@ -5,7 +5,6 @@ #nullable disable using System; -using System.Collections.Immutable; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; diff --git a/src/Features/Core/Portable/SplitOrMergeIfStatements/IIfLikeStatementGenerator.cs b/src/Features/Core/Portable/SplitOrMergeIfStatements/IIfLikeStatementGenerator.cs index fe1d6c962f31c..6f6657c7d98b0 100644 --- a/src/Features/Core/Portable/SplitOrMergeIfStatements/IIfLikeStatementGenerator.cs +++ b/src/Features/Core/Portable/SplitOrMergeIfStatements/IIfLikeStatementGenerator.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Host; diff --git a/src/Features/Core/Portable/StackTraceExplorer/IStackTraceExplorerService.cs b/src/Features/Core/Portable/StackTraceExplorer/IStackTraceExplorerService.cs index 68f42960dfc3b..d8aabcce75751 100644 --- a/src/Features/Core/Portable/StackTraceExplorer/IStackTraceExplorerService.cs +++ b/src/Features/Core/Portable/StackTraceExplorer/IStackTraceExplorerService.cs @@ -16,7 +16,7 @@ internal interface IStackTraceExplorerService : IWorkspaceService /// in a solution. Looks for an exact filepath match first, then defaults to /// a best guess. /// - (Document? document, int line) GetDocumentAndLine(Solution solution, ParsedFrame frame); + (TextDocument? document, int line) GetDocumentAndLine(Solution solution, ParsedFrame frame); Task TryFindDefinitionAsync(Solution solution, ParsedFrame frame, StackFrameSymbolPart symbolPart, CancellationToken cancellationToken); } diff --git a/src/Features/Core/Portable/StackTraceExplorer/StackTraceExplorerService.cs b/src/Features/Core/Portable/StackTraceExplorer/StackTraceExplorerService.cs index e809b29c3f232..22c06ad2d006f 100644 --- a/src/Features/Core/Portable/StackTraceExplorer/StackTraceExplorerService.cs +++ b/src/Features/Core/Portable/StackTraceExplorer/StackTraceExplorerService.cs @@ -2,30 +2,29 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Composition; using System.IO; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.EmbeddedLanguages.StackFrame; using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Remote; +using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.StackTraceExplorer; [ExportWorkspaceService(typeof(IStackTraceExplorerService)), Shared] -internal sealed class StackTraceExplorerService : IStackTraceExplorerService +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class StackTraceExplorerService() : IStackTraceExplorerService { - [ImportingConstructor] - [System.Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public StackTraceExplorerService() - { - } - - public (Document? document, int line) GetDocumentAndLine(Solution solution, ParsedFrame frame) + public (TextDocument? document, int line) GetDocumentAndLine(Solution solution, ParsedFrame frame) { if (frame is ParsedStackFrame parsedFrame) { @@ -73,7 +72,7 @@ public StackTraceExplorerService() return await StackTraceExplorerUtilities.GetDefinitionAsync(solution, parsedFrame.Root, symbolPart, cancellationToken).ConfigureAwait(false); } - private static ImmutableArray GetFileMatches(Solution solution, StackFrameCompilationUnit root, out int lineNumber) + private static ImmutableArray GetFileMatches(Solution solution, StackFrameCompilationUnit root, out int lineNumber) { lineNumber = 0; if (root.FileInformationExpression is null) @@ -86,19 +85,28 @@ private static ImmutableArray GetFileMatches(Solution solution, StackF RoslynDebug.AssertNotNull(lineString); lineNumber = int.Parse(lineString); + var documentId = solution.GetDocumentIdsWithFilePath(fileName).FirstOrDefault(); + + if (documentId is not null) + { + var document = solution.GetRequiredTextDocument(documentId); + return [document]; + } + var documentName = Path.GetFileName(fileName); - var potentialMatches = new HashSet(); + var potentialMatches = new HashSet(); foreach (var project in solution.Projects) { - foreach (var document in project.Documents) - { - if (document.FilePath == fileName) - { - return [document]; - } + // As of writing there is no way to get all the documents for a specific project + // so we need to check both the main and additional documents. If more document types + // get added this likely will need to be updated. + var allDocuments = project.Documents.Concat(project.AdditionalDocuments); - else if (document.Name == documentName) + foreach (var document in allDocuments) + { + var name = Path.GetFileName(document.Name); + if (name.Equals(documentName, StringComparison.OrdinalIgnoreCase)) { potentialMatches.Add(document); } diff --git a/src/Features/Core/Portable/Structure/BlockStructure.cs b/src/Features/Core/Portable/Structure/BlockStructure.cs index a7353954b5d01..9f232eca1bb21 100644 --- a/src/Features/Core/Portable/Structure/BlockStructure.cs +++ b/src/Features/Core/Portable/Structure/BlockStructure.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; namespace Microsoft.CodeAnalysis.Structure; diff --git a/src/Features/Core/Portable/Structure/BlockStructureContext.cs b/src/Features/Core/Portable/Structure/BlockStructureContext.cs index da3d108b1d6c7..9f7184e063b8a 100644 --- a/src/Features/Core/Portable/Structure/BlockStructureContext.cs +++ b/src/Features/Core/Portable/Structure/BlockStructureContext.cs @@ -5,7 +5,6 @@ using System; using System.Threading; using Microsoft.CodeAnalysis.PooledObjects; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Structure; diff --git a/src/Features/Core/Portable/Structure/BlockTypes.cs b/src/Features/Core/Portable/Structure/BlockTypes.cs index e715be39d990a..4d118d0eda4b1 100644 --- a/src/Features/Core/Portable/Structure/BlockTypes.cs +++ b/src/Features/Core/Portable/Structure/BlockTypes.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.Structure; internal static class BlockTypes diff --git a/src/Features/Core/Portable/Structure/Syntax/AbstractBlockStructureProvider.cs b/src/Features/Core/Portable/Structure/Syntax/AbstractBlockStructureProvider.cs index 27ed0aeb698ca..a81c2a84ff107 100644 --- a/src/Features/Core/Portable/Structure/Syntax/AbstractBlockStructureProvider.cs +++ b/src/Features/Core/Portable/Structure/Syntax/AbstractBlockStructureProvider.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using Microsoft.CodeAnalysis.ErrorReporting; -using Roslyn.Utilities; +using Microsoft.CodeAnalysis.Threading; namespace Microsoft.CodeAnalysis.Structure; diff --git a/src/Features/Core/Portable/Structure/Syntax/BlockStructureExtensions.cs b/src/Features/Core/Portable/Structure/Syntax/BlockStructureExtensions.cs index 52811854f5556..808928eb22b47 100644 --- a/src/Features/Core/Portable/Structure/Syntax/BlockStructureExtensions.cs +++ b/src/Features/Core/Portable/Structure/Syntax/BlockStructureExtensions.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Immutable; diff --git a/src/Features/Core/Portable/SymbolMapping/SymbolMappingResult.cs b/src/Features/Core/Portable/SymbolMapping/SymbolMappingResult.cs index 2bd03eb6725b3..ee967b837ed40 100644 --- a/src/Features/Core/Portable/SymbolMapping/SymbolMappingResult.cs +++ b/src/Features/Core/Portable/SymbolMapping/SymbolMappingResult.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Roslyn.Utilities; - namespace Microsoft.CodeAnalysis.SymbolMapping; internal sealed class SymbolMappingResult diff --git a/src/Features/Core/Portable/SymbolSearch/Windows/IAddReferenceDatabaseWrapper.cs b/src/Features/Core/Portable/SymbolSearch/Windows/IAddReferenceDatabaseWrapper.cs index 85cc85b9ace5d..13908953fa677 100644 --- a/src/Features/Core/Portable/SymbolSearch/Windows/IAddReferenceDatabaseWrapper.cs +++ b/src/Features/Core/Portable/SymbolSearch/Windows/IAddReferenceDatabaseWrapper.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Elfie.Model; namespace Microsoft.CodeAnalysis.SymbolSearch; diff --git a/src/Features/Core/Portable/SymbolSearch/Windows/IPatchService.cs b/src/Features/Core/Portable/SymbolSearch/Windows/IPatchService.cs index afb5da781ae0d..9183ba25a27eb 100644 --- a/src/Features/Core/Portable/SymbolSearch/Windows/IPatchService.cs +++ b/src/Features/Core/Portable/SymbolSearch/Windows/IPatchService.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.SymbolSearch; /// diff --git a/src/Features/Core/Portable/SymbolSearch/Windows/NativePatching.cs b/src/Features/Core/Portable/SymbolSearch/Windows/NativePatching.cs index 9682c6af9ae09..20f280c58e42b 100644 --- a/src/Features/Core/Portable/SymbolSearch/Windows/NativePatching.cs +++ b/src/Features/Core/Portable/SymbolSearch/Windows/NativePatching.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.ComponentModel; using System.Runtime.InteropServices; diff --git a/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.DelayService.cs b/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.DelayService.cs index f7f27b62241df..ea917220569fd 100644 --- a/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.DelayService.cs +++ b/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.DelayService.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; namespace Microsoft.CodeAnalysis.SymbolSearch; diff --git a/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.PatchService.cs b/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.PatchService.cs index 1390a65cf5497..dae5b6b2b2029 100644 --- a/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.PatchService.cs +++ b/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.PatchService.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.SymbolSearch; internal sealed partial class SymbolSearchUpdateEngine diff --git a/src/Features/Core/Portable/SyncNamespaces/ISyncNamespacesService.cs b/src/Features/Core/Portable/SyncNamespaces/ISyncNamespacesService.cs index a64225f234aab..677432813b071 100644 --- a/src/Features/Core/Portable/SyncNamespaces/ISyncNamespacesService.cs +++ b/src/Features/Core/Portable/SyncNamespaces/ISyncNamespacesService.cs @@ -6,7 +6,6 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.SyncNamespaces; diff --git a/src/Features/Core/Portable/TaskList/AbstractTaskListService.cs b/src/Features/Core/Portable/TaskList/AbstractTaskListService.cs index 4fffe4664dde4..707a9827ee98a 100644 --- a/src/Features/Core/Portable/TaskList/AbstractTaskListService.cs +++ b/src/Features/Core/Portable/TaskList/AbstractTaskListService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Immutable; using System.Threading; diff --git a/src/Features/Core/Portable/ValueTracking/SerializableValueTrackedItem.cs b/src/Features/Core/Portable/ValueTracking/SerializableValueTrackedItem.cs index 9bf3bec419197..8d88841b022ef 100644 --- a/src/Features/Core/Portable/ValueTracking/SerializableValueTrackedItem.cs +++ b/src/Features/Core/Portable/ValueTracking/SerializableValueTrackedItem.cs @@ -7,7 +7,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ValueTracking; diff --git a/src/Features/Core/Portable/ValueTracking/ValueTrackedItem.cs b/src/Features/Core/Portable/ValueTracking/ValueTrackedItem.cs index 50eaca6dbf26a..ae379c7485cfc 100644 --- a/src/Features/Core/Portable/ValueTracking/ValueTrackedItem.cs +++ b/src/Features/Core/Portable/ValueTracking/ValueTrackedItem.cs @@ -6,7 +6,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ValueTracking; diff --git a/src/Features/Core/Portable/Workspace/CompileTimeSolutionProvider.cs b/src/Features/Core/Portable/Workspace/CompileTimeSolutionProvider.cs index b7f4fc33ddcc3..ba732e0261e17 100644 --- a/src/Features/Core/Portable/Workspace/CompileTimeSolutionProvider.cs +++ b/src/Features/Core/Portable/Workspace/CompileTimeSolutionProvider.cs @@ -35,7 +35,7 @@ public Factory() } [Obsolete(MefConstruction.FactoryMethodMessage, error: true)] - public IWorkspaceService? CreateService(HostWorkspaceServices workspaceServices) + public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) => new CompileTimeSolutionProvider(workspaceServices.Workspace); } diff --git a/src/Features/Core/Portable/Wrapping/AbstractWrappingCodeRefactoringProvider.cs b/src/Features/Core/Portable/Wrapping/AbstractWrappingCodeRefactoringProvider.cs index d57f2479f6d4c..9612c1b5b3da1 100644 --- a/src/Features/Core/Portable/Wrapping/AbstractWrappingCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/Wrapping/AbstractWrappingCodeRefactoringProvider.cs @@ -5,7 +5,6 @@ using System.Collections.Immutable; using System.Linq; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Features/Core/Portable/Wrapping/ISyntaxWrapper.cs b/src/Features/Core/Portable/Wrapping/ISyntaxWrapper.cs index 445c4d721a952..2c5e666bd5634 100644 --- a/src/Features/Core/Portable/Wrapping/ISyntaxWrapper.cs +++ b/src/Features/Core/Portable/Wrapping/ISyntaxWrapper.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; @@ -25,6 +23,6 @@ internal interface ISyntaxWrapper /// Returns the that produces wrapping code actions for the /// node passed in. Returns if this Wrapper cannot wrap this node. /// - Task TryCreateComputerAsync( + Task TryCreateComputerAsync( Document document, int position, SyntaxNode node, SyntaxWrappingOptions options, bool containsSyntaxError, CancellationToken cancellationToken); } diff --git a/src/Features/Core/Portable/Wrapping/SeparatedSyntaxList/SeparatedSyntaxListCodeActionComputer.cs b/src/Features/Core/Portable/Wrapping/SeparatedSyntaxList/SeparatedSyntaxListCodeActionComputer.cs index 2c6276e32b4e4..4c74a01041c65 100644 --- a/src/Features/Core/Portable/Wrapping/SeparatedSyntaxList/SeparatedSyntaxListCodeActionComputer.cs +++ b/src/Features/Core/Portable/Wrapping/SeparatedSyntaxList/SeparatedSyntaxListCodeActionComputer.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; diff --git a/src/Features/Core/Portable/Wrapping/WrapItemsAction.cs b/src/Features/Core/Portable/Wrapping/WrapItemsAction.cs index 5fa29164d5cca..959500575b3d6 100644 --- a/src/Features/Core/Portable/Wrapping/WrapItemsAction.cs +++ b/src/Features/Core/Portable/Wrapping/WrapItemsAction.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.Immutable; diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf index abf7bf7c71c78..08bc6cbc15f53 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf @@ -147,17 +147,17 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Adding or moving {0} of {1} requires restarting the application. - Adding or moving {0} of {1} requires restarting the application. + Přidání nebo přesunutí {0} {1} vyžaduje restartování aplikace. Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. - Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + Přidání nebo přesunutí {0} z(e) {1} s explicitním nebo sekvenčním rozložením vyžaduje restartování aplikace. Adding or moving {0} of a COM interface requires restarting the application. - Adding or moving {0} of a COM interface requires restarting the application. + Přidání nebo přesunutí {0} rozhraní COM vyžaduje restartování aplikace. @@ -337,7 +337,7 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Cannot determine valid range of statements to extract - Cannot determine valid range of statements to extract + Nelze určit platný rozsah příkazů k extrakci. @@ -467,12 +467,12 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Changing the signature of {0} requires restarting the application. - Changing the signature of {0} requires restarting the application. + Změna podpisu {0} vyžaduje restartování aplikace. Changing the signature of {0} requires restarting the application because is not supported by the runtime. - Changing the signature of {0} requires restarting the application because is not supported by the runtime. + Změna podpisu {0} vyžaduje restartování aplikace, protože ji modul runtime nepodporuje. @@ -537,7 +537,7 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Conflict(s) detected. - Conflict(s) detected. + Zjistily se konflikty. @@ -857,7 +857,7 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Generate constructor from members... - Generate constructor from members... + Generovat konstruktor od členů... @@ -1100,11 +1100,6 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Metoda {0} musí být statická a neobecná. - - Method '{0}' must have a single parameter of type '{1}' and return '{2}' - Metoda {0} musí mít jeden parametr typu {1} a musí vracet {2}. - - Miscellaneous Files Různé soubory @@ -1197,7 +1192,7 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Move declaration near reference (may change semantics) - Move declaration near reference (may change semantics) + Přesunout deklaraci blízko odkazu (může se změnit sémantika) @@ -1272,12 +1267,12 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn No valid statement range to extract - No valid statement range to extract + Žádný platný rozsah příkazů pro extrakci Not all code paths return - Not all code paths return + Ne všechny cesty kódu vracejí @@ -1327,7 +1322,7 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Pull '{0}' up to ... - Pull '{0}' up to ... + Povýšit {0} na... @@ -2617,12 +2612,12 @@ Pozitivní kontrolní výrazy zpětného vyhledávání s nulovou délkou se obv Simplify member access '{0}' - Simplify member access '{0}' + Zjednodušit přístup ke členu {0} Simplify name '{0}' - Simplify name '{0}' + Zjednodušit název {0} @@ -2701,13 +2696,18 @@ Pozitivní kontrolní výrazy zpětného vyhledávání s nulovou délkou se obv - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - Sestavení analyzátoru {0} odkazuje na verzi {1} kompilátoru, která je novější než aktuálně spuštěná verze {2}. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + Sestavení analyzátoru {0} odkazuje na verzi {1} kompilátoru, která je novější než aktuálně spuštěná verze {2}. + + + + The query does not specify '{0}' top-level function + The query does not specify '{0}' top-level function - - The query does not specify '{0}' method or top-level function - Dotaz neurčuje metodu {0} nebo funkci nejvyšší úrovně. + + The query specifies multiple top-level functions '{1}' + The query specifies multiple top-level functions '{1}' @@ -2750,11 +2750,21 @@ Pozitivní kontrolní výrazy zpětného vyhledávání s nulovou délkou se obv Příliš mnoho znaků ) This is an error message shown to the user when they write an invalid Regular Expression. Example: ) + + Top-level function '{0}' must have a single parameter + Top-level function '{0}' must have a single parameter + + Trailing comma not allowed Čárka na konci není povolená + + Type '{0}' is not among supported types: {1} + Type '{0}' is not among supported types: {1} + + Types: Typy: @@ -2767,7 +2777,7 @@ Pozitivní kontrolní výrazy zpětného vyhledávání s nulovou délkou se obv Unable to create '{0}' - Unable to create '{0}' + Nepovedlo se vytvořit {0} @@ -3478,7 +3488,7 @@ Pokud se specifikátor formátu H použije bez dalších specifikátorů vlastn <class name> - <class name> + <název třídy> @@ -3664,7 +3674,7 @@ Specifikátor standardního formátu f představuje kombinaci vzorů dlouhého d <interface name> - <interface name> + <název rozhraní> @@ -3787,7 +3797,7 @@ Pokud se specifikátor formátu M použije bez dalších specifikátorů vlastn <namespace name> - <namespace name> + <název oboru názvů> @@ -4817,7 +4827,7 @@ Tato verze se používá zde: {2}. Add _null checks - Přidat kontroly hodnot null + Přidat kontroly hodnot _null diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf index 3f66f5c007bca..04652524b6549 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf @@ -147,17 +147,17 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Adding or moving {0} of {1} requires restarting the application. - Adding or moving {0} of {1} requires restarting the application. + Zum Hinzufügen oder Verschieben {0} von {1} muss die Anwendung neu gestartet werden. Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. - Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + Das Hinzufügen oder Verschieben von {0} von {1} mit explizitem oder sequenziellem Layout erfordert einen Neustart der Anwendung. Adding or moving {0} of a COM interface requires restarting the application. - Adding or moving {0} of a COM interface requires restarting the application. + Zum Hinzufügen oder Verschieben {0} einer COM-Schnittstelle muss die Anwendung neu gestartet werden. @@ -337,7 +337,7 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Cannot determine valid range of statements to extract - Cannot determine valid range of statements to extract + Ein gültiger Bereich der zu extrahierenden Anweisungen kann nicht ermittelt werden. @@ -467,12 +467,12 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Changing the signature of {0} requires restarting the application. - Changing the signature of {0} requires restarting the application. + Das Ändern der Signatur von {0} erfordert einen Neustart der Anwendung. Changing the signature of {0} requires restarting the application because is not supported by the runtime. - Changing the signature of {0} requires restarting the application because is not supported by the runtime. + Das Ändern der Signatur von {0} erfordert einen Neustart der Anwendung, da es von der Runtime nicht unterstützt wird. @@ -537,7 +537,7 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Conflict(s) detected. - Conflict(s) detected. + Konflikt(e) erkannt. @@ -857,7 +857,7 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Generate constructor from members... - Generate constructor from members... + Konstruktor aus Membern generieren... @@ -1100,11 +1100,6 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Die Methode „{0}“ muss statisch und nicht generisch sein. - - Method '{0}' must have a single parameter of type '{1}' and return '{2}' - Die Methode „{0}“ muss einen einzelnen Parameter vom Typ „{1}“ aufweisen und „{2}“ zurückgeben. - - Miscellaneous Files Sonstige Dateien @@ -1197,7 +1192,7 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Move declaration near reference (may change semantics) - Move declaration near reference (may change semantics) + Deklaration in die Nähe des Verweises verschieben (kann die Semantik ändern) @@ -1272,12 +1267,12 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d No valid statement range to extract - No valid statement range to extract + Kein gültiger Anweisungsbereich für die Extraktion Not all code paths return - Not all code paths return + Nicht alle Codepfadrückgaben @@ -1327,7 +1322,7 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Pull '{0}' up to ... - Pull '{0}' up to ... + „{0}“ ziehen bis zu ... @@ -2617,12 +2612,12 @@ Positive Lookbehindassertionen mit Nullbreite werden normalerweise am Anfang reg Simplify member access '{0}' - Simplify member access '{0}' + Memberzugriff '{0}' vereinfachen Simplify name '{0}' - Simplify name '{0}' + Name '{0}' vereinfachen @@ -2701,13 +2696,18 @@ Positive Lookbehindassertionen mit Nullbreite werden normalerweise am Anfang reg - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - Die Analyzerassembly „{0}“ verweist auf Version „{1}“ des Compilers, die neuer ist als die aktuell ausgeführte Version „{2}“. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + Die Analyzerassembly „{0}“ verweist auf Version „{1}“ des Compilers, die neuer ist als die aktuell ausgeführte Version „{2}“. + + + + The query does not specify '{0}' top-level function + The query does not specify '{0}' top-level function - - The query does not specify '{0}' method or top-level function - Die Abfrage gibt weder die Methode „{0}“ noch die Funktion der obersten Ebene an. + + The query specifies multiple top-level functions '{1}' + The query specifies multiple top-level functions '{1}' @@ -2750,11 +2750,21 @@ Positive Lookbehindassertionen mit Nullbreite werden normalerweise am Anfang reg Zu viele )-Zeichen. This is an error message shown to the user when they write an invalid Regular Expression. Example: ) + + Top-level function '{0}' must have a single parameter + Top-level function '{0}' must have a single parameter + + Trailing comma not allowed Ein nachgestelltes Komma ist unzulässig + + Type '{0}' is not among supported types: {1} + Type '{0}' is not among supported types: {1} + + Types: Typen: @@ -2767,7 +2777,7 @@ Positive Lookbehindassertionen mit Nullbreite werden normalerweise am Anfang reg Unable to create '{0}' - Unable to create '{0}' + „{0}“ kann nicht erstellt werden @@ -3478,7 +3488,7 @@ Bei Verwendung des Formatbezeichners "H" ohne weitere benutzerdefinierte Formatb <class name> - <class name> + <Klassenname> @@ -3664,7 +3674,7 @@ Der Standardformatbezeichner "f" repräsentiert eine Kombination aus den Mustern <interface name> - <interface name> + <Schnittstellenname> @@ -3787,7 +3797,7 @@ Bei Verwendung des Formatbezeichners "M" ohne weitere benutzerdefinierte Formatb <namespace name> - <namespace name> + <Namespacename> @@ -4817,7 +4827,7 @@ Diese Version wird verwendet in: {2} Add _null checks - NULL-Überprüfungen hinzufügen + _NULL-Überprüfungen hinzufügen diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf index eaf7db275ce17..08230a9f12fd1 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf @@ -147,17 +147,17 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Adding or moving {0} of {1} requires restarting the application. - Adding or moving {0} of {1} requires restarting the application. + Para agregar o mover {0} de {1} es necesario reiniciar la aplicación. Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. - Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + Para agregar o mover {0} de {1} con un diseño explícito o secuencial, es necesario reiniciar la aplicación. Adding or moving {0} of a COM interface requires restarting the application. - Adding or moving {0} of a COM interface requires restarting the application. + Para agregar o mover {0} de una interfaz COM es necesario reiniciar la aplicación. @@ -337,7 +337,7 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Cannot determine valid range of statements to extract - Cannot determine valid range of statements to extract + No se puede determinar el intervalo válido de instrucciones que se van a extraer @@ -467,12 +467,12 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Changing the signature of {0} requires restarting the application. - Changing the signature of {0} requires restarting the application. + Para cambiar la firma de {0} es necesario reiniciar la aplicación. Changing the signature of {0} requires restarting the application because is not supported by the runtime. - Changing the signature of {0} requires restarting the application because is not supported by the runtime. + Para cambiar la firma de {0} es necesario reiniciar la aplicación porque no es compatible con el tiempo de ejecución. @@ -537,7 +537,7 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Conflict(s) detected. - Conflict(s) detected. + Conflicto(s) detectado(s). @@ -857,7 +857,7 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Generate constructor from members... - Generate constructor from members... + Generar constructor a partir de miembros... @@ -1100,11 +1100,6 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa El método "{0}" debe ser estático y no genérico - - Method '{0}' must have a single parameter of type '{1}' and return '{2}' - El método "{0}" debe tener un único parámetro de tipo "{1}" y devolver "{2}" - - Miscellaneous Files Archivos varios @@ -1197,7 +1192,7 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Move declaration near reference (may change semantics) - Move declaration near reference (may change semantics) + Mover declaración cerca de referencia (puede cambiar semántica) @@ -1272,12 +1267,12 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa No valid statement range to extract - No valid statement range to extract + No hay un intervalo válido de instrucciones para extraer. Not all code paths return - Not all code paths return + No todas las rutas de acceso de código vuelven @@ -1327,7 +1322,7 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Pull '{0}' up to ... - Pull '{0}' up to ... + Extraer '{0}' hasta... @@ -2617,12 +2612,12 @@ Las aserciones de búsqueda retrasada (lookbehind) positivas de ancho cero se us Simplify member access '{0}' - Simplify member access '{0}' + Simplificar acceso a miembros "{0}" Simplify name '{0}' - Simplify name '{0}' + Simplificar nombre "{0}" @@ -2701,13 +2696,18 @@ Las aserciones de búsqueda retrasada (lookbehind) positivas de ancho cero se us - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - El ensamblado del analizador ”{0}” hace referencia a la versión ”{1}” del compilador, que es más reciente que la versión "{2}" que se está ejecutando actualmente. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + El ensamblado del analizador ”{0}” hace referencia a la versión ”{1}” del compilador, que es más reciente que la versión "{2}" que se está ejecutando actualmente. + + + + The query does not specify '{0}' top-level function + The query does not specify '{0}' top-level function - - The query does not specify '{0}' method or top-level function - La consulta no especifica "{0}" método o función de nivel superior + + The query specifies multiple top-level functions '{1}' + The query specifies multiple top-level functions '{1}' @@ -2750,11 +2750,21 @@ Las aserciones de búsqueda retrasada (lookbehind) positivas de ancho cero se us Demasiados ) This is an error message shown to the user when they write an invalid Regular Expression. Example: ) + + Top-level function '{0}' must have a single parameter + Top-level function '{0}' must have a single parameter + + Trailing comma not allowed Coma final no permitida + + Type '{0}' is not among supported types: {1} + Type '{0}' is not among supported types: {1} + + Types: Tipos: @@ -2767,7 +2777,7 @@ Las aserciones de búsqueda retrasada (lookbehind) positivas de ancho cero se us Unable to create '{0}' - Unable to create '{0}' + No se puede crear '{0}' @@ -3478,7 +3488,7 @@ Si el especificador de formato "H" se usa sin otros especificadores de formato p <class name> - <class name> + <nombre de la clase> @@ -3664,7 +3674,7 @@ El especificador de formato estándar "f" representa una combinación de los pat <interface name> - <interface name> + <nombre de la interfaz> @@ -3787,7 +3797,7 @@ Si el especificador de formato "M" se usa sin otros especificadores de formato p <namespace name> - <namespace name> + <nombre de espacio de nombres> @@ -4817,7 +4827,7 @@ Esta versión se utiliza en: {2} Add _null checks - Agregar comprobaciones de valores null + Agregar comprobaciones de _null diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf index cab7bba71c303..86f2a0c048051 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf @@ -147,17 +147,17 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Adding or moving {0} of {1} requires restarting the application. - Adding or moving {0} of {1} requires restarting the application. + L’ajout ou le déplacement de {0} de {1} nécessite le redémarrage de l’application. Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. - Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + L'ajout ou le déplacement de {0} sur {1} avec une disposition explicite ou séquentielle nécessite le redémarrage de l'application. Adding or moving {0} of a COM interface requires restarting the application. - Adding or moving {0} of a COM interface requires restarting the application. + L’ajout ou le déplacement {0} d’une interface COM nécessite le redémarrage de l’application. @@ -337,7 +337,7 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Cannot determine valid range of statements to extract - Cannot determine valid range of statements to extract + Impossible de déterminer la plage valide des instructions à extraire @@ -467,12 +467,12 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Changing the signature of {0} requires restarting the application. - Changing the signature of {0} requires restarting the application. + Changer la signature {0} nécessite de redémarrer l'application. Changing the signature of {0} requires restarting the application because is not supported by the runtime. - Changing the signature of {0} requires restarting the application because is not supported by the runtime. + La modification de la signature de {0} nécessite le redémarrage de l'application car elle n'est pas prise en charge par le runtime. @@ -537,7 +537,7 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Conflict(s) detected. - Conflict(s) detected. + Conflit(s) détecté(s). @@ -857,7 +857,7 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Generate constructor from members... - Generate constructor from members... + Générer un constructeur à partir des membres... @@ -1100,11 +1100,6 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai La méthode « {0} » doit être statique et non générique - - Method '{0}' must have a single parameter of type '{1}' and return '{2}' - Le « {0} » de méthode doit avoir un seul paramètre de type « {1} » et « {2} » de retour - - Miscellaneous Files Fichiers divers @@ -1197,7 +1192,7 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Move declaration near reference (may change semantics) - Move declaration near reference (may change semantics) + Déplacer la déclaration près de la référence (peut modifier la sémantique) @@ -1272,12 +1267,12 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai No valid statement range to extract - No valid statement range to extract + Aucune plage valide d'instructions à extraire Not all code paths return - Not all code paths return + Tous les chemins du code n'ont pas été retournés @@ -1327,7 +1322,7 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Pull '{0}' up to ... - Pull '{0}' up to ... + Tirez '{0}' jusqu'à ... @@ -2617,12 +2612,12 @@ Les assertions arrière positives de largeur nulle sont généralement utilisée Simplify member access '{0}' - Simplify member access '{0}' + Simplifier l'accès au membre '{0}' Simplify name '{0}' - Simplify name '{0}' + Simplifier le nom '{0}' @@ -2701,13 +2696,18 @@ Les assertions arrière positives de largeur nulle sont généralement utilisée - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - L'assembly d'analyseur '{0}' fait référence à la version '{1}' du compilateur, qui est plus récente que la version en cours d'exécution '{2}'. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + L'assembly d'analyseur '{0}' fait référence à la version '{1}' du compilateur, qui est plus récente que la version en cours d'exécution '{2}'. + + + + The query does not specify '{0}' top-level function + The query does not specify '{0}' top-level function - - The query does not specify '{0}' method or top-level function - La requête ne spécifie pas « {0} » méthode ou fonction de niveau supérieur + + The query specifies multiple top-level functions '{1}' + The query specifies multiple top-level functions '{1}' @@ -2750,11 +2750,21 @@ Les assertions arrière positives de largeur nulle sont généralement utilisée Trop de )'s This is an error message shown to the user when they write an invalid Regular Expression. Example: ) + + Top-level function '{0}' must have a single parameter + Top-level function '{0}' must have a single parameter + + Trailing comma not allowed Virgule de fin non autorisée + + Type '{0}' is not among supported types: {1} + Type '{0}' is not among supported types: {1} + + Types: Types : @@ -2767,7 +2777,7 @@ Les assertions arrière positives de largeur nulle sont généralement utilisée Unable to create '{0}' - Unable to create '{0}' + Impossible de créer « {0} » @@ -3478,7 +3488,7 @@ Si le spécificateur de format "H" est utilisé sans autres spécificateurs de f <class name> - <class name> + <class name> @@ -3664,7 +3674,7 @@ Le spécificateur de format standard "f" représente une combinaison des modèle <interface name> - <interface name> + <interface name> @@ -3787,7 +3797,7 @@ Si le spécificateur de format "M" est utilisé sans autres spécificateurs de f <namespace name> - <namespace name> + <namespace name> @@ -4817,7 +4827,7 @@ Version utilisée dans : {2} Add _null checks - Ajouter des contrôles de valeur null + Ajoutez des contrôles _null diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf index 76120583c5f41..d0b40fab387c4 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf @@ -147,17 +147,17 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Adding or moving {0} of {1} requires restarting the application. - Adding or moving {0} of {1} requires restarting the application. + Per aggiungere o spostare {0} di {1} è necessario riavviare l'applicazione. Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. - Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + Se si aggiunge o sposta {0} di {1} con layout esplicito o sequenziale, è necessario riavviare l'applicazione. Adding or moving {0} of a COM interface requires restarting the application. - Adding or moving {0} of a COM interface requires restarting the application. + Per aggiungere o spostare {0} di un'interfaccia COM è necessario riavviare l'applicazione. @@ -337,7 +337,7 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Cannot determine valid range of statements to extract - Cannot determine valid range of statements to extract + Non è possibile determinare l'intervallo valido di istruzioni da estrarre @@ -467,12 +467,12 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Changing the signature of {0} requires restarting the application. - Changing the signature of {0} requires restarting the application. + Se si modifica la firma di {0}, è necessario riavviare l'applicazione. Changing the signature of {0} requires restarting the application because is not supported by the runtime. - Changing the signature of {0} requires restarting the application because is not supported by the runtime. + Se si modifica la firma di {0}, è necessario riavviare l'applicazione perché l'operazione non è supportata dal runtime. @@ -537,7 +537,7 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Conflict(s) detected. - Conflict(s) detected. + Sono stati rilevati conflitti. @@ -857,7 +857,7 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Generate constructor from members... - Generate constructor from members... + Genera costruttore da membri... @@ -1100,11 +1100,6 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Il metodo '{0}' deve essere statico e non generico - - Method '{0}' must have a single parameter of type '{1}' and return '{2}' - Il metodo '{0}' deve avere un singolo parametro di tipo '{1}' e restituire '{2}' - - Miscellaneous Files File esterni @@ -1197,7 +1192,7 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Move declaration near reference (may change semantics) - Move declaration near reference (may change semantics) + Sposta la dichiarazione in prossimità del riferimento (può modificare la semantica) @@ -1272,12 +1267,12 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa No valid statement range to extract - No valid statement range to extract + Non esiste alcun intervallo di istruzioni valido per l'estrazione Not all code paths return - Not all code paths return + Non vengono restituiti tutti i percorsi del codice @@ -1327,7 +1322,7 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Pull '{0}' up to ... - Pull '{0}' up to ... + Esegui pull di '{0}' fino a... @@ -2617,12 +2612,12 @@ Le asserzioni lookbehind positive di larghezza zero vengono usate in genere all' Simplify member access '{0}' - Simplify member access '{0}' + Semplifica l'accesso dei membri '{0}' Simplify name '{0}' - Simplify name '{0}' + Semplifica il nome '{0}' @@ -2701,13 +2696,18 @@ Le asserzioni lookbehind positive di larghezza zero vengono usate in genere all' - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - L'assembly dell'analizzatore '{0}' fa riferimento alla versione '{1}' del compilatore, che è più recente della versione attualmente in esecuzione '{2}'. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + L'assembly dell'analizzatore '{0}' fa riferimento alla versione '{1}' del compilatore, che è più recente della versione attualmente in esecuzione '{2}'. + + + + The query does not specify '{0}' top-level function + The query does not specify '{0}' top-level function - - The query does not specify '{0}' method or top-level function - La query non specifica il metodo '{0}' o la funzione di primo livello + + The query specifies multiple top-level functions '{1}' + The query specifies multiple top-level functions '{1}' @@ -2750,11 +2750,21 @@ Le asserzioni lookbehind positive di larghezza zero vengono usate in genere all' Troppe parentesi di chiusura This is an error message shown to the user when they write an invalid Regular Expression. Example: ) + + Top-level function '{0}' must have a single parameter + Top-level function '{0}' must have a single parameter + + Trailing comma not allowed Virgola finale non consentita + + Type '{0}' is not among supported types: {1} + Type '{0}' is not among supported types: {1} + + Types: Tipi: @@ -2767,7 +2777,7 @@ Le asserzioni lookbehind positive di larghezza zero vengono usate in genere all' Unable to create '{0}' - Unable to create '{0}' + Non è stato possibile creare "{0}" @@ -3478,7 +3488,7 @@ Se l'identificatore di formato "H" viene usato senza altri identificatori di for <class name> - <class name> + <class name> @@ -3664,7 +3674,7 @@ L'identificatore di formato standard "f" rappresenta una combinazione degli sche <interface name> - <interface name> + <interface name> @@ -3787,7 +3797,7 @@ Se l'identificatore di formato "M" viene usato senza altri identificatori di for <namespace name> - <namespace name> + <namespace name> @@ -4817,7 +4827,7 @@ Questa versione è usata {2} Add _null checks - Aggiungi i controlli Null + Aggiungi controlli _null diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf index 432a95cb4cbf9..c5110c4b6d30c 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf @@ -147,17 +147,17 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Adding or moving {0} of {1} requires restarting the application. - Adding or moving {0} of {1} requires restarting the application. + {1} の {0} を追加または移動するには、アプリケーションを再起動する必要があります。 Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. - Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + 明示的またはシーケンシャルなレイアウトに、{1} の {0} を移動または追加するには、アプリケーションを再起動する必要があります。 Adding or moving {0} of a COM interface requires restarting the application. - Adding or moving {0} of a COM interface requires restarting the application. + COM インターフェイスの {0} を追加または移動するには、アプリケーションを再起動する必要があります。 @@ -337,7 +337,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Cannot determine valid range of statements to extract - Cannot determine valid range of statements to extract + 抽出するステートメントの有効な範囲を決定できません @@ -467,12 +467,12 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Changing the signature of {0} requires restarting the application. - Changing the signature of {0} requires restarting the application. + {0} の署名を変更するには、アプリケーションを再起動する必要があります。 Changing the signature of {0} requires restarting the application because is not supported by the runtime. - Changing the signature of {0} requires restarting the application because is not supported by the runtime. + ランタイムでサポートされていないため、{0} をの署名を変更するには、アプリケーションを再起動する必要があります。 @@ -537,7 +537,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Conflict(s) detected. - Conflict(s) detected. + 競合が検出されました。 @@ -857,7 +857,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Generate constructor from members... - Generate constructor from members... + メンバーからコンストラクターを生成... @@ -1100,11 +1100,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma メソッド '{0}' は静的かつ非ジェネリックである必要があります - - Method '{0}' must have a single parameter of type '{1}' and return '{2}' - メソッド '{0}' では、型が '{1}' のパラメーターを 1 つ設定し、'{2}' を返す必要があります - - Miscellaneous Files その他のファイル @@ -1197,7 +1192,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Move declaration near reference (may change semantics) - Move declaration near reference (may change semantics) + 宣言を参照の近くに移動します (セマンティクスが変更される可能性があります) @@ -1272,12 +1267,12 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma No valid statement range to extract - No valid statement range to extract + 抽出する有効なステートメントの範囲がありません Not all code paths return - Not all code paths return + 返されないコード パスがあります @@ -1327,7 +1322,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Pull '{0}' up to ... - Pull '{0}' up to ... + '{0}' をプルする最大数... @@ -2617,12 +2612,12 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Simplify member access '{0}' - Simplify member access '{0}' + メンバーのアクセス '{0}' を単純化します Simplify name '{0}' - Simplify name '{0}' + 名前 '{0}' の単純化 @@ -2701,13 +2696,18 @@ Zero-width positive lookbehind assertions are typically used at the beginning of - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - アナライザー アセンブリ '{0}' は、コンパイラのバージョン '{1}' を参照しています。これは、現在実行中のバージョン '{2}' よりも新しいバージョンです。 + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + アナライザー アセンブリ '{0}' は、コンパイラのバージョン '{1}' を参照しています。これは、現在実行中のバージョン '{2}' よりも新しいバージョンです。 + + + + The query does not specify '{0}' top-level function + The query does not specify '{0}' top-level function - - The query does not specify '{0}' method or top-level function - クエリで、'{0}' メソッドまたは上位レベルの関数が指定されていません + + The query specifies multiple top-level functions '{1}' + The query specifies multiple top-level functions '{1}' @@ -2750,11 +2750,21 @@ Zero-width positive lookbehind assertions are typically used at the beginning of ) が多すぎます This is an error message shown to the user when they write an invalid Regular Expression. Example: ) + + Top-level function '{0}' must have a single parameter + Top-level function '{0}' must have a single parameter + + Trailing comma not allowed 末尾にコンマは使用できない + + Type '{0}' is not among supported types: {1} + Type '{0}' is not among supported types: {1} + + Types: 型: @@ -2767,7 +2777,7 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Unable to create '{0}' - Unable to create '{0}' + '{0}' を作成できません @@ -3478,7 +3488,7 @@ If the "H" format specifier is used without other custom format specifiers, it's <class name> - <class name> + <class name> @@ -3664,7 +3674,7 @@ The "f" standard format specifier represents a combination of the long date ("D" <interface name> - <interface name> + <interface name> @@ -3787,7 +3797,7 @@ If the "M" format specifier is used without other custom format specifiers, it's <namespace name> - <namespace name> + <namespace name> @@ -4817,7 +4827,7 @@ This version used in: {2} Add _null checks - null チェックを追加する + _null チェックを追加 diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf index 355563e2fc89f..80bf56020bc1e 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf @@ -147,17 +147,17 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Adding or moving {0} of {1} requires restarting the application. - Adding or moving {0} of {1} requires restarting the application. + {1} {0} 추가하거나 이동하려면 응용 프로그램을 다시 시작해야 합니다. Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. - Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + 명시적 또는 순차적 레이아웃으로 {1}개 중 {0}개를 추가하거나 이동하려면 응용 프로그램을 다시 시작해야 합니다. Adding or moving {0} of a COM interface requires restarting the application. - Adding or moving {0} of a COM interface requires restarting the application. + COM 인터페이스의 {0} 추가하거나 이동하려면 응용 프로그램을 다시 시작해야 합니다. @@ -337,7 +337,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Cannot determine valid range of statements to extract - Cannot determine valid range of statements to extract + 추출할 문의 유효한 범위를 결정할 수 없습니다. @@ -467,12 +467,12 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Changing the signature of {0} requires restarting the application. - Changing the signature of {0} requires restarting the application. + {0} 서명을 변경하려면 애플리케이션을 다시 시작해야 합니다. Changing the signature of {0} requires restarting the application because is not supported by the runtime. - Changing the signature of {0} requires restarting the application because is not supported by the runtime. + 런타임에서 지원하지 않기 때문에 {0} 서명을 변경하려면 애플리케이션을 다시 시작해야 합니다. @@ -537,7 +537,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Conflict(s) detected. - Conflict(s) detected. + 충돌이 감지되었습니다. @@ -857,7 +857,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Generate constructor from members... - Generate constructor from members... + 멤버에서 생성자 생성... @@ -1100,11 +1100,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 메서드 '{0}'은(는) 정적이어야 하며 제네릭이 아니어야 합니다. - - Method '{0}' must have a single parameter of type '{1}' and return '{2}' - 메서드 '{0}'은(는) '{1}' 형식의 단일 매개 변수가 있어야 하며 '{2}'을(를) 반환해야 합니다. - - Miscellaneous Files 기타 파일 @@ -1197,7 +1192,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Move declaration near reference (may change semantics) - Move declaration near reference (may change semantics) + 선언을 참조 근처로 이동(의미 체계가 변경될 수 있음) @@ -1272,12 +1267,12 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma No valid statement range to extract - No valid statement range to extract + 추출하는 데 유효한 문 범위가 없습니다. Not all code paths return - Not all code paths return + 일부 코드 경로가 반환됩니다. @@ -1327,7 +1322,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Pull '{0}' up to ... - Pull '{0}' up to ... + '{0}'을(를) 다음으로 끌어오기... @@ -2617,12 +2612,12 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Simplify member access '{0}' - Simplify member access '{0}' + 멤버 액세스 '{0}' 단순화 Simplify name '{0}' - Simplify name '{0}' + '{0}' 이름 단순화 @@ -2701,13 +2696,18 @@ Zero-width positive lookbehind assertions are typically used at the beginning of - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - 분석기 어셈블리 '{0}'은(는) 컴파일러의 '{1}' 버전을 참조하며, 이 버전은 현재 실행 중인 버전 '{2}'보다 최신 버전입니다. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + 분석기 어셈블리 '{0}'은(는) 컴파일러의 '{1}' 버전을 참조하며, 이 버전은 현재 실행 중인 버전 '{2}'보다 최신 버전입니다. + + + + The query does not specify '{0}' top-level function + The query does not specify '{0}' top-level function - - The query does not specify '{0}' method or top-level function - 쿼리가 '{0}' 메서드 또는 최상위 함수를 지정하지 않습니다. + + The query specifies multiple top-level functions '{1}' + The query specifies multiple top-level functions '{1}' @@ -2750,11 +2750,21 @@ Zero-width positive lookbehind assertions are typically used at the beginning of )가 너무 많습니다. This is an error message shown to the user when they write an invalid Regular Expression. Example: ) + + Top-level function '{0}' must have a single parameter + Top-level function '{0}' must have a single parameter + + Trailing comma not allowed 후행 쉼표는 허용되지 않습니다. + + Type '{0}' is not among supported types: {1} + Type '{0}' is not among supported types: {1} + + Types: 형식: @@ -2767,7 +2777,7 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Unable to create '{0}' - Unable to create '{0}' + {0}(을)를 만들 수 없음 @@ -3478,7 +3488,7 @@ If the "H" format specifier is used without other custom format specifiers, it's <class name> - <class name> + <class name> @@ -3664,7 +3674,7 @@ The "f" standard format specifier represents a combination of the long date ("D" <interface name> - <interface name> + <interface name> @@ -3787,7 +3797,7 @@ If the "M" format specifier is used without other custom format specifiers, it's <namespace name> - <namespace name> + <namespace name> @@ -4817,7 +4827,7 @@ This version used in: {2} Add _null checks - null 검사 추가 + _null 검사 추가 diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf index aa4dadb24f4aa..4086c13937cb8 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf @@ -147,17 +147,17 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Adding or moving {0} of {1} requires restarting the application. - Adding or moving {0} of {1} requires restarting the application. + Dodanie lub przeniesienie {0} {1} wymaga ponownego uruchomienia aplikacji. Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. - Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + Dodanie lub przeniesienie {0} z {1} wraz z układem jawnym lub sekwencyjnym wymaga ponownego uruchomienia aplikacji. Adding or moving {0} of a COM interface requires restarting the application. - Adding or moving {0} of a COM interface requires restarting the application. + Dodanie lub przeniesienie {0} interfejsu COM wymaga ponownego uruchomienia aplikacji. @@ -337,7 +337,7 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Cannot determine valid range of statements to extract - Cannot determine valid range of statements to extract + Nie można określić prawidłowego zakresu instrukcji do wyodrębnienia @@ -467,12 +467,12 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Changing the signature of {0} requires restarting the application. - Changing the signature of {0} requires restarting the application. + Zmiana podpisu {0} wymaga ponownego uruchomienia aplikacji. Changing the signature of {0} requires restarting the application because is not supported by the runtime. - Changing the signature of {0} requires restarting the application because is not supported by the runtime. + Zmienianie podpisu {0} wymaga ponownego uruchomienia aplikacji, ponieważ nie jest to obsługiwane przez środowisko uruchomieniowe. @@ -537,7 +537,7 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Conflict(s) detected. - Conflict(s) detected. + Wykryto konflikty. @@ -857,7 +857,7 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Generate constructor from members... - Generate constructor from members... + Generuj konstruktor na podstawie składowych... @@ -1100,11 +1100,6 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Metoda „{0}” musi być statyczna i nieogólna - - Method '{0}' must have a single parameter of type '{1}' and return '{2}' - Metoda „{0}” musi mieć jeden parametr typu „{1}” i zwracać wartość „{2}” - - Miscellaneous Files Różne pliki @@ -1197,7 +1192,7 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Move declaration near reference (may change semantics) - Move declaration near reference (may change semantics) + Przenieś deklarację w pobliżu odwołania (może zmienić semantykę) @@ -1272,12 +1267,12 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k No valid statement range to extract - No valid statement range to extract + Brak prawidłowego zakresu instrukcji do wyodrębnienia Not all code paths return - Not all code paths return + Nie wszystkie ścieżki w kodzie zwracają wartość @@ -1327,7 +1322,7 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Pull '{0}' up to ... - Pull '{0}' up to ... + Ściągnij elementy „{0}” aż do... @@ -2617,12 +2612,12 @@ Pozytywne asercje wsteczne o zerowej szerokości są zwykle używane na początk Simplify member access '{0}' - Simplify member access '{0}' + Uprość dostęp do składowej „{0}” Simplify name '{0}' - Simplify name '{0}' + Uprość nazwę „{0}” @@ -2701,13 +2696,18 @@ Pozytywne asercje wsteczne o zerowej szerokości są zwykle używane na początk - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - Zestaw analizatora „{0}” odwołuje się do wersji „{1}” kompilatora, która jest nowsza niż obecnie uruchomiona wersja „{2}”. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + Zestaw analizatora „{0}” odwołuje się do wersji „{1}” kompilatora, która jest nowsza niż obecnie uruchomiona wersja „{2}”. + + + + The query does not specify '{0}' top-level function + The query does not specify '{0}' top-level function - - The query does not specify '{0}' method or top-level function - Zapytanie nie określa metody „{0}” ani funkcji najwyższego poziomu + + The query specifies multiple top-level functions '{1}' + The query specifies multiple top-level functions '{1}' @@ -2750,11 +2750,21 @@ Pozytywne asercje wsteczne o zerowej szerokości są zwykle używane na początk Zbyt wiele znaków ) This is an error message shown to the user when they write an invalid Regular Expression. Example: ) + + Top-level function '{0}' must have a single parameter + Top-level function '{0}' must have a single parameter + + Trailing comma not allowed Końcowy przecinek jest niedozwolony. + + Type '{0}' is not among supported types: {1} + Type '{0}' is not among supported types: {1} + + Types: Typy: @@ -2767,7 +2777,7 @@ Pozytywne asercje wsteczne o zerowej szerokości są zwykle używane na początk Unable to create '{0}' - Unable to create '{0}' + Nie można utworzyć „{0}” @@ -3478,7 +3488,7 @@ Jeśli specyfikator formatu „H” zostanie użyty bez innych indywidualnych sp <class name> - <class name> + <class name> @@ -3664,7 +3674,7 @@ Standardowy specyfikator formatu „f” reprezentuje połączenie wzorców dłu <interface name> - <interface name> + <interface name> @@ -3787,7 +3797,7 @@ Jeśli specyfikator formatu „M” jest używany bez innych niestandardowych sp <namespace name> - <namespace name> + <namespace name> @@ -4817,7 +4827,7 @@ Ta wersja jest używana wersja: {2} Add _null checks - Dodaj sprawdzenia wartości null + Dodaj sprawdzenia wartości _null diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf index c66c51062e0c4..d3487bb3dd06f 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf @@ -147,17 +147,17 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Adding or moving {0} of {1} requires restarting the application. - Adding or moving {0} of {1} requires restarting the application. + Adicionar ou mover {0} de {1} requer a reinicialização do aplicativo. Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. - Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + Adicionar ou migrar {0} de {1} com layout explícito ou sequencial requer a reinicialização do aplicativo. Adding or moving {0} of a COM interface requires restarting the application. - Adding or moving {0} of a COM interface requires restarting the application. + Adicionar ou mover {0} de uma interface COM requer a reinicialização do aplicativo. @@ -337,7 +337,7 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Cannot determine valid range of statements to extract - Cannot determine valid range of statements to extract + Não é possível determinar o intervalo válido de instruções a serem extraídas @@ -467,12 +467,12 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Changing the signature of {0} requires restarting the application. - Changing the signature of {0} requires restarting the application. + Alterar a assinatura de {0} requer a reinicialização do aplicativo. Changing the signature of {0} requires restarting the application because is not supported by the runtime. - Changing the signature of {0} requires restarting the application because is not supported by the runtime. + A alteração da assinatura de {0} requer a reinicialização do aplicativo porque não há suporte com o tempo de execução. @@ -537,7 +537,7 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Conflict(s) detected. - Conflict(s) detected. + Conflito(s) detectado(s). @@ -857,7 +857,7 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Generate constructor from members... - Generate constructor from members... + Gerar construtor a partir de membros... @@ -1100,11 +1100,6 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess O método '{0}' deve ser estático e não genérico - - Method '{0}' must have a single parameter of type '{1}' and return '{2}' - O método '{0}' deve ter um único parâmetro do tipo '{1}' e retornar '{2}' - - Miscellaneous Files Arquivos Diversos @@ -1197,7 +1192,7 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Move declaration near reference (may change semantics) - Move declaration near reference (may change semantics) + Mover declaração para perto da referência (pode alterar a semântica) @@ -1272,12 +1267,12 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess No valid statement range to extract - No valid statement range to extract + Nenhum intervalo de instruções válido para extrair Not all code paths return - Not all code paths return + Nem todos os caminhos de código são retornados @@ -1327,7 +1322,7 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Pull '{0}' up to ... - Pull '{0}' up to ... + Efetuar pull de "{0}" até... @@ -2617,12 +2612,12 @@ As declarações de lookbehind positivas de largura zero normalmente são usadas Simplify member access '{0}' - Simplify member access '{0}' + Simplificar acesso do membro '{0}' Simplify name '{0}' - Simplify name '{0}' + Simplificar nome '{0}' @@ -2701,13 +2696,18 @@ As declarações de lookbehind positivas de largura zero normalmente são usadas - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - O assembly do analisador '{0}' referencia a versão '{1}' do compilador, que é mais recente que a versão em execução no momento '{2}'. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + O assembly do analisador '{0}' referencia a versão '{1}' do compilador, que é mais recente que a versão em execução no momento '{2}'. + + + + The query does not specify '{0}' top-level function + The query does not specify '{0}' top-level function - - The query does not specify '{0}' method or top-level function - A consulta não especifica o método '{0}' ou a função de nível superior + + The query specifies multiple top-level functions '{1}' + The query specifies multiple top-level functions '{1}' @@ -2750,11 +2750,21 @@ As declarações de lookbehind positivas de largura zero normalmente são usadas Muitos )'s This is an error message shown to the user when they write an invalid Regular Expression. Example: ) + + Top-level function '{0}' must have a single parameter + Top-level function '{0}' must have a single parameter + + Trailing comma not allowed Vírgula à direita não permitida + + Type '{0}' is not among supported types: {1} + Type '{0}' is not among supported types: {1} + + Types: Tipos: @@ -2767,7 +2777,7 @@ As declarações de lookbehind positivas de largura zero normalmente são usadas Unable to create '{0}' - Unable to create '{0}' + Não é possível criar '{0}' @@ -3478,7 +3488,7 @@ Se o especificador de formato "H" for usado sem outros especificadores de format <class name> - <class name> + <nome da classe> @@ -3664,7 +3674,7 @@ O especificador de formato padrão "f" representa uma combinação de padrões d <interface name> - <interface name> + <nome da interface> @@ -3787,7 +3797,7 @@ Se o especificador de formato "M" for usado sem outros especificadores de format <namespace name> - <namespace name> + <nome do namespace> @@ -4817,7 +4827,7 @@ Essa versão é usada no: {2} Add _null checks - Adicionar verificações nulas + Adicionar verificações _null diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf index ab241c6db2a39..f83713c17fb83 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf @@ -147,17 +147,17 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Adding or moving {0} of {1} requires restarting the application. - Adding or moving {0} of {1} requires restarting the application. + Добавление или {0} {1} требует перезапуска приложения. Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. - Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + Добавление или перемещение {0} из {1} с явной или последовательной компоновкой требует перезапуска приложения. Adding or moving {0} of a COM interface requires restarting the application. - Adding or moving {0} of a COM interface requires restarting the application. + Чтобы добавить или {0} com-интерфейса, необходимо перезапустить приложение. @@ -337,7 +337,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Cannot determine valid range of statements to extract - Cannot determine valid range of statements to extract + Невозможно определить допустимый диапазон операторов для извлечения @@ -467,12 +467,12 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Changing the signature of {0} requires restarting the application. - Changing the signature of {0} requires restarting the application. + Изменение подписи {0} требует перезапуска приложения. Changing the signature of {0} requires restarting the application because is not supported by the runtime. - Changing the signature of {0} requires restarting the application because is not supported by the runtime. + Для изменения подписи {0} требуется перезапустить приложение, так как это не поддерживается средой выполнения. @@ -537,7 +537,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Conflict(s) detected. - Conflict(s) detected. + Обнаружены конфликты. @@ -857,7 +857,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Generate constructor from members... - Generate constructor from members... + Создать конструктор из элементов... @@ -1100,11 +1100,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Метод "{0}" должен быть статическим и неуниверсалным - - Method '{0}' must have a single parameter of type '{1}' and return '{2}' - Метод "{0}" должен иметь один параметр типа "{1}" и возвращать "{2}" - - Miscellaneous Files Прочие файлы @@ -1197,7 +1192,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Move declaration near reference (may change semantics) - Move declaration near reference (may change semantics) + Переместить объявление рядом со ссылкой (может изменить семантику) @@ -1272,12 +1267,12 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma No valid statement range to extract - No valid statement range to extract + Отсутствует допустимый диапазон операторов для извлечения Not all code paths return - Not all code paths return + Не все пути к коду возвращают значения @@ -1327,7 +1322,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Pull '{0}' up to ... - Pull '{0}' up to ... + Извлечь "{0}" до ... @@ -2617,12 +2612,12 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Simplify member access '{0}' - Simplify member access '{0}' + Упрощение доступа для членов "{0}" Simplify name '{0}' - Simplify name '{0}' + Упрощение имени "{0}" @@ -2701,13 +2696,18 @@ Zero-width positive lookbehind assertions are typically used at the beginning of - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - Сборка анализатора "{0}" ссылается на версию "{1}" компилятора, являющуюся более новой, чем версия "{2}". + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + Сборка анализатора "{0}" ссылается на версию "{1}" компилятора, являющуюся более новой, чем версия "{2}". + + + + The query does not specify '{0}' top-level function + The query does not specify '{0}' top-level function - - The query does not specify '{0}' method or top-level function - В запросе не указан метод "{0}" или функция верхнего уровня + + The query specifies multiple top-level functions '{1}' + The query specifies multiple top-level functions '{1}' @@ -2750,11 +2750,21 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Слишком много закрывающих круглых скобок This is an error message shown to the user when they write an invalid Regular Expression. Example: ) + + Top-level function '{0}' must have a single parameter + Top-level function '{0}' must have a single parameter + + Trailing comma not allowed Завершающая запятая не разрешена + + Type '{0}' is not among supported types: {1} + Type '{0}' is not among supported types: {1} + + Types: Типы: @@ -2767,7 +2777,7 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Unable to create '{0}' - Unable to create '{0}' + Не удается создать "{0}" @@ -3478,7 +3488,7 @@ If the "H" format specifier is used without other custom format specifiers, it's <class name> - <class name> + <имя класса> @@ -3664,7 +3674,7 @@ The "f" standard format specifier represents a combination of the long date ("D" <interface name> - <interface name> + <имя интерфейса> @@ -3787,7 +3797,7 @@ If the "M" format specifier is used without other custom format specifiers, it's <namespace name> - <namespace name> + <имя пространства имен> @@ -4817,7 +4827,7 @@ This version used in: {2} Add _null checks - Добавить проверки значений NULL + Добавить проверки значений _null diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf index ad6a0b9a037bb..76137f8e96d3a 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf @@ -147,17 +147,17 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be Adding or moving {0} of {1} requires restarting the application. - Adding or moving {0} of {1} requires restarting the application. + Uygulamanın bir {0} veya {1} uygulamanın yeniden başlatılmasını gerektirir. Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. - Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + Açık veya sıralı düzene sahip {1} türünde {0}eklemek veya taşımak, uygulamanın yeniden başlatılmasını gerektirir. Adding or moving {0} of a COM interface requires restarting the application. - Adding or moving {0} of a COM interface requires restarting the application. + COM arabiriminin {0} veya taşıma işlemi uygulamanın yeniden başlatılmasını gerektirir. @@ -337,7 +337,7 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be Cannot determine valid range of statements to extract - Cannot determine valid range of statements to extract + Ayıklanacak geçerli deyim aralığı belirlenemedi @@ -467,12 +467,12 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be Changing the signature of {0} requires restarting the application. - Changing the signature of {0} requires restarting the application. + {0} imzasının değiştirilmesi, uygulamanın yeniden başlatılmasını gerektirir. Changing the signature of {0} requires restarting the application because is not supported by the runtime. - Changing the signature of {0} requires restarting the application because is not supported by the runtime. + {0} imzasının silinmesi, çalışma zamanı tarafından desteklenmediğinden uygulamanın yeniden başlatılmasını gerektirir. @@ -537,7 +537,7 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be Conflict(s) detected. - Conflict(s) detected. + Çakışmalar algılandı. @@ -857,7 +857,7 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be Generate constructor from members... - Generate constructor from members... + Üyelerden oluşturucu oluştur... @@ -1100,11 +1100,6 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be '{0}' yönteminin statik olması ve genel olmaması gerekir. - - Method '{0}' must have a single parameter of type '{1}' and return '{2}' - '{0}' yönteminin '{1}' türünde tek bir parametre olması ve '{2}' değerini döndürmesi gerekir - - Miscellaneous Files Diğer Dosyalar @@ -1197,7 +1192,7 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be Move declaration near reference (may change semantics) - Move declaration near reference (may change semantics) + Bildirimi başvuruya yakın bir değere taşı (semantiği değiştirebilir) @@ -1272,12 +1267,12 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be No valid statement range to extract - No valid statement range to extract + Ayıklanacak geçerli deyim aralığı yok Not all code paths return - Not all code paths return + Kod yollarından bazıları dönmüyor @@ -1327,7 +1322,7 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be Pull '{0}' up to ... - Pull '{0}' up to ... + '{0}' öğesini çek... @@ -2617,12 +2612,12 @@ Sıfır genişlikli pozitif geri yönlü onaylamalar genellikle normal ifadeleri Simplify member access '{0}' - Simplify member access '{0}' + '{0}' üye erişimini basitleştir Simplify name '{0}' - Simplify name '{0}' + '{0}' adını basitleştir @@ -2701,13 +2696,18 @@ Sıfır genişlikli pozitif geri yönlü onaylamalar genellikle normal ifadeleri - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - '{0}' çözümleyici bütünleştirilmiş kodu, derleyicinin şu anda çalışan '{2}' sürümünden daha yeni olan '{1}' sürümüne başvurur. + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + '{0}' çözümleyici bütünleştirilmiş kodu, derleyicinin şu anda çalışan '{2}' sürümünden daha yeni olan '{1}' sürümüne başvurur. + + + + The query does not specify '{0}' top-level function + The query does not specify '{0}' top-level function - - The query does not specify '{0}' method or top-level function - Sorgu '{0}' yöntemini veya üst düzey işlev belirtmiyor + + The query specifies multiple top-level functions '{1}' + The query specifies multiple top-level functions '{1}' @@ -2750,11 +2750,21 @@ Sıfır genişlikli pozitif geri yönlü onaylamalar genellikle normal ifadeleri Çok fazla)'s This is an error message shown to the user when they write an invalid Regular Expression. Example: ) + + Top-level function '{0}' must have a single parameter + Top-level function '{0}' must have a single parameter + + Trailing comma not allowed Sona eklenen virgüle izin verilmiyor + + Type '{0}' is not among supported types: {1} + Type '{0}' is not among supported types: {1} + + Types: Türler: @@ -2767,7 +2777,7 @@ Sıfır genişlikli pozitif geri yönlü onaylamalar genellikle normal ifadeleri Unable to create '{0}' - Unable to create '{0}' + '{0}' oluşturulamıyor @@ -3478,7 +3488,7 @@ If the "H" format specifier is used without other custom format specifiers, it's <class name> - <class name> + <sınıf adı> @@ -3664,7 +3674,7 @@ The "f" standard format specifier represents a combination of the long date ("D" <interface name> - <interface name> + <arabirim adı> @@ -3787,7 +3797,7 @@ If the "M" format specifier is used without other custom format specifiers, it's <namespace name> - <namespace name> + <ad alanı adı> @@ -4817,7 +4827,7 @@ Bu sürüm şurada kullanılır: {2} Add _null checks - Null denetimleri ekle + _Null denetimleri ekle diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf index 7349eca4fb7b5..dc56299ba8c2f 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf @@ -147,17 +147,17 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Adding or moving {0} of {1} requires restarting the application. - Adding or moving {0} of {1} requires restarting the application. + 添加或移动 {1} {0} 需要重启应用程序。 Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. - Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + 添加或移动具有显示或顺序布局的 {1} 的 {0} 需要重启应用程序。 Adding or moving {0} of a COM interface requires restarting the application. - Adding or moving {0} of a COM interface requires restarting the application. + 添加或移动 COM 接口 {0} 需要重启应用程序。 @@ -337,7 +337,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Cannot determine valid range of statements to extract - Cannot determine valid range of statements to extract + 无法确定要提取的语句的有效范围 @@ -467,12 +467,12 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Changing the signature of {0} requires restarting the application. - Changing the signature of {0} requires restarting the application. + 更改 {0} 的签名需要重启应用程序。 Changing the signature of {0} requires restarting the application because is not supported by the runtime. - Changing the signature of {0} requires restarting the application because is not supported by the runtime. + 更改 {0} 的签名需要重新启动应用程序,因为不受运行时支持。 @@ -537,7 +537,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Conflict(s) detected. - Conflict(s) detected. + 检测到冲突。 @@ -857,7 +857,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Generate constructor from members... - Generate constructor from members... + 从成员生成构造函数... @@ -1100,11 +1100,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 方法“{0}”必须是静态的和非泛型的 - - Method '{0}' must have a single parameter of type '{1}' and return '{2}' - 方法“{0}”必须具有类型“{1}”的单个参数并返回“{2}” - - Miscellaneous Files 杂项文件 @@ -1197,7 +1192,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Move declaration near reference (may change semantics) - Move declaration near reference (may change semantics) + 在引用 (附近移动声明可能会更改语义) @@ -1272,12 +1267,12 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma No valid statement range to extract - No valid statement range to extract + 没有可供提取的有效语句范围 Not all code paths return - Not all code paths return + 未返回所有代码路径 @@ -1327,7 +1322,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Pull '{0}' up to ... - Pull '{0}' up to ... + 将“{0}”拉取到... @@ -2617,12 +2612,12 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Simplify member access '{0}' - Simplify member access '{0}' + 简化成员访问“{0}” Simplify name '{0}' - Simplify name '{0}' + 简化名称“{0}” @@ -2701,13 +2696,18 @@ Zero-width positive lookbehind assertions are typically used at the beginning of - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - 分析器程序集“{0}”引用了编译器的版本“{1}”,该版本高于当前正在运行的版本“{2}”。 + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + 分析器程序集“{0}”引用了编译器的版本“{1}”,该版本高于当前正在运行的版本“{2}”。 + + + + The query does not specify '{0}' top-level function + The query does not specify '{0}' top-level function - - The query does not specify '{0}' method or top-level function - 查询未指定方法“{0}”或顶级函数 + + The query specifies multiple top-level functions '{1}' + The query specifies multiple top-level functions '{1}' @@ -2750,11 +2750,21 @@ Zero-width positive lookbehind assertions are typically used at the beginning of ")" 太多 This is an error message shown to the user when they write an invalid Regular Expression. Example: ) + + Top-level function '{0}' must have a single parameter + Top-level function '{0}' must have a single parameter + + Trailing comma not allowed 不允许使用尾随逗号 + + Type '{0}' is not among supported types: {1} + Type '{0}' is not among supported types: {1} + + Types: 类型: @@ -2767,7 +2777,7 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Unable to create '{0}' - Unable to create '{0}' + 无法创建“{0}” @@ -3478,7 +3488,7 @@ If the "H" format specifier is used without other custom format specifiers, it's <class name> - <class name> + <class name> @@ -3664,7 +3674,7 @@ The "f" standard format specifier represents a combination of the long date ("D" <interface name> - <interface name> + <interface name> @@ -3787,7 +3797,7 @@ If the "M" format specifier is used without other custom format specifiers, it's <namespace name> - <namespace name> + <namespace name> @@ -4817,7 +4827,7 @@ This version used in: {2} Add _null checks - 添加 null 检查 + 添加 null 检查(_N) diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf index 8bc9eb2f3feab..6267639a72c23 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf @@ -147,17 +147,17 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Adding or moving {0} of {1} requires restarting the application. - Adding or moving {0} of {1} requires restarting the application. + 新增或移動 {1} {0} 需要重新啟動應用程式。 Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. - Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + 使用明確或循序配置新增或移動 {1} 的 {0} 需要重新啟動應用程式。 Adding or moving {0} of a COM interface requires restarting the application. - Adding or moving {0} of a COM interface requires restarting the application. + 新增或移動 COM 介面的 {0} 需要重新啟動應用程式。 @@ -337,7 +337,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Cannot determine valid range of statements to extract - Cannot determine valid range of statements to extract + 無法判斷要擷取的有效陳述式範圍 @@ -467,12 +467,12 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Changing the signature of {0} requires restarting the application. - Changing the signature of {0} requires restarting the application. + 變更 {0} 的簽章需要重新啟動應用程式。 Changing the signature of {0} requires restarting the application because is not supported by the runtime. - Changing the signature of {0} requires restarting the application because is not supported by the runtime. + 變更 {0} 的簽章需要重新啟動應用程式,因為執行階段不支援它。 @@ -537,7 +537,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Conflict(s) detected. - Conflict(s) detected. + 偵測到衝突。 @@ -857,7 +857,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Generate constructor from members... - Generate constructor from members... + 從成員產生建構函式... @@ -1100,11 +1100,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 方法 '{0}' 必須是靜態和非泛型 - - Method '{0}' must have a single parameter of type '{1}' and return '{2}' - 方法 '{0}' 必須具有類型為 '{1}' 的單一參數,並傳回 '{2}' - - Miscellaneous Files 其他檔案 @@ -1197,7 +1192,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Move declaration near reference (may change semantics) - Move declaration near reference (may change semantics) + 移動宣告附近參考 (可能會變更語意) @@ -1272,12 +1267,12 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma No valid statement range to extract - No valid statement range to extract + 沒有可擷取的有效陳述式範圍 Not all code paths return - Not all code paths return + 未傳回所有程式碼路徑 @@ -1327,7 +1322,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Pull '{0}' up to ... - Pull '{0}' up to ... + 將 '{0}' 提取至 ... @@ -2617,12 +2612,12 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Simplify member access '{0}' - Simplify member access '{0}' + 簡化成員存取 '{0}' Simplify name '{0}' - Simplify name '{0}' + 簡化名稱 '{0}' @@ -2701,13 +2696,18 @@ Zero-width positive lookbehind assertions are typically used at the beginning of - The analyzer assembly '{0}' references version '{1}' of the compiler, which is newer than the currently running version '{2}'. - 分析程式組件 '{0}' 參考編譯器的版本 '{1}' ,比目前執行的版本 '{2}' 還要新。 + Analyzer assembly '{0}' cannot be used because it references version '{1}' of the compiler, which is newer than the currently running version '{2}'. + 分析程式組件 '{0}' 參考編譯器的版本 '{1}' ,比目前執行的版本 '{2}' 還要新。 + + + + The query does not specify '{0}' top-level function + The query does not specify '{0}' top-level function - - The query does not specify '{0}' method or top-level function - 查詢未指定 '{0}' 方法或頂層函式 + + The query specifies multiple top-level functions '{1}' + The query specifies multiple top-level functions '{1}' @@ -2750,11 +2750,21 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 太多 ) This is an error message shown to the user when they write an invalid Regular Expression. Example: ) + + Top-level function '{0}' must have a single parameter + Top-level function '{0}' must have a single parameter + + Trailing comma not allowed 尾端不得為逗號 + + Type '{0}' is not among supported types: {1} + Type '{0}' is not among supported types: {1} + + Types: 類型: @@ -2767,7 +2777,7 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Unable to create '{0}' - Unable to create '{0}' + 無法建立 '{0}' @@ -3478,7 +3488,7 @@ If the "H" format specifier is used without other custom format specifiers, it's <class name> - <class name> + <class name> @@ -3664,7 +3674,7 @@ The "f" standard format specifier represents a combination of the long date ("D" <interface name> - <interface name> + <interface name> @@ -3787,7 +3797,7 @@ If the "M" format specifier is used without other custom format specifiers, it's <namespace name> - <namespace name> + <namespace name> @@ -4817,7 +4827,7 @@ This version used in: {2} Add _null checks - 新增 null 檢查 + 新增 _null 檢查 diff --git a/src/Features/DiagnosticsTestUtilities/CodeActions/CSharpCodeFixVerifier`2+Test.cs b/src/Features/DiagnosticsTestUtilities/CodeActions/CSharpCodeFixVerifier`2+Test.cs index 37288f531803f..bedf0d8515caa 100644 --- a/src/Features/DiagnosticsTestUtilities/CodeActions/CSharpCodeFixVerifier`2+Test.cs +++ b/src/Features/DiagnosticsTestUtilities/CodeActions/CSharpCodeFixVerifier`2+Test.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Net; @@ -15,7 +14,6 @@ using Microsoft.CodeAnalysis.CSharp.Testing; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Testing; -using Microsoft.CodeAnalysis.Text; using Xunit; #if !CODE_STYLE @@ -70,6 +68,9 @@ public Test() [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] public new string FixedCode { set => base.FixedCode = value; } + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] + public new string BatchFixedCode { set => base.BatchFixedCode = value; } + /// public string? EditorConfig { diff --git a/src/Features/DiagnosticsTestUtilities/CodeActions/CSharpCodeRefactoringVerifier`1+Test.cs b/src/Features/DiagnosticsTestUtilities/CodeActions/CSharpCodeRefactoringVerifier`1+Test.cs index 2585055daa8dc..81f4d7e50dfe9 100644 --- a/src/Features/DiagnosticsTestUtilities/CodeActions/CSharpCodeRefactoringVerifier`1+Test.cs +++ b/src/Features/DiagnosticsTestUtilities/CodeActions/CSharpCodeRefactoringVerifier`1+Test.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Testing; using Microsoft.CodeAnalysis.Testing; -using Microsoft.CodeAnalysis.Testing.Verifiers; using System.Diagnostics.CodeAnalysis; #if !CODE_STYLE diff --git a/src/Features/DiagnosticsTestUtilities/CodeActions/SharedVerifierState.cs b/src/Features/DiagnosticsTestUtilities/CodeActions/SharedVerifierState.cs index 7a8ddc3c69d2e..e340cfeee417a 100644 --- a/src/Features/DiagnosticsTestUtilities/CodeActions/SharedVerifierState.cs +++ b/src/Features/DiagnosticsTestUtilities/CodeActions/SharedVerifierState.cs @@ -4,8 +4,6 @@ using System; using Microsoft.CodeAnalysis.Testing; -using Microsoft.CodeAnalysis.Testing.Verifiers; -using Microsoft.CodeAnalysis.Diagnostics; #if !CODE_STYLE using Microsoft.CodeAnalysis.CodeActions; diff --git a/src/Features/DiagnosticsTestUtilities/CodeActions/VisualBasicCodeFixVerifier`2+Test.cs b/src/Features/DiagnosticsTestUtilities/CodeActions/VisualBasicCodeFixVerifier`2+Test.cs index 4a89ea39fc172..5a0f22e64aaa3 100644 --- a/src/Features/DiagnosticsTestUtilities/CodeActions/VisualBasicCodeFixVerifier`2+Test.cs +++ b/src/Features/DiagnosticsTestUtilities/CodeActions/VisualBasicCodeFixVerifier`2+Test.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Testing; -using Microsoft.CodeAnalysis.Testing.Verifiers; using Microsoft.CodeAnalysis.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Testing; using Xunit; diff --git a/src/Features/DiagnosticsTestUtilities/CodeActions/VisualBasicCodeRefactoringVerifier`1+Test.cs b/src/Features/DiagnosticsTestUtilities/CodeActions/VisualBasicCodeRefactoringVerifier`1+Test.cs index 7b253715f4971..419ef7295d036 100644 --- a/src/Features/DiagnosticsTestUtilities/CodeActions/VisualBasicCodeRefactoringVerifier`1+Test.cs +++ b/src/Features/DiagnosticsTestUtilities/CodeActions/VisualBasicCodeRefactoringVerifier`1+Test.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Testing; -using Microsoft.CodeAnalysis.Testing.Verifiers; using Microsoft.CodeAnalysis.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Testing; diff --git a/src/Features/DiagnosticsTestUtilities/CodeActionsLegacy/AbstractCodeActionOrUserDiagnosticTest_NoEditor.cs b/src/Features/DiagnosticsTestUtilities/CodeActionsLegacy/AbstractCodeActionOrUserDiagnosticTest_NoEditor.cs index cd4fc6bc994cd..27e98ede07ae8 100644 --- a/src/Features/DiagnosticsTestUtilities/CodeActionsLegacy/AbstractCodeActionOrUserDiagnosticTest_NoEditor.cs +++ b/src/Features/DiagnosticsTestUtilities/CodeActionsLegacy/AbstractCodeActionOrUserDiagnosticTest_NoEditor.cs @@ -22,7 +22,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis.Diagnostics.EngineV2; +using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Remote.Testing; @@ -154,7 +154,7 @@ private protected virtual IDocumentServiceProvider GetDocumentServiceProvider() protected virtual TestComposition GetComposition() => FeaturesTestCompositions.Features - .AddAssemblies(typeof(DiagnosticIncrementalAnalyzer).Assembly); + .AddAssemblies(typeof(DiagnosticAnalyzerService).Assembly); protected virtual void InitializeWorkspace(TestWorkspace workspace, TestParameters parameters) { diff --git a/src/Features/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionAllCodeTests.cs b/src/Features/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionAllCodeTests.cs index 9fb723a0ac1c4..38fa73de279e3 100644 --- a/src/Features/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionAllCodeTests.cs +++ b/src/Features/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionAllCodeTests.cs @@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeFixes.Suppression; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.UnitTests.Diagnostics; using Roslyn.Utilities; diff --git a/src/Features/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreCSharpVirtualCharService.cs b/src/Features/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreCSharpVirtualCharService.cs index 94c9102be13e7..a173839f7ea4c 100644 --- a/src/Features/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreCSharpVirtualCharService.cs +++ b/src/Features/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreCSharpVirtualCharService.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. -using System.Text; using Microsoft.CodeAnalysis.CSharp.EmbeddedLanguages.VirtualChars; using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; -using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.ExternalAccess.AspNetCore.EmbeddedLanguages { diff --git a/src/Features/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreVirtualChar.cs b/src/Features/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreVirtualChar.cs index d526b8c731c76..dc9b381ca14b6 100644 --- a/src/Features/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreVirtualChar.cs +++ b/src/Features/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreVirtualChar.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Text; using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreVirtualCharSequence.cs b/src/Features/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreVirtualCharSequence.cs index 39ed6a0ae36d4..b45321a2fa95e 100644 --- a/src/Features/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreVirtualCharSequence.cs +++ b/src/Features/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreVirtualCharSequence.cs @@ -2,11 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections; using System.Collections.Generic; using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; -using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.ExternalAccess.AspNetCore.EmbeddedLanguages diff --git a/src/Features/ExternalAccess/AspNetCore/EmbeddedLanguages/BraceMatching/AspNetCoreBraceMatchingResult.cs b/src/Features/ExternalAccess/AspNetCore/EmbeddedLanguages/BraceMatching/AspNetCoreBraceMatchingResult.cs index eb9e9bf4cc3ae..98afd2569aa63 100644 --- a/src/Features/ExternalAccess/AspNetCore/EmbeddedLanguages/BraceMatching/AspNetCoreBraceMatchingResult.cs +++ b/src/Features/ExternalAccess/AspNetCore/EmbeddedLanguages/BraceMatching/AspNetCoreBraceMatchingResult.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.BraceMatching; -using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.ExternalAccess.AspNetCore.EmbeddedLanguages diff --git a/src/Features/ExternalAccess/AspNetCore/EmbeddedLanguages/BraceMatching/IAspNetCoreEmbeddedLanguageBraceMatcher.cs b/src/Features/ExternalAccess/AspNetCore/EmbeddedLanguages/BraceMatching/IAspNetCoreEmbeddedLanguageBraceMatcher.cs index e5a1b76c93a19..67ee321b0e3f3 100644 --- a/src/Features/ExternalAccess/AspNetCore/EmbeddedLanguages/BraceMatching/IAspNetCoreEmbeddedLanguageBraceMatcher.cs +++ b/src/Features/ExternalAccess/AspNetCore/EmbeddedLanguages/BraceMatching/IAspNetCoreEmbeddedLanguageBraceMatcher.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Threading; -using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.BraceMatching; namespace Microsoft.CodeAnalysis.ExternalAccess.AspNetCore.EmbeddedLanguages diff --git a/src/Features/ExternalAccess/AspNetCore/Internal/EmbeddedLanguages/AspNetCoreEmbeddedLanguageBraceMatcher.cs b/src/Features/ExternalAccess/AspNetCore/Internal/EmbeddedLanguages/AspNetCoreEmbeddedLanguageBraceMatcher.cs index e441ba5fc5e45..0810c14bf6534 100644 --- a/src/Features/ExternalAccess/AspNetCore/Internal/EmbeddedLanguages/AspNetCoreEmbeddedLanguageBraceMatcher.cs +++ b/src/Features/ExternalAccess/AspNetCore/Internal/EmbeddedLanguages/AspNetCoreEmbeddedLanguageBraceMatcher.cs @@ -6,9 +6,6 @@ using System.Composition; using System.Threading; using Microsoft.CodeAnalysis.BraceMatching; -using Microsoft.CodeAnalysis.Classification; -using Microsoft.CodeAnalysis.Editor; -using Microsoft.CodeAnalysis.ExternalAccess.AspNetCore.EmbeddedLanguages; using Microsoft.CodeAnalysis.Host.Mef; namespace Microsoft.CodeAnalysis.ExternalAccess.AspNetCore.Internal.EmbeddedLanguages diff --git a/src/EditorFeatures/ExternalAccess/Copilot/.editorconfig b/src/Features/ExternalAccess/Copilot/.editorconfig similarity index 100% rename from src/EditorFeatures/ExternalAccess/Copilot/.editorconfig rename to src/Features/ExternalAccess/Copilot/.editorconfig diff --git a/src/EditorFeatures/ExternalAccess/Copilot/Analyzer/CopilotChecksumWrapper.cs b/src/Features/ExternalAccess/Copilot/Analyzer/CopilotChecksumWrapper.cs similarity index 92% rename from src/EditorFeatures/ExternalAccess/Copilot/Analyzer/CopilotChecksumWrapper.cs rename to src/Features/ExternalAccess/Copilot/Analyzer/CopilotChecksumWrapper.cs index 8c78970c45ca5..8bf7c472a6250 100644 --- a/src/EditorFeatures/ExternalAccess/Copilot/Analyzer/CopilotChecksumWrapper.cs +++ b/src/Features/ExternalAccess/Copilot/Analyzer/CopilotChecksumWrapper.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot; /// /// Exposed to provide an efficient checksum implementation. -/// Intended usage including cahching responses w/o retaining potentially long strings. +/// Intended usage including caching responses w/o retaining potentially long strings. /// internal sealed class CopilotChecksumWrapper { diff --git a/src/EditorFeatures/ExternalAccess/Copilot/Analyzer/CopilotUtilities.cs b/src/Features/ExternalAccess/Copilot/Analyzer/CopilotUtilities.cs similarity index 100% rename from src/EditorFeatures/ExternalAccess/Copilot/Analyzer/CopilotUtilities.cs rename to src/Features/ExternalAccess/Copilot/Analyzer/CopilotUtilities.cs diff --git a/src/EditorFeatures/ExternalAccess/Copilot/Analyzer/IExternalCSharpCopilotCodeAnalysisService.cs b/src/Features/ExternalAccess/Copilot/Analyzer/IExternalCSharpCopilotCodeAnalysisService.cs similarity index 85% rename from src/EditorFeatures/ExternalAccess/Copilot/Analyzer/IExternalCSharpCopilotCodeAnalysisService.cs rename to src/Features/ExternalAccess/Copilot/Analyzer/IExternalCSharpCopilotCodeAnalysisService.cs index 1a0fed9bd383b..397b31031be87 100644 --- a/src/EditorFeatures/ExternalAccess/Copilot/Analyzer/IExternalCSharpCopilotCodeAnalysisService.cs +++ b/src/Features/ExternalAccess/Copilot/Analyzer/IExternalCSharpCopilotCodeAnalysisService.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; @@ -18,6 +17,5 @@ internal interface IExternalCSharpCopilotCodeAnalysisService Task> AnalyzeDocumentAsync(Document document, TextSpan? span, string promptTitle, CancellationToken cancellationToken); Task> GetCachedDiagnosticsAsync(Document document, string promptTitle, CancellationToken cancellationToken); Task StartRefinementSessionAsync(Document oldDocument, Document newDocument, Diagnostic? primaryDiagnostic, CancellationToken cancellationToken); - Task<(string responseString, bool isQuotaExceeded)> GetOnTheFlyDocsAsync(string symbolSignature, ImmutableArray declarationCode, string language, CancellationToken cancellationToken); Task IsFileExcludedAsync(string filePath, CancellationToken cancellationToken); } diff --git a/src/EditorFeatures/ExternalAccess/Copilot/CodeMapper/ICSharpCopilotMapCodeService.cs b/src/Features/ExternalAccess/Copilot/CodeMapper/ICSharpCopilotMapCodeService.cs similarity index 100% rename from src/EditorFeatures/ExternalAccess/Copilot/CodeMapper/ICSharpCopilotMapCodeService.cs rename to src/Features/ExternalAccess/Copilot/CodeMapper/ICSharpCopilotMapCodeService.cs diff --git a/src/Features/ExternalAccess/Copilot/GenerateDocumentation/CopilotDocumentationCommentProposalWrapper.cs b/src/Features/ExternalAccess/Copilot/GenerateDocumentation/CopilotDocumentationCommentProposalWrapper.cs new file mode 100644 index 0000000000000..00746d8d1fa3d --- /dev/null +++ b/src/Features/ExternalAccess/Copilot/GenerateDocumentation/CopilotDocumentationCommentProposalWrapper.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.Collections.Immutable; +using Microsoft.CodeAnalysis.DocumentationComments; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot +{ + internal sealed class CopilotDocumentationCommentProposalWrapper + { + private readonly DocumentationCommentProposal _documentationCommentProposal; + private readonly ImmutableArray _wrappedProposedEdits; + + public CopilotDocumentationCommentProposalWrapper(DocumentationCommentProposal documentationCommentProposal) + { + _documentationCommentProposal = documentationCommentProposal; + _wrappedProposedEdits = _documentationCommentProposal.ProposedEdits.SelectAsArray(e => new CopilotDocumentationCommentProposedEditWrapper(e)); + + } + + public string SymbolToAnalyze => _documentationCommentProposal.SymbolToAnalyze; + public ImmutableArray ProposedEdits => _wrappedProposedEdits; + } +} diff --git a/src/Features/ExternalAccess/Copilot/GenerateDocumentation/CopilotDocumentationCommentProposedEditWrapper.cs b/src/Features/ExternalAccess/Copilot/GenerateDocumentation/CopilotDocumentationCommentProposedEditWrapper.cs new file mode 100644 index 0000000000000..f5a0e66235e03 --- /dev/null +++ b/src/Features/ExternalAccess/Copilot/GenerateDocumentation/CopilotDocumentationCommentProposedEditWrapper.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 Microsoft.CodeAnalysis.DocumentationComments; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot +{ + internal sealed class CopilotDocumentationCommentProposedEditWrapper + { + + private readonly DocumentationCommentProposedEdit _documentationCommentProposedEdit; + + public CopilotDocumentationCommentProposedEditWrapper(DocumentationCommentProposedEdit proposedEdit) + { + _documentationCommentProposedEdit = proposedEdit; + } + + public TextSpan SpanToReplace => _documentationCommentProposedEdit.SpanToReplace; + + public string? SymbolName => _documentationCommentProposedEdit.SymbolName; + + public CopilotDocumentationCommentTagType TagType => (CopilotDocumentationCommentTagType)_documentationCommentProposedEdit.TagType; + } +} diff --git a/src/Features/ExternalAccess/Copilot/GenerateDocumentation/CopilotDocumentationCommentTagType.cs b/src/Features/ExternalAccess/Copilot/GenerateDocumentation/CopilotDocumentationCommentTagType.cs new file mode 100644 index 0000000000000..2a560477f21e6 --- /dev/null +++ b/src/Features/ExternalAccess/Copilot/GenerateDocumentation/CopilotDocumentationCommentTagType.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 Microsoft.CodeAnalysis.DocumentationComments; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot +{ + internal enum CopilotDocumentationCommentTagType + { + Summary = DocumentationCommentTagType.Summary, + Remarks = DocumentationCommentTagType.Remarks, + TypeParam = DocumentationCommentTagType.TypeParam, + Param = DocumentationCommentTagType.Param, + Returns = DocumentationCommentTagType.Returns, + Value = DocumentationCommentTagType.Value, + Exception = DocumentationCommentTagType.Exception, + } +} diff --git a/src/Features/ExternalAccess/Copilot/GenerateDocumentation/IExternalCSharpCopilotGenerateDocumentationService.cs b/src/Features/ExternalAccess/Copilot/GenerateDocumentation/IExternalCSharpCopilotGenerateDocumentationService.cs new file mode 100644 index 0000000000000..4b6bce93306a8 --- /dev/null +++ b/src/Features/ExternalAccess/Copilot/GenerateDocumentation/IExternalCSharpCopilotGenerateDocumentationService.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot +{ + internal interface IExternalCSharpCopilotGenerateDocumentationService + { + Task<(Dictionary? responseDictionary, bool isQuotaExceeded)> GetDocumentationCommentAsync(CopilotDocumentationCommentProposalWrapper proposal, CancellationToken cancellationToken); + } +} diff --git a/src/Features/ExternalAccess/Copilot/GenerateImplementation/IExternalCSharpCopilotGenerateImplementationService.cs b/src/Features/ExternalAccess/Copilot/GenerateImplementation/IExternalCSharpCopilotGenerateImplementationService.cs new file mode 100644 index 0000000000000..906712857e536 --- /dev/null +++ b/src/Features/ExternalAccess/Copilot/GenerateImplementation/IExternalCSharpCopilotGenerateImplementationService.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.Collections.Immutable; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.ExternalAccess.Copilot.GenerateImplementation; +using Microsoft.CodeAnalysis.FindSymbols; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot; + +internal interface IExternalCSharpCopilotGenerateImplementationService +{ + Task> ImplementNotImplementedExceptionsAsync( + Document document, + ImmutableDictionary> methodOrProperties, + CancellationToken cancellationToken); +} diff --git a/src/Features/ExternalAccess/Copilot/GenerateImplementation/ImplementationDetailsWrapper.cs b/src/Features/ExternalAccess/Copilot/GenerateImplementation/ImplementationDetailsWrapper.cs new file mode 100644 index 0000000000000..9cfcb8bdf5c4b --- /dev/null +++ b/src/Features/ExternalAccess/Copilot/GenerateImplementation/ImplementationDetailsWrapper.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 Microsoft.CodeAnalysis.ExternalAccess.Copilot.GenerateImplementation; + +/// +/// Holds details about a replacement node, providing either a message explaining the absence of a replacement or the +/// replacement syntax node itself. One of or must always be set. +/// +internal sealed class ImplementationDetailsWrapper +{ + /// + /// Gets the message explaining why a replacement node is not provided. Either this property or must be set. + /// + public string? Message { get; init; } + + /// + /// Gets the replacement syntax node. Either this property or must be set. + /// + public SyntaxNode? ReplacementNode { get; init; } +} diff --git a/src/EditorFeatures/ExternalAccess/Copilot/Internal/Analyzer/AbstractCopilotCodeAnalysisService.cs b/src/Features/ExternalAccess/Copilot/Internal/Analyzer/AbstractCopilotCodeAnalysisService.cs similarity index 78% rename from src/EditorFeatures/ExternalAccess/Copilot/Internal/Analyzer/AbstractCopilotCodeAnalysisService.cs rename to src/Features/ExternalAccess/Copilot/Internal/Analyzer/AbstractCopilotCodeAnalysisService.cs index a75f5e8f6f026..48af70a1e8696 100644 --- a/src/EditorFeatures/ExternalAccess/Copilot/Internal/Analyzer/AbstractCopilotCodeAnalysisService.cs +++ b/src/Features/ExternalAccess/Copilot/Internal/Analyzer/AbstractCopilotCodeAnalysisService.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; @@ -11,7 +10,10 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Copilot; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.DocumentationComments; +using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.QuickInfo; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -39,8 +41,12 @@ internal abstract class AbstractCopilotCodeAnalysisService(IDiagnosticsRefresher protected abstract Task> AnalyzeDocumentCoreAsync(Document document, TextSpan? span, string promptTitle, CancellationToken cancellationToken); protected abstract Task> GetCachedDiagnosticsCoreAsync(Document document, string promptTitle, CancellationToken cancellationToken); protected abstract Task StartRefinementSessionCoreAsync(Document oldDocument, Document newDocument, Diagnostic? primaryDiagnostic, CancellationToken cancellationToken); - protected abstract Task<(string responseString, bool isQuotaExceeded)> GetOnTheFlyDocsCoreAsync(string symbolSignature, ImmutableArray declarationCode, string language, CancellationToken cancellationToken); + protected abstract Task GetOnTheFlyDocsPromptCoreAsync(OnTheFlyDocsInfo onTheFlyDocsInfo, CancellationToken cancellationToken); + protected abstract Task<(string responseString, bool isQuotaExceeded)> GetOnTheFlyDocsResponseCoreAsync(string prompt, CancellationToken cancellationToken); protected abstract Task IsFileExcludedCoreAsync(string filePath, CancellationToken cancellationToken); + protected abstract Task<(Dictionary? responseDictionary, bool isQuotaExceeded)> GetDocumentationCommentCoreAsync(DocumentationCommentProposal proposal, CancellationToken cancellationToken); + protected abstract Task> ImplementNotImplementedExceptionsCoreAsync(Document document, ImmutableDictionary> methodOrProperties, CancellationToken cancellationToken); + protected abstract bool IsImplementNotImplementedExceptionsAvailableCore(); public Task IsAvailableAsync(CancellationToken cancellationToken) => IsAvailableCoreAsync(cancellationToken); @@ -161,7 +167,7 @@ public async Task> GetCachedDocumentDiagnosticsAsync( protected virtual Task> GetDiagnosticsIntersectWithSpanAsync(Document document, IReadOnlyList diagnostics, TextSpan span, CancellationToken cancellationToken) { - return Task.FromResult(diagnostics.WhereAsArray((diagnostic, _) => diagnostic.Location.SourceSpan.IntersectsWith(span), state: (object)null)); + return Task.FromResult(diagnostics.WhereAsArray((diagnostic, _) => diagnostic.Location.SourceSpan.IntersectsWith(span), state: (object?)null)); } public async Task StartRefinementSessionAsync(Document oldDocument, Document newDocument, Diagnostic? primaryDiagnostic, CancellationToken cancellationToken) @@ -173,12 +179,16 @@ public async Task StartRefinementSessionAsync(Document oldDocument, Document new await StartRefinementSessionCoreAsync(oldDocument, newDocument, primaryDiagnostic, cancellationToken).ConfigureAwait(false); } - public async Task<(string responseString, bool isQuotaExceeded)> GetOnTheFlyDocsAsync(string symbolSignature, ImmutableArray declarationCode, string language, CancellationToken cancellationToken) + public async Task GetOnTheFlyDocsPromptAsync(OnTheFlyDocsInfo onTheFlyDocsInfo, CancellationToken cancellationToken) + { + return await GetOnTheFlyDocsPromptCoreAsync(onTheFlyDocsInfo, cancellationToken).ConfigureAwait(false); + } + public async Task<(string responseString, bool isQuotaExceeded)> GetOnTheFlyDocsResponseAsync(string prompt, CancellationToken cancellationToken) { if (!await IsAvailableAsync(cancellationToken).ConfigureAwait(false)) return (string.Empty, false); - return await GetOnTheFlyDocsCoreAsync(symbolSignature, declarationCode, language, cancellationToken).ConfigureAwait(false); + return await GetOnTheFlyDocsResponseCoreAsync(prompt, cancellationToken).ConfigureAwait(false); } public async Task IsFileExcludedAsync(string filePath, CancellationToken cancellationToken) @@ -188,4 +198,26 @@ public async Task IsFileExcludedAsync(string filePath, CancellationToken c return await IsFileExcludedCoreAsync(filePath, cancellationToken).ConfigureAwait(false); } + + public async Task<(Dictionary? responseDictionary, bool isQuotaExceeded)> GetDocumentationCommentAsync(DocumentationCommentProposal proposal, CancellationToken cancellationToken) + { + if (!await IsAvailableAsync(cancellationToken).ConfigureAwait(false)) + return (null, false); + + return await GetDocumentationCommentCoreAsync(proposal, cancellationToken).ConfigureAwait(false); + } + + public async Task IsImplementNotImplementedExceptionsAvailableAsync(CancellationToken cancellationToken) + { + return await IsAvailableAsync(cancellationToken).ConfigureAwait(false) + && IsImplementNotImplementedExceptionsAvailableCore(); + } + + public async Task> ImplementNotImplementedExceptionsAsync( + Document document, + ImmutableDictionary> methodOrProperties, + CancellationToken cancellationToken) + { + return await ImplementNotImplementedExceptionsCoreAsync(document, methodOrProperties, cancellationToken).ConfigureAwait(false); + } } diff --git a/src/Features/ExternalAccess/Copilot/Internal/Analyzer/CSharp/CSharpCopilotCodeAnalysisService.cs b/src/Features/ExternalAccess/Copilot/Internal/Analyzer/CSharp/CSharpCopilotCodeAnalysisService.cs new file mode 100644 index 0000000000000..ac005eb0be0e0 --- /dev/null +++ b/src/Features/ExternalAccess/Copilot/Internal/Analyzer/CSharp/CSharpCopilotCodeAnalysisService.cs @@ -0,0 +1,181 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation 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.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Copilot; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.DocumentationComments; +using Microsoft.CodeAnalysis.ErrorReporting; +using Microsoft.CodeAnalysis.FindSymbols; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.LanguageService; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.QuickInfo; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot.Internal.Analyzer.CSharp; + +[ExportLanguageService(typeof(ICopilotCodeAnalysisService), LanguageNames.CSharp), Shared] +internal sealed class CSharpCopilotCodeAnalysisService : AbstractCopilotCodeAnalysisService +{ + private IExternalCSharpCopilotCodeAnalysisService? AnalysisService { get; } + private IExternalCSharpCopilotGenerateDocumentationService? GenerateDocumentationService { get; } + private IExternalCSharpOnTheFlyDocsService? OnTheFlyDocsService { get; } + private IExternalCSharpCopilotGenerateImplementationService? GenerateImplementationService { get; } + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CSharpCopilotCodeAnalysisService( + [Import(AllowDefault = true)] IExternalCSharpCopilotCodeAnalysisService? externalCopilotService, + [Import(AllowDefault = true)] IExternalCSharpCopilotGenerateDocumentationService? externalCSharpCopilotGenerateDocumentationService, + [Import(AllowDefault = true)] IExternalCSharpOnTheFlyDocsService? externalCSharpOnTheFlyDocsService, + [Import(AllowDefault = true)] IExternalCSharpCopilotGenerateImplementationService? externalCSharpCopilotGenerateImplementationService, + IDiagnosticsRefresher diagnosticsRefresher + ) : base(diagnosticsRefresher) + { + if (externalCopilotService is null) + FatalError.ReportAndCatch(new ArgumentNullException(nameof(externalCopilotService)), ErrorSeverity.Diagnostic); + + if (externalCSharpCopilotGenerateDocumentationService is null) + FatalError.ReportAndCatch(new ArgumentNullException(nameof(externalCSharpCopilotGenerateDocumentationService)), ErrorSeverity.Diagnostic); + + if (externalCSharpOnTheFlyDocsService is null) + FatalError.ReportAndCatch(new ArgumentNullException(nameof(externalCSharpOnTheFlyDocsService)), ErrorSeverity.Diagnostic); + + if (externalCSharpCopilotGenerateImplementationService is null) + FatalError.ReportAndCatch(new ArgumentNullException(nameof(externalCSharpCopilotGenerateImplementationService)), ErrorSeverity.Diagnostic); + + AnalysisService = externalCopilotService; + GenerateDocumentationService = externalCSharpCopilotGenerateDocumentationService; + OnTheFlyDocsService = externalCSharpOnTheFlyDocsService; + GenerateImplementationService = externalCSharpCopilotGenerateImplementationService; + } + + protected override Task> AnalyzeDocumentCoreAsync(Document document, TextSpan? span, string promptTitle, CancellationToken cancellationToken) + { + if (AnalysisService is not null) + return AnalysisService.AnalyzeDocumentAsync(document, span, promptTitle, cancellationToken); + + return Task.FromResult(ImmutableArray.Empty); + } + + protected override Task> GetAvailablePromptTitlesCoreAsync(Document document, CancellationToken cancellationToken) + { + if (AnalysisService is not null) + return AnalysisService.GetAvailablePromptTitlesAsync(document, cancellationToken); + + return Task.FromResult(ImmutableArray.Empty); + } + + protected override Task> GetCachedDiagnosticsCoreAsync(Document document, string promptTitle, CancellationToken cancellationToken) + { + if (AnalysisService is not null) + return AnalysisService.GetCachedDiagnosticsAsync(document, promptTitle, cancellationToken); + + return Task.FromResult(ImmutableArray.Empty); + } + + protected override Task IsAvailableCoreAsync(CancellationToken cancellationToken) + { + if (AnalysisService is not null) + return AnalysisService.IsAvailableAsync(cancellationToken); + + return Task.FromResult(false); + } + + protected override Task StartRefinementSessionCoreAsync(Document oldDocument, Document newDocument, Diagnostic? primaryDiagnostic, CancellationToken cancellationToken) + { + if (AnalysisService is not null) + return AnalysisService.StartRefinementSessionAsync(oldDocument, newDocument, primaryDiagnostic, cancellationToken); + + return Task.CompletedTask; + } + + protected override Task GetOnTheFlyDocsPromptCoreAsync(OnTheFlyDocsInfo onTheFlyDocsInfo, CancellationToken cancellationToken) + { + if (OnTheFlyDocsService is not null) + return OnTheFlyDocsService.GetOnTheFlyDocsPromptAsync(new CopilotOnTheFlyDocsInfoWrapper(onTheFlyDocsInfo), cancellationToken); + + return Task.FromResult(string.Empty); + } + + protected override Task<(string responseString, bool isQuotaExceeded)> GetOnTheFlyDocsResponseCoreAsync(string prompt, CancellationToken cancellationToken) + { + if (OnTheFlyDocsService is not null) + return OnTheFlyDocsService.GetOnTheFlyDocsResponseAsync(prompt, cancellationToken); + + return Task.FromResult((string.Empty, false)); + } + + protected override async Task> GetDiagnosticsIntersectWithSpanAsync( + Document document, IReadOnlyList diagnostics, TextSpan span, CancellationToken cancellationToken) + { + using var _ = ArrayBuilder.GetInstance(out var filteredDiagnostics); + + // The location of Copilot diagnostics is on the method identifier, we'd like to expand the range to include them + // if any part of the method intersects with the given span. + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var syntaxFacts = document.GetRequiredLanguageService(); + + foreach (var diagnostic in diagnostics) + { + var containingMethod = syntaxFacts.GetContainingMethodDeclaration(root, diagnostic.Location.SourceSpan.Start, useFullSpan: false); + if (containingMethod?.Span.IntersectsWith(span) is true) + filteredDiagnostics.Add(diagnostic); + } + + return filteredDiagnostics.ToImmutable(); + } + + protected override Task IsFileExcludedCoreAsync(string filePath, CancellationToken cancellationToken) + { + if (AnalysisService is not null) + return AnalysisService.IsFileExcludedAsync(filePath, cancellationToken); + + return Task.FromResult(false); + } + + protected override Task<(Dictionary? responseDictionary, bool isQuotaExceeded)> GetDocumentationCommentCoreAsync(DocumentationCommentProposal proposal, CancellationToken cancellationToken) + { + if (GenerateDocumentationService is not null) + return GenerateDocumentationService.GetDocumentationCommentAsync(new CopilotDocumentationCommentProposalWrapper(proposal), cancellationToken); + + return Task.FromResult<(Dictionary?, bool)>((null, false)); + } + + protected override bool IsImplementNotImplementedExceptionsAvailableCore() + { + return GenerateImplementationService is not null; + } + + protected override async Task> ImplementNotImplementedExceptionsCoreAsync( + Document document, + ImmutableDictionary> methodOrProperties, + CancellationToken cancellationToken) + { + Contract.ThrowIfNull(GenerateImplementationService); + var nodeToWrappers = await GenerateImplementationService.ImplementNotImplementedExceptionsAsync(document, methodOrProperties, cancellationToken).ConfigureAwait(false); + + var resultBuilder = ImmutableDictionary.CreateBuilder(); + foreach (var nodeToWrapper in nodeToWrappers) + { + resultBuilder.Add( + nodeToWrapper.Key, + new ImplementationDetails + { + ReplacementNode = nodeToWrapper.Value.ReplacementNode, + Message = nodeToWrapper.Value.Message + }); + } + + return resultBuilder.ToImmutable(); + } +} diff --git a/src/EditorFeatures/ExternalAccess/Copilot/Internal/CodeMapper/CopilotCSharpMapCodeService.cs b/src/Features/ExternalAccess/Copilot/Internal/CodeMapper/CopilotCSharpMapCodeService.cs similarity index 100% rename from src/EditorFeatures/ExternalAccess/Copilot/Internal/CodeMapper/CopilotCSharpMapCodeService.cs rename to src/Features/ExternalAccess/Copilot/Internal/CodeMapper/CopilotCSharpMapCodeService.cs diff --git a/src/EditorFeatures/ExternalAccess/Copilot/Internal/RelatedDocuments/CSharpCopilotRelatedDocumentsService.cs b/src/Features/ExternalAccess/Copilot/Internal/RelatedDocuments/CSharpCopilotRelatedDocumentsService.cs similarity index 100% rename from src/EditorFeatures/ExternalAccess/Copilot/Internal/RelatedDocuments/CSharpCopilotRelatedDocumentsService.cs rename to src/Features/ExternalAccess/Copilot/Internal/RelatedDocuments/CSharpCopilotRelatedDocumentsService.cs diff --git a/src/Features/ExternalAccess/Copilot/Internal/SemanticSearch/SemanticSearchCopilotServiceWrapper.cs b/src/Features/ExternalAccess/Copilot/Internal/SemanticSearch/SemanticSearchCopilotServiceWrapper.cs new file mode 100644 index 0000000000000..accb6ead3824b --- /dev/null +++ b/src/Features/ExternalAccess/Copilot/Internal/SemanticSearch/SemanticSearchCopilotServiceWrapper.cs @@ -0,0 +1,43 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch; +using Microsoft.CodeAnalysis.SemanticSearch; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot.Internal.SemanticSearch; + +[Export(typeof(ISemanticSearchCopilotService)), Shared] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class SemanticSearchCopilotServiceWrapper( + [Import(AllowDefault = true)] Lazy? impl) : ISemanticSearchCopilotService +{ + bool ISemanticSearchCopilotService.IsAvailable + => impl != null; + + async ValueTask ISemanticSearchCopilotService.TryGetQueryAsync(string text, SemanticSearchCopilotContext context, CancellationToken cancellationToken) + { + Contract.ThrowIfNull(impl); + + var result = await impl.Value.TryGetQueryAsync( + text, + new SemanticSearchCopilotContextImpl() + { + ModelName = context.ModelName, + AvailablePackages = context.AvailablePackages, + }, + cancellationToken).ConfigureAwait(false); + + return new SemanticSearchCopilotGeneratedQuery() + { + IsError = result.IsError, + Text = result.Text, + }; + } +} diff --git a/src/EditorFeatures/ExternalAccess/Copilot/InternalAPI.Shipped.txt b/src/Features/ExternalAccess/Copilot/InternalAPI.Shipped.txt similarity index 100% rename from src/EditorFeatures/ExternalAccess/Copilot/InternalAPI.Shipped.txt rename to src/Features/ExternalAccess/Copilot/InternalAPI.Shipped.txt diff --git a/src/Features/ExternalAccess/Copilot/InternalAPI.Unshipped.txt b/src/Features/ExternalAccess/Copilot/InternalAPI.Unshipped.txt new file mode 100644 index 0000000000000..7d380ca5d1e14 --- /dev/null +++ b/src/Features/ExternalAccess/Copilot/InternalAPI.Unshipped.txt @@ -0,0 +1,81 @@ +#nullable enable +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CodeMapper.ICSharpCopilotMapCodeService +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CodeMapper.ICSharpCopilotMapCodeService.MapCodeAsync(Microsoft.CodeAnalysis.Document! document, System.Collections.Immutable.ImmutableArray contents, System.Collections.Immutable.ImmutableArray<(Microsoft.CodeAnalysis.Document! document, Microsoft.CodeAnalysis.Text.TextSpan textSpan)> prioritizedFocusLocations, System.Collections.Generic.Dictionary! options, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task?>! +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotChecksumWrapper +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotChecksumWrapper.Equals(Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotChecksumWrapper? other) -> bool +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentProposalWrapper +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentProposalWrapper.CopilotDocumentationCommentProposalWrapper(Microsoft.CodeAnalysis.DocumentationComments.DocumentationCommentProposal! documentationCommentProposal) -> void +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentProposalWrapper.ProposedEdits.get -> System.Collections.Immutable.ImmutableArray +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentProposalWrapper.SymbolToAnalyze.get -> string! +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentProposedEditWrapper +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentProposedEditWrapper.CopilotDocumentationCommentProposedEditWrapper(Microsoft.CodeAnalysis.DocumentationComments.DocumentationCommentProposedEdit! proposedEdit) -> void +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentProposedEditWrapper.SpanToReplace.get -> Microsoft.CodeAnalysis.Text.TextSpan +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentProposedEditWrapper.SymbolName.get -> string? +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentProposedEditWrapper.TagType.get -> Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentTagType +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentTagType +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentTagType.Exception = 6 -> Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentTagType +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentTagType.Param = 3 -> Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentTagType +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentTagType.Remarks = 1 -> Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentTagType +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentTagType.Returns = 4 -> Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentTagType +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentTagType.Summary = 0 -> Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentTagType +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentTagType.TypeParam = 2 -> Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentTagType +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentTagType.Value = 5 -> Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentTagType +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotOnTheFlyDocsInfoWrapper +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotOnTheFlyDocsInfoWrapper.AdditionalContext.get -> System.Collections.Immutable.ImmutableArray +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotOnTheFlyDocsInfoWrapper.CopilotOnTheFlyDocsInfoWrapper(Microsoft.CodeAnalysis.QuickInfo.OnTheFlyDocsInfo! onTheFlyDocsInfo) -> void +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotOnTheFlyDocsInfoWrapper.DeclarationCode.get -> System.Collections.Immutable.ImmutableArray +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotOnTheFlyDocsInfoWrapper.HasComments.get -> bool +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotOnTheFlyDocsInfoWrapper.IsContentExcluded.get -> bool +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotOnTheFlyDocsInfoWrapper.Language.get -> string! +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotOnTheFlyDocsInfoWrapper.SymbolSignature.get -> string! +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotOnTheFlyDocsRelevantFileInfoWrapper +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotOnTheFlyDocsRelevantFileInfoWrapper.CopilotOnTheFlyDocsRelevantFileInfoWrapper(Microsoft.CodeAnalysis.QuickInfo.OnTheFlyDocsRelevantFileInfo! onTheFlyDocsRelevantFileInfo) -> void +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotOnTheFlyDocsRelevantFileInfoWrapper.Document.get -> Microsoft.CodeAnalysis.Document! +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotOnTheFlyDocsRelevantFileInfoWrapper.TextSpan.get -> Microsoft.CodeAnalysis.Text.TextSpan +Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotUtilities +Microsoft.CodeAnalysis.ExternalAccess.Copilot.GenerateImplementation.ImplementationDetailsWrapper +Microsoft.CodeAnalysis.ExternalAccess.Copilot.GenerateImplementation.ImplementationDetailsWrapper.ImplementationDetailsWrapper() -> void +Microsoft.CodeAnalysis.ExternalAccess.Copilot.GenerateImplementation.ImplementationDetailsWrapper.Message.get -> string? +Microsoft.CodeAnalysis.ExternalAccess.Copilot.GenerateImplementation.ImplementationDetailsWrapper.Message.init -> void +Microsoft.CodeAnalysis.ExternalAccess.Copilot.GenerateImplementation.ImplementationDetailsWrapper.ReplacementNode.get -> Microsoft.CodeAnalysis.SyntaxNode? +Microsoft.CodeAnalysis.ExternalAccess.Copilot.GenerateImplementation.ImplementationDetailsWrapper.ReplacementNode.init -> void +Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotCodeAnalysisService +Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotCodeAnalysisService.AnalyzeDocumentAsync(Microsoft.CodeAnalysis.Document! document, Microsoft.CodeAnalysis.Text.TextSpan? span, string! promptTitle, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task>! +Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotCodeAnalysisService.GetAvailablePromptTitlesAsync(Microsoft.CodeAnalysis.Document! document, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task>! +Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotCodeAnalysisService.GetCachedDiagnosticsAsync(Microsoft.CodeAnalysis.Document! document, string! promptTitle, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task>! +Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotCodeAnalysisService.GetOnTheFlyDocsAsync(string! symbolSignature, System.Collections.Immutable.ImmutableArray declarationCode, string! language, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task<(string! responseString, bool isQuotaExceeded)>! +Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotCodeAnalysisService.IsAvailableAsync(System.Threading.CancellationToken cancellation) -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotCodeAnalysisService.IsFileExcludedAsync(string! filePath, System.Threading.CancellationToken cancellationToken) -> 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.IExternalCSharpCopilotGenerateDocumentationService +Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotGenerateDocumentationService.GetDocumentationCommentAsync(Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentProposalWrapper! proposal, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task<(System.Collections.Generic.Dictionary? responseDictionary, bool isQuotaExceeded)>! +Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotGenerateImplementationService.ImplementNotImplementedExceptionsAsync(Microsoft.CodeAnalysis.Document! document, System.Collections.Immutable.ImmutableDictionary>! methodOrProperties, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task!>! +Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpOnTheFlyDocsService +Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpOnTheFlyDocsService.GetOnTheFlyDocsPromptAsync(Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotOnTheFlyDocsInfoWrapper! onTheFlyDocsInfo, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpOnTheFlyDocsService.GetOnTheFlyDocsResponseAsync(string! prompt, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task<(string! responseString, bool isQuotaExceeded)>! +Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotGenerateImplementationService +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 +Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.ISemanticSearchCopilotServiceImpl +Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.ISemanticSearchCopilotServiceImpl.TryGetQueryAsync(string! text, Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.SemanticSearchCopilotContextImpl! context, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask +Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.SemanticSearchCopilotContextImpl +Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.SemanticSearchCopilotContextImpl.AvailablePackages.get -> System.Collections.Generic.IEnumerable<(string! name, System.Version! version)>! +Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.SemanticSearchCopilotContextImpl.AvailablePackages.init -> void +Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.SemanticSearchCopilotContextImpl.ModelName.get -> string! +Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.SemanticSearchCopilotContextImpl.ModelName.init -> void +Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.SemanticSearchCopilotContextImpl.SemanticSearchCopilotContextImpl() -> void +Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.SemanticSearchCopilotGeneratedQueryImpl +Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.SemanticSearchCopilotGeneratedQueryImpl.IsError.get -> bool +Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.SemanticSearchCopilotGeneratedQueryImpl.IsError.init -> void +Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.SemanticSearchCopilotGeneratedQueryImpl.SemanticSearchCopilotGeneratedQueryImpl() -> void +Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.SemanticSearchCopilotGeneratedQueryImpl.Text.get -> string! +Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.SemanticSearchCopilotGeneratedQueryImpl.Text.init -> void +Microsoft.CodeAnalysis.SemanticSearch.SemanticSearchCopilotServiceWrapper +Microsoft.CodeAnalysis.SemanticSearch.SemanticSearchCopilotServiceWrapper.SemanticSearchCopilotServiceWrapper(System.Lazy? impl) -> void +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! +static Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotUtilities.GetContainingMethodDeclarationAsync(Microsoft.CodeAnalysis.Document! document, int position, bool useFullSpan, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task! +static Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotUtilities.GetCopilotSuggestionDiagnosticTag() -> string! +static Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotUtilities.IsResultantVisibilityPublic(this Microsoft.CodeAnalysis.ISymbol! symbol) -> bool +static Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotUtilities.IsValidIdentifier(string? name) -> bool diff --git a/src/EditorFeatures/ExternalAccess/Copilot/Microsoft.CodeAnalysis.ExternalAccess.Copilot.csproj b/src/Features/ExternalAccess/Copilot/Microsoft.CodeAnalysis.ExternalAccess.Copilot.csproj similarity index 74% rename from src/EditorFeatures/ExternalAccess/Copilot/Microsoft.CodeAnalysis.ExternalAccess.Copilot.csproj rename to src/Features/ExternalAccess/Copilot/Microsoft.CodeAnalysis.ExternalAccess.Copilot.csproj index 0da1aa938d434..69e66be254d12 100644 --- a/src/EditorFeatures/ExternalAccess/Copilot/Microsoft.CodeAnalysis.ExternalAccess.Copilot.csproj +++ b/src/Features/ExternalAccess/Copilot/Microsoft.CodeAnalysis.ExternalAccess.Copilot.csproj @@ -4,13 +4,14 @@ Library Microsoft.CodeAnalysis.ExternalAccess.Copilot - net472 + $(NetVSShared);net472 + true true Microsoft.CodeAnalysis.ExternalAccess.Copilot - A supporting package for Copilot Chat: + A supporting package for GitHub Copilot: https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_git/VisualStudio.Conversations @@ -21,14 +22,11 @@ --> + - - - - - + diff --git a/src/Features/ExternalAccess/Copilot/OnTheFlyDocs/CopilotOnTheFlyDocsInfoWrapper.cs b/src/Features/ExternalAccess/Copilot/OnTheFlyDocs/CopilotOnTheFlyDocsInfoWrapper.cs new file mode 100644 index 0000000000000..c7e1cb312b447 --- /dev/null +++ b/src/Features/ExternalAccess/Copilot/OnTheFlyDocs/CopilotOnTheFlyDocsInfoWrapper.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.Collections.Immutable; +using Microsoft.CodeAnalysis.QuickInfo; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot; + +internal sealed class CopilotOnTheFlyDocsInfoWrapper +{ + private readonly OnTheFlyDocsInfo _onTheFlyDocsInfo; + private readonly ImmutableArray _wrappedDeclarationCode; + private readonly ImmutableArray _wrappedAdditionalContext; + + public CopilotOnTheFlyDocsInfoWrapper(OnTheFlyDocsInfo onTheFlyDocsInfo) + { + _onTheFlyDocsInfo = onTheFlyDocsInfo; + _wrappedDeclarationCode = _onTheFlyDocsInfo.DeclarationCode.SelectAsArray(c => c is not null ? new CopilotOnTheFlyDocsRelevantFileInfoWrapper(c) : null); + _wrappedAdditionalContext = _onTheFlyDocsInfo.AdditionalContext.SelectAsArray(c => c is not null ? new CopilotOnTheFlyDocsRelevantFileInfoWrapper(c) : null); + + } + + public string SymbolSignature => _onTheFlyDocsInfo.SymbolSignature; + public ImmutableArray DeclarationCode => _wrappedDeclarationCode; + public string Language => _onTheFlyDocsInfo.Language; + public bool IsContentExcluded => _onTheFlyDocsInfo.IsContentExcluded; + public ImmutableArray AdditionalContext => _wrappedAdditionalContext; + public bool HasComments => _onTheFlyDocsInfo.HasComments; +} + diff --git a/src/Features/ExternalAccess/Copilot/OnTheFlyDocs/CopilotOnTheFlyDocsRelevantFileInfoWrapper.cs b/src/Features/ExternalAccess/Copilot/OnTheFlyDocs/CopilotOnTheFlyDocsRelevantFileInfoWrapper.cs new file mode 100644 index 0000000000000..c56903c86cd82 --- /dev/null +++ b/src/Features/ExternalAccess/Copilot/OnTheFlyDocs/CopilotOnTheFlyDocsRelevantFileInfoWrapper.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.QuickInfo; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot; + +internal sealed class CopilotOnTheFlyDocsRelevantFileInfoWrapper(OnTheFlyDocsRelevantFileInfo onTheFlyDocsRelevantFileInfo) +{ + private readonly OnTheFlyDocsRelevantFileInfo _onTheFlyDocsRelevantFileInfo = onTheFlyDocsRelevantFileInfo; + + public Document Document => _onTheFlyDocsRelevantFileInfo.Document; + public TextSpan TextSpan => _onTheFlyDocsRelevantFileInfo.TextSpan; +} diff --git a/src/Features/ExternalAccess/Copilot/OnTheFlyDocs/IExternalCSharpOnTheFlyDocsService.cs b/src/Features/ExternalAccess/Copilot/OnTheFlyDocs/IExternalCSharpOnTheFlyDocsService.cs new file mode 100644 index 0000000000000..ba83f33f96137 --- /dev/null +++ b/src/Features/ExternalAccess/Copilot/OnTheFlyDocs/IExternalCSharpOnTheFlyDocsService.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot +{ + internal interface IExternalCSharpOnTheFlyDocsService + { + Task GetOnTheFlyDocsPromptAsync(CopilotOnTheFlyDocsInfoWrapper onTheFlyDocsInfo, CancellationToken cancellationToken); + Task<(string responseString, bool isQuotaExceeded)> GetOnTheFlyDocsResponseAsync(string prompt, CancellationToken cancellationToken); + } +} diff --git a/src/EditorFeatures/ExternalAccess/Copilot/PublicAPI.Shipped.txt b/src/Features/ExternalAccess/Copilot/PublicAPI.Shipped.txt similarity index 100% rename from src/EditorFeatures/ExternalAccess/Copilot/PublicAPI.Shipped.txt rename to src/Features/ExternalAccess/Copilot/PublicAPI.Shipped.txt diff --git a/src/EditorFeatures/ExternalAccess/Copilot/PublicAPI.Unshipped.txt b/src/Features/ExternalAccess/Copilot/PublicAPI.Unshipped.txt similarity index 100% rename from src/EditorFeatures/ExternalAccess/Copilot/PublicAPI.Unshipped.txt rename to src/Features/ExternalAccess/Copilot/PublicAPI.Unshipped.txt diff --git a/src/EditorFeatures/ExternalAccess/Copilot/RelatedDocuments/ICopilotRelatedDocumentsService.cs b/src/Features/ExternalAccess/Copilot/RelatedDocuments/ICopilotRelatedDocumentsService.cs similarity index 100% rename from src/EditorFeatures/ExternalAccess/Copilot/RelatedDocuments/ICopilotRelatedDocumentsService.cs rename to src/Features/ExternalAccess/Copilot/RelatedDocuments/ICopilotRelatedDocumentsService.cs diff --git a/src/Features/ExternalAccess/Copilot/SemanticSearch/ISemanticSearchCopilotServiceImpl.cs b/src/Features/ExternalAccess/Copilot/SemanticSearch/ISemanticSearchCopilotServiceImpl.cs new file mode 100644 index 0000000000000..4b3a34a53bb6b --- /dev/null +++ b/src/Features/ExternalAccess/Copilot/SemanticSearch/ISemanticSearchCopilotServiceImpl.cs @@ -0,0 +1,38 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch; + +internal interface ISemanticSearchCopilotServiceImpl +{ + ValueTask TryGetQueryAsync(string text, SemanticSearchCopilotContextImpl context, CancellationToken cancellationToken); +} + +internal sealed class SemanticSearchCopilotContextImpl +{ + public required string ModelName { get; init; } + + /// + /// List of package names and versions that to include in the prompt. + /// + public required IEnumerable<(string name, Version version)> AvailablePackages { get; init; } +} + +internal readonly struct SemanticSearchCopilotGeneratedQueryImpl +{ + /// + /// True if is an error message. + /// + public required bool IsError { get; init; } + + /// + /// The generated code or an error message. + /// + public required string Text { get; init; } +} diff --git a/src/Features/ExternalAccess/OmniSharp.CSharp/Formatting/OmniSharpSyntaxFormattingOptionsFactory.cs b/src/Features/ExternalAccess/OmniSharp.CSharp/Formatting/OmniSharpSyntaxFormattingOptionsFactory.cs index 844abf30f4831..9b68b7451a033 100644 --- a/src/Features/ExternalAccess/OmniSharp.CSharp/Formatting/OmniSharpSyntaxFormattingOptionsFactory.cs +++ b/src/Features/ExternalAccess/OmniSharp.CSharp/Formatting/OmniSharpSyntaxFormattingOptionsFactory.cs @@ -2,11 +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 Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CSharp.Formatting; -using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Formatting; -using Microsoft.CodeAnalysis.Formatting; namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.CSharp.Formatting { diff --git a/src/Features/ExternalAccess/OmniSharp/Analyzers/OmnisharpAnalyzerLoaderFactory.cs b/src/Features/ExternalAccess/OmniSharp/Analyzers/OmnisharpAnalyzerLoaderFactory.cs index e876349f28962..c10f63386bfe6 100644 --- a/src/Features/ExternalAccess/OmniSharp/Analyzers/OmnisharpAnalyzerLoaderFactory.cs +++ b/src/Features/ExternalAccess/OmniSharp/Analyzers/OmnisharpAnalyzerLoaderFactory.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 Microsoft.CodeAnalysis.Diagnostics; using System.IO; namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Analyzers @@ -12,7 +11,7 @@ internal static class OmnisharpAnalyzerAssemblyLoaderFactory public static IAnalyzerAssemblyLoader CreateShadowCopyAnalyzerAssemblyLoader(string? baseDirectory = null) { baseDirectory ??= Path.Combine(Path.GetTempPath(), "CodeAnalysis", "OmnisharpAnalyzerShadowCopies"); - return DefaultAnalyzerAssemblyLoader.CreateNonLockingLoader(baseDirectory); + return AnalyzerAssemblyLoader.CreateNonLockingLoader(baseDirectory); } } } diff --git a/src/Features/ExternalAccess/OmniSharp/DocumentationComments/OmniSharpDocumentationCommentOptionsWrapper.cs b/src/Features/ExternalAccess/OmniSharp/DocumentationComments/OmniSharpDocumentationCommentOptionsWrapper.cs index e97f58dfcd72a..2b598f0757b29 100644 --- a/src/Features/ExternalAccess/OmniSharp/DocumentationComments/OmniSharpDocumentationCommentOptionsWrapper.cs +++ b/src/Features/ExternalAccess/OmniSharp/DocumentationComments/OmniSharpDocumentationCommentOptionsWrapper.cs @@ -4,7 +4,6 @@ using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.DocumentationComments; using Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Options; using Microsoft.CodeAnalysis.Formatting; diff --git a/src/Features/ExternalAccess/OmniSharp/ExtractClass/IOmniSharpExtractClassOptionsService.cs b/src/Features/ExternalAccess/OmniSharp/ExtractClass/IOmniSharpExtractClassOptionsService.cs index 6e50eefd8ee60..3d48e03532c97 100644 --- a/src/Features/ExternalAccess/OmniSharp/ExtractClass/IOmniSharpExtractClassOptionsService.cs +++ b/src/Features/ExternalAccess/OmniSharp/ExtractClass/IOmniSharpExtractClassOptionsService.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; -using System.Threading.Tasks; namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.ExtractClass { diff --git a/src/Features/ExternalAccess/OmniSharp/ExtractInterface/IOmniSharpExtractInterfaceOptionsService.cs b/src/Features/ExternalAccess/OmniSharp/ExtractInterface/IOmniSharpExtractInterfaceOptionsService.cs index 270e11fdfebeb..f9a7d14bc4137 100644 --- a/src/Features/ExternalAccess/OmniSharp/ExtractInterface/IOmniSharpExtractInterfaceOptionsService.cs +++ b/src/Features/ExternalAccess/OmniSharp/ExtractInterface/IOmniSharpExtractInterfaceOptionsService.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Collections.Immutable; -using System.Threading.Tasks; namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.ExtractInterface { diff --git a/src/Features/ExternalAccess/OmniSharp/Formatting/OmniSharpOrganizeImportsOptionsWrapper.cs b/src/Features/ExternalAccess/OmniSharp/Formatting/OmniSharpOrganizeImportsOptionsWrapper.cs index 5e690bb39bd71..7d099289b289b 100644 --- a/src/Features/ExternalAccess/OmniSharp/Formatting/OmniSharpOrganizeImportsOptionsWrapper.cs +++ b/src/Features/ExternalAccess/OmniSharp/Formatting/OmniSharpOrganizeImportsOptionsWrapper.cs @@ -5,7 +5,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.OrganizeImports; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Formatting { diff --git a/src/Features/ExternalAccess/OmniSharp/Formatting/OmniSharpSyntaxFormattingOptionsWrapper.cs b/src/Features/ExternalAccess/OmniSharp/Formatting/OmniSharpSyntaxFormattingOptionsWrapper.cs index 334ec58a57273..4c1e3d42db5d8 100644 --- a/src/Features/ExternalAccess/OmniSharp/Formatting/OmniSharpSyntaxFormattingOptionsWrapper.cs +++ b/src/Features/ExternalAccess/OmniSharp/Formatting/OmniSharpSyntaxFormattingOptionsWrapper.cs @@ -5,8 +5,6 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.AddImport; -using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Options; using Microsoft.CodeAnalysis.Formatting; diff --git a/src/Features/ExternalAccess/OmniSharp/InlineHints/OmniSharpInlineHintsOptions.cs b/src/Features/ExternalAccess/OmniSharp/InlineHints/OmniSharpInlineHintsOptions.cs index 9f7defb342070..792f8545d4a61 100644 --- a/src/Features/ExternalAccess/OmniSharp/InlineHints/OmniSharpInlineHintsOptions.cs +++ b/src/Features/ExternalAccess/OmniSharp/InlineHints/OmniSharpInlineHintsOptions.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.InlineHints; -using Microsoft.CodeAnalysis.LanguageService; namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.InlineHints; diff --git a/src/Features/ExternalAccess/OmniSharp/Internal/ExtractClass/OmniSharpExtractClassOptionsService.cs b/src/Features/ExternalAccess/OmniSharp/Internal/ExtractClass/OmniSharpExtractClassOptionsService.cs index 0569f5894203e..1b756d5272c24 100644 --- a/src/Features/ExternalAccess/OmniSharp/Internal/ExtractClass/OmniSharpExtractClassOptionsService.cs +++ b/src/Features/ExternalAccess/OmniSharp/Internal/ExtractClass/OmniSharpExtractClassOptionsService.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.ExtractClass; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Internal.ExtractClass; diff --git a/src/Features/ExternalAccess/OmniSharp/Internal/ExtractInterface/OmniSharpExtractInterfaceOptionsService.cs b/src/Features/ExternalAccess/OmniSharp/Internal/ExtractInterface/OmniSharpExtractInterfaceOptionsService.cs index 4b7bdbb8eb102..5194d0788f843 100644 --- a/src/Features/ExternalAccess/OmniSharp/Internal/ExtractInterface/OmniSharpExtractInterfaceOptionsService.cs +++ b/src/Features/ExternalAccess/OmniSharp/Internal/ExtractInterface/OmniSharpExtractInterfaceOptionsService.cs @@ -3,9 +3,8 @@ // 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.Threading; using Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.ExtractInterface; using Microsoft.CodeAnalysis.ExtractInterface; using Microsoft.CodeAnalysis.Host.Mef; @@ -22,14 +21,14 @@ internal sealed class OmniSharpExtractInterfaceOptionsService( public ExtractInterfaceOptionsResult GetExtractInterfaceOptions( Document document, - List extractableMembers, + ImmutableArray extractableMembers, string defaultInterfaceName, - List conflictingTypeNames, + ImmutableArray conflictingTypeNames, string defaultNamespace, - string generatedNameTypeParameterSuffix, - CancellationToken cancellationToken) + string generatedNameTypeParameterSuffix) { - var result = _omniSharpExtractInterfaceOptionsService.GetExtractInterfaceOptions(extractableMembers, defaultInterfaceName); + var result = _omniSharpExtractInterfaceOptionsService.GetExtractInterfaceOptions( + [.. extractableMembers], defaultInterfaceName); return new( result.IsCancelled, result.IncludedMembers, diff --git a/src/Features/ExternalAccess/OmniSharp/MetadataAsSource/OmniSharpMetadataAsSourceService.cs b/src/Features/ExternalAccess/OmniSharp/MetadataAsSource/OmniSharpMetadataAsSourceService.cs index 56ec424d51d3d..abc4cde6e6b23 100644 --- a/src/Features/ExternalAccess/OmniSharp/MetadataAsSource/OmniSharpMetadataAsSourceService.cs +++ b/src/Features/ExternalAccess/OmniSharp/MetadataAsSource/OmniSharpMetadataAsSourceService.cs @@ -2,18 +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.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeCleanup; -using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Formatting; -using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.MetadataAsSource; using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Simplification; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.MetadataAsSource { diff --git a/src/Features/ExternalAccess/OmniSharp/NavigateTo/OmniSharpNavigateToSearchResult.cs b/src/Features/ExternalAccess/OmniSharp/NavigateTo/OmniSharpNavigateToSearchResult.cs index 6f62810cec32c..71ebe9d98ea88 100644 --- a/src/Features/ExternalAccess/OmniSharp/NavigateTo/OmniSharpNavigateToSearchResult.cs +++ b/src/Features/ExternalAccess/OmniSharp/NavigateTo/OmniSharpNavigateToSearchResult.cs @@ -2,10 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Generic; using System.Collections.Immutable; -using System.Text; using Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Navigation; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/ExternalAccess/OmniSharp/Options/IOmniSharpLineFormattingOptionsProvider.cs b/src/Features/ExternalAccess/OmniSharp/Options/IOmniSharpLineFormattingOptionsProvider.cs index 8b92e27116e95..32515de5c6442 100644 --- a/src/Features/ExternalAccess/OmniSharp/Options/IOmniSharpLineFormattingOptionsProvider.cs +++ b/src/Features/ExternalAccess/OmniSharp/Options/IOmniSharpLineFormattingOptionsProvider.cs @@ -2,10 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Generic; -using System.Text; - namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Options { internal interface IOmniSharpLineFormattingOptionsProvider diff --git a/src/Features/ExternalAccess/OmniSharp/Options/OmniSharpSolutionAnalyzerConfigOptionsUpdater.cs b/src/Features/ExternalAccess/OmniSharp/Options/OmniSharpSolutionAnalyzerConfigOptionsUpdater.cs index dd1209b916f32..f040bebf31562 100644 --- a/src/Features/ExternalAccess/OmniSharp/Options/OmniSharpSolutionAnalyzerConfigOptionsUpdater.cs +++ b/src/Features/ExternalAccess/OmniSharp/Options/OmniSharpSolutionAnalyzerConfigOptionsUpdater.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.ImplementType; using Microsoft.CodeAnalysis.Options; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Options; diff --git a/src/Features/ExternalAccess/OmniSharp/Rename/OmniSharpRenamer.cs b/src/Features/ExternalAccess/OmniSharp/Rename/OmniSharpRenamer.cs index badcd77216474..cce78bd6662b6 100644 --- a/src/Features/ExternalAccess/OmniSharp/Rename/OmniSharpRenamer.cs +++ b/src/Features/ExternalAccess/OmniSharp/Rename/OmniSharpRenamer.cs @@ -2,12 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Rename; using Roslyn.Utilities; diff --git a/src/Features/ExternalAccess/OmniSharp/Structure/OmniSharpBlockStructureOptions.cs b/src/Features/ExternalAccess/OmniSharp/Structure/OmniSharpBlockStructureOptions.cs index 52b0b27612bd5..bfd7009ed432c 100644 --- a/src/Features/ExternalAccess/OmniSharp/Structure/OmniSharpBlockStructureOptions.cs +++ b/src/Features/ExternalAccess/OmniSharp/Structure/OmniSharpBlockStructureOptions.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 Microsoft.CodeAnalysis.Structure; namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Structure diff --git a/src/Features/Lsif/Generator/CompilerInvocation.cs b/src/Features/Lsif/Generator/CompilerInvocation.cs index faaa64cb2e950..90b116f73d2e6 100644 --- a/src/Features/Lsif/Generator/CompilerInvocation.cs +++ b/src/Features/Lsif/Generator/CompilerInvocation.cs @@ -68,7 +68,7 @@ public static async Task CreateFromInvocationInfoAsync(CompilerInvocati var commandLineParserService = languageServices.GetRequiredService(); var parsedCommandLine = commandLineParserService.Parse(splitCommandLine, Path.GetDirectoryName(invocationInfo.ProjectFilePath), isInteractive: false, sdkDirectory: null); - var analyzerLoader = new DefaultAnalyzerAssemblyLoader(); + var analyzerLoader = new AnalyzerAssemblyLoader(); var projectId = ProjectId.CreateNewId(invocationInfo.ProjectFilePath); diff --git a/src/Features/Lsif/Generator/Generator.cs b/src/Features/Lsif/Generator/Generator.cs index 354e412cf2d71..f885d8521c6d4 100644 --- a/src/Features/Lsif/Generator/Generator.cs +++ b/src/Features/Lsif/Generator/Generator.cs @@ -466,19 +466,22 @@ private static async Task GenerateSemanticTokensAsync( IdFactory idFactory, LsifDocument documentVertex) { + var cancellationToken = CancellationToken.None; + // Compute colorization data. // // Unlike the mainline LSP scenario, where we control both the syntactic colorizer (in-proc syntax tagger) // and the semantic colorizer (LSP semantic tokens) LSIF is more likely to be consumed by clients which may // have different syntactic classification behavior than us, resulting in missing colors. To avoid this, we // include syntax tokens in the generated data. + var text = await document.GetTextAsync(cancellationToken); var data = await SemanticTokensHelpers.ComputeSemanticTokensDataAsync( // Just get the pure-lsp semantic tokens here. document, - spans: [], + spans: [text.Lines.GetLinePositionSpan(new TextSpan(0, text.Length))], supportsVisualStudioExtensions: true, options: Classification.ClassificationOptions.Default, - cancellationToken: CancellationToken.None); + cancellationToken); var semanticTokensResult = new SemanticTokensResult(new SemanticTokens { Data = data }, idFactory); var semanticTokensEdge = Edge.Create(Methods.TextDocumentSemanticTokensFullName, documentVertex.GetId(), semanticTokensResult.GetId(), idFactory); diff --git a/src/Features/Lsif/Generator/Graph/Edge.cs b/src/Features/Lsif/Generator/Graph/Edge.cs index 1a10b36ecf2dd..5752a03863dd8 100644 --- a/src/Features/Lsif/Generator/Graph/Edge.cs +++ b/src/Features/Lsif/Generator/Graph/Edge.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using Newtonsoft.Json; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.Graph { diff --git a/src/Features/Lsif/Generator/Graph/RangeBasedDocumentSymbol.cs b/src/Features/Lsif/Generator/Graph/RangeBasedDocumentSymbol.cs index 70db03d5bbc5f..2e55b2cd33773 100644 --- a/src/Features/Lsif/Generator/Graph/RangeBasedDocumentSymbol.cs +++ b/src/Features/Lsif/Generator/Graph/RangeBasedDocumentSymbol.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using Microsoft.CodeAnalysis.Text; using Newtonsoft.Json; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.Graph; diff --git a/src/Features/Lsif/Generator/Logging/LsifFormatLogger.cs b/src/Features/Lsif/Generator/Logging/LsifFormatLogger.cs index 190dc336a9015..7e2a1871b9e45 100644 --- a/src/Features/Lsif/Generator/Logging/LsifFormatLogger.cs +++ b/src/Features/Lsif/Generator/Logging/LsifFormatLogger.cs @@ -7,7 +7,6 @@ using Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.Writing; using Microsoft.Extensions.Logging; using Newtonsoft.Json; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.Logging { diff --git a/src/Features/Lsif/Generator/Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.csproj b/src/Features/Lsif/Generator/Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.csproj index 08a3b376f97de..1b6c512bb1cfb 100644 --- a/src/Features/Lsif/Generator/Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.csproj +++ b/src/Features/Lsif/Generator/Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.csproj @@ -55,7 +55,6 @@ - diff --git a/src/Features/Lsif/GeneratorTest/FoldingRangeTests.vb b/src/Features/Lsif/GeneratorTest/FoldingRangeTests.vb index ed51d59f2626f..07ab30c4f4720 100644 --- a/src/Features/Lsif/GeneratorTest/FoldingRangeTests.vb +++ b/src/Features/Lsif/GeneratorTest/FoldingRangeTests.vb @@ -2,11 +2,9 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Test.Utilities Imports Roslyn.LanguageServer.Protocol Imports Roslyn.Test.Utilities -Imports Roslyn.Utilities Namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.UnitTests @@ -52,7 +50,6 @@ using System.Linq;|}", "...")> , openDocuments:=False, composition:=TestLsifOutput.TestComposition) - Dim annotatedLocations = Await AbstractLanguageServerProtocolTests.GetAnnotatedLocationsAsync(workspace, workspace.CurrentSolution) Dim expectedRanges = annotatedLocations.SelectMany(Function(kvp) kvp.Value.Select(Function(location) CreateFoldingRange(kvp.Key, location.Range, collapsedText))).OrderByDescending(Function(range) range.StartLine).ToArray() diff --git a/src/Features/Lsif/GeneratorTest/Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.UnitTests.vbproj b/src/Features/Lsif/GeneratorTest/Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.UnitTests.vbproj index 0a9d98d4bcde6..ac2f33f5aabe0 100644 --- a/src/Features/Lsif/GeneratorTest/Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.UnitTests.vbproj +++ b/src/Features/Lsif/GeneratorTest/Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.UnitTests.vbproj @@ -10,6 +10,7 @@ + diff --git a/src/Features/RulesMissingDocumentation.md b/src/Features/RulesMissingDocumentation.md index 07536d5ee0624..16fad36e94713 100644 --- a/src/Features/RulesMissingDocumentation.md +++ b/src/Features/RulesMissingDocumentation.md @@ -29,3 +29,4 @@ JSON001 | | Invalid JSON pattern | JSON002 | | Probable JSON string detected | RE0001 | | Invalid regex pattern | RemoveUnnecessaryImportsFixable | | | +IDE3000 | | Implement with Copilot | \ No newline at end of file diff --git a/src/Features/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs b/src/Features/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs index f61982ada6dcc..2fadd765778cc 100644 --- a/src/Features/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs +++ b/src/Features/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs @@ -153,9 +153,9 @@ public async Task StartDebuggingSession_CapturingDocuments(bool captureAllDocume EnterBreakState(debuggingSession); var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ModuleUpdateStatus.None, updates.Status); + Assert.Equal(ModuleUpdateStatus.Blocked, updates.Status); Assert.Empty(updates.Updates); - AssertEx.Equal([$"P.csproj: (0,0)-(0,0): Warning ENC1005: {string.Format(FeaturesResources.DocumentIsOutOfSyncWithDebuggee, sourceFileB.Path)}"], InspectDiagnostics(emitDiagnostics)); + AssertEx.Equal([$"P.csproj: (0,0)-(0,0): Error ENC1005: {string.Format(FeaturesResources.DocumentIsOutOfSyncWithDebuggee, sourceFileB.Path)}"], InspectDiagnostics(emitDiagnostics)); EndDebuggingSession(debuggingSession); } @@ -595,9 +595,9 @@ public async Task ErrorReadingPdbFile() // an error occurred so we need to call update to determine whether we have changes to apply or not: var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ModuleUpdateStatus.None, updates.Status); + Assert.Equal(ModuleUpdateStatus.Blocked, updates.Status); Assert.Empty(updates.Updates); - AssertEx.Equal([$"proj.csproj: (0,0)-(0,0): Warning ENC1006: {string.Format(FeaturesResources.UnableToReadSourceFileOrPdb, sourceFile.Path)}"], InspectDiagnostics(emitDiagnostics)); + AssertEx.Equal([$"proj.csproj: (0,0)-(0,0): Error ENC1006: {string.Format(FeaturesResources.UnableToReadSourceFileOrPdb, sourceFile.Path)}"], InspectDiagnostics(emitDiagnostics)); EndDebuggingSession(debuggingSession); @@ -642,9 +642,9 @@ public async Task ErrorReadingSourceFile() // an error occurred so we need to call update to determine whether we have changes to apply or not: var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ModuleUpdateStatus.None, updates.Status); + Assert.Equal(ModuleUpdateStatus.Blocked, updates.Status); Assert.Empty(updates.Updates); - AssertEx.Equal([$"test.csproj: (0,0)-(0,0): Warning ENC1006: {string.Format(FeaturesResources.UnableToReadSourceFileOrPdb, sourceFile.Path)}"], InspectDiagnostics(emitDiagnostics)); + AssertEx.Equal([$"test.csproj: (0,0)-(0,0): Error ENC1006: {string.Format(FeaturesResources.UnableToReadSourceFileOrPdb, sourceFile.Path)}"], InspectDiagnostics(emitDiagnostics)); fileLock.Dispose(); @@ -1168,9 +1168,9 @@ public async Task RudeEdits_DocumentOutOfSync(bool breakMode) // since the document is out-of-sync we need to call update to determine whether we have changes to apply or not: var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ModuleUpdateStatus.None, updates.Status); + Assert.Equal(ModuleUpdateStatus.Blocked, updates.Status); Assert.Empty(updates.Updates); - AssertEx.Equal([$"proj.csproj: (0,0)-(0,0): Warning ENC1005: {string.Format(FeaturesResources.DocumentIsOutOfSyncWithDebuggee, sourceFile.Path)}"], InspectDiagnostics(emitDiagnostics)); + AssertEx.Equal([$"proj.csproj: (0,0)-(0,0): Error ENC1005: {string.Format(FeaturesResources.DocumentIsOutOfSyncWithDebuggee, sourceFile.Path)}"], InspectDiagnostics(emitDiagnostics)); // update the file to match the build: sourceFile.WriteAllText(source0, Encoding.UTF8); @@ -1594,15 +1594,8 @@ public async Task HasChanges() EndDebuggingSession(debuggingSession); } - public enum DocumentKind - { - Source, - Additional, - AnalyzerConfig, - } - [Theory, CombinatorialData] - public async Task HasChanges_Documents(DocumentKind documentKind) + public async Task HasChanges_Documents(TextDocumentKind documentKind) { using var _ = CreateWorkspace(out var solution, out var service); var log = new TraceLog("Test"); @@ -1617,15 +1610,15 @@ public async Task HasChanges_Documents(DocumentKind documentKind) { switch (documentKind) { - case DocumentKind.Source: + case TextDocumentKind.Document: context.AddSource("Generated.cs", context.Compilation.SyntaxTrees.SingleOrDefault(t => t.FilePath.EndsWith("X.cs"))?.ToString() ?? "none"); break; - case DocumentKind.Additional: + case TextDocumentKind.AdditionalDocument: context.AddSource("Generated.cs", context.AdditionalFiles.FirstOrDefault()?.GetText().ToString() ?? "none"); break; - case DocumentKind.AnalyzerConfig: + case TextDocumentKind.AnalyzerConfigDocument: var syntaxTree = context.Compilation.SyntaxTrees.Single(t => t.FilePath.EndsWith("A.cs")); var content = context.AnalyzerConfigOptions.GetOptions(syntaxTree).TryGetValue("x", out var optionValue) ? optionValue.ToString() : "none"; @@ -1663,9 +1656,9 @@ public async Task HasChanges_Documents(DocumentKind documentKind) var documentId = DocumentId.CreateNewId(projectId); solution = documentKind switch { - 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([("x", "1")]), filePath: pathX), + TextDocumentKind.Document => solution.AddDocument(documentId, "X", CreateText("xxx"), filePath: pathX), + TextDocumentKind.AdditionalDocument => solution.AddAdditionalDocument(documentId, "X", CreateText("xxx"), filePath: pathX), + TextDocumentKind.AnalyzerConfigDocument => solution.AddAnalyzerConfigDocument(documentId, "X", GetAnalyzerConfigText([("x", "1")]), filePath: pathX), _ => throw ExceptionUtilities.Unreachable(), }; Assert.True(await EditSession.HasChangesAsync(oldSolution, solution, CancellationToken.None)); @@ -1683,7 +1676,7 @@ public async Task HasChanges_Documents(DocumentKind documentKind) var diagnostics = new ArrayBuilder(); await EditSession.PopulateChangedAndAddedDocumentsAsync(log, 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)); + AssertEx.Equal(documentKind == TextDocumentKind.Document ? [documentId, generatedDocumentId] : [generatedDocumentId], changedOrAddedDocuments.Select(d => d.Id)); Assert.Equal(1, generatorExecutionCount); @@ -1696,9 +1689,9 @@ public async Task HasChanges_Documents(DocumentKind documentKind) solution = documentKind switch { - DocumentKind.Source => solution.WithDocumentText(documentId, CreateText("xxx")), - DocumentKind.Additional => solution.WithAdditionalDocumentText(documentId, CreateText("xxx")), - DocumentKind.AnalyzerConfig => solution.WithAnalyzerConfigDocumentText(documentId, GetAnalyzerConfigText([("x", "1")])), + TextDocumentKind.Document => solution.WithDocumentText(documentId, CreateText("xxx")), + TextDocumentKind.AdditionalDocument => solution.WithAdditionalDocumentText(documentId, CreateText("xxx")), + TextDocumentKind.AnalyzerConfigDocument => solution.WithAnalyzerConfigDocumentText(documentId, GetAnalyzerConfigText([("x", "1")])), _ => throw ExceptionUtilities.Unreachable(), }; Assert.False(await EditSession.HasChangesAsync(oldSolution, solution, CancellationToken.None)); @@ -1707,7 +1700,7 @@ public async Task HasChanges_Documents(DocumentKind documentKind) Assert.Equal(0, generatorExecutionCount); // source generator infrastructure compares content and reuses state if it matches (SourceGeneratedDocumentState.WithUpdatedGeneratedContent): - AssertEx.Equal(documentKind == DocumentKind.Source ? new[] { documentId } : [], + AssertEx.Equal(documentKind == TextDocumentKind.Document ? new[] { documentId } : [], await EditSession.GetChangedDocumentsAsync(log, oldSolution.GetProject(projectId), solution.GetProject(projectId), CancellationToken.None).ToImmutableArrayAsync(CancellationToken.None)); await EditSession.PopulateChangedAndAddedDocumentsAsync(log, oldSolution.GetProject(projectId), solution.GetProject(projectId), changedOrAddedDocuments, diagnostics, CancellationToken.None); @@ -1724,20 +1717,20 @@ public async Task HasChanges_Documents(DocumentKind documentKind) oldSolution = solution; solution = documentKind switch { - DocumentKind.Source => solution.WithDocumentText(documentId, CreateText("xxx-changed")), - DocumentKind.Additional => solution.WithAdditionalDocumentText(documentId, CreateText("xxx-changed")), - DocumentKind.AnalyzerConfig => solution.WithAnalyzerConfigDocumentText(documentId, GetAnalyzerConfigText([("x", "2")])), + TextDocumentKind.Document => solution.WithDocumentText(documentId, CreateText("xxx-changed")), + TextDocumentKind.AdditionalDocument => solution.WithAdditionalDocumentText(documentId, CreateText("xxx-changed")), + TextDocumentKind.AnalyzerConfigDocument => solution.WithAnalyzerConfigDocumentText(documentId, GetAnalyzerConfigText([("x", "2")])), _ => throw ExceptionUtilities.Unreachable(), }; Assert.True(await EditSession.HasChangesAsync(oldSolution, solution, CancellationToken.None)); Assert.True(await EditSession.HasChangesAsync(oldSolution, solution, pathX, CancellationToken.None)); - AssertEx.Equal(documentKind == DocumentKind.Source ? [documentId, generatedDocumentId] : [generatedDocumentId], + AssertEx.Equal(documentKind == TextDocumentKind.Document ? [documentId, generatedDocumentId] : [generatedDocumentId], await EditSession.GetChangedDocumentsAsync(log, oldSolution.GetProject(projectId), solution.GetProject(projectId), CancellationToken.None).ToImmutableArrayAsync(CancellationToken.None)); await EditSession.PopulateChangedAndAddedDocumentsAsync(log, 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)); + AssertEx.Equal(documentKind == TextDocumentKind.Document ? [documentId, generatedDocumentId] : [generatedDocumentId], changedOrAddedDocuments.Select(d => d.Id)); Assert.Equal(1, generatorExecutionCount); @@ -1749,9 +1742,9 @@ public async Task HasChanges_Documents(DocumentKind documentKind) oldSolution = solution; solution = documentKind switch { - DocumentKind.Source => solution.RemoveDocument(documentId), - DocumentKind.Additional => solution.RemoveAdditionalDocument(documentId), - DocumentKind.AnalyzerConfig => solution.RemoveAnalyzerConfigDocument(documentId), + TextDocumentKind.Document => solution.RemoveDocument(documentId), + TextDocumentKind.AdditionalDocument => solution.RemoveAdditionalDocument(documentId), + TextDocumentKind.AnalyzerConfigDocument => solution.RemoveAnalyzerConfigDocument(documentId), _ => throw ExceptionUtilities.Unreachable(), }; Assert.True(await EditSession.HasChangesAsync(oldSolution, solution, CancellationToken.None)); @@ -2319,8 +2312,8 @@ public async Task ValidSignificantChange_FileUpdateNotObservedBeforeDebuggingSes // since the document is out-of-sync we need to call update to determine whether we have changes to apply or not: var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ModuleUpdateStatus.None, updates.Status); - AssertEx.Equal([$"test.csproj: (0,0)-(0,0): Warning ENC1005: {string.Format(FeaturesResources.DocumentIsOutOfSyncWithDebuggee, sourceFile.Path)}"], InspectDiagnostics(emitDiagnostics)); + Assert.Equal(ModuleUpdateStatus.Blocked, updates.Status); + AssertEx.Equal([$"test.csproj: (0,0)-(0,0): Error ENC1005: {string.Format(FeaturesResources.DocumentIsOutOfSyncWithDebuggee, sourceFile.Path)}"], InspectDiagnostics(emitDiagnostics)); // undo: solution = solution.WithDocumentText(documentId, CreateText(source1)); @@ -3118,6 +3111,44 @@ public async Task ValidSignificantChange_SourceGenerators_DocumentRemove() EndDebuggingSession(debuggingSession); } + [Fact] + public async Task ValidInsignificantChange() + { + var sourceV1 = "class C1 { void M() { /* System.Console.WriteLine(1); */ } }"; + var sourceV2 = "class C1 { void M() { /* System.Console.WriteLine(2); */ } }"; + + using var _ = CreateWorkspace(out var solution, out var service); + (solution, var document1) = AddDefaultTestProject(solution, sourceV1); + + var moduleId = EmitAndLoadLibraryToDebuggee(sourceV1); + + var debuggingSession = await StartDebuggingSessionAsync(service, solution); + + // change the source (valid edit): + solution = solution.WithDocumentText(document1.Id, CreateText(sourceV2)); + var document2 = solution.GetDocument(document1.Id); + + var diagnostics1 = await service.GetDocumentDiagnosticsAsync(document2, s_noActiveSpans, CancellationToken.None); + AssertEx.Empty(diagnostics1); + + // validate solution update status and emit: + var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); + Assert.Empty(emitDiagnostics); + Assert.Equal(ModuleUpdateStatus.None, updates.Status); + + // solution has been updated: + var text = await debuggingSession.LastCommittedSolution.GetRequiredProject(document1.Project.Id).GetDocument(document1.Id).GetTextAsync(); + Assert.Equal(sourceV2, text.ToString()); + + EndDebuggingSession(debuggingSession); + + AssertEx.SequenceEqual( + [ + "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=False|HadValidInsignificantChanges=True|RudeEditsCount=0|EmitDeltaErrorIdCount=0|InBreakState=False|Capabilities=0|ProjectIdsWithAppliedChanges=|ProjectIdsWithUpdatedBaselines=" + ], _telemetryLog); + } + [Fact] public async Task RudeEdit() { diff --git a/src/Features/Test/EditAndContinue/EmitSolutionUpdateResultsTests.cs b/src/Features/Test/EditAndContinue/EmitSolutionUpdateResultsTests.cs index 1b4aec81d413d..0d9924e15d765 100644 --- a/src/Features/Test/EditAndContinue/EmitSolutionUpdateResultsTests.cs +++ b/src/Features/Test/EditAndContinue/EmitSolutionUpdateResultsTests.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Collections.Immutable; using System.IO; @@ -16,7 +15,6 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; -using Roslyn.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.EditAndContinue.UnitTests diff --git a/src/Features/Test/EditAndContinue/RemoteEditAndContinueServiceTests.cs b/src/Features/Test/EditAndContinue/RemoteEditAndContinueServiceTests.cs index 9cd39cf62b4e9..cb7b9c834e12e 100644 --- a/src/Features/Test/EditAndContinue/RemoteEditAndContinueServiceTests.cs +++ b/src/Features/Test/EditAndContinue/RemoteEditAndContinueServiceTests.cs @@ -21,7 +21,6 @@ using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.UnitTests; using Roslyn.Test.Utilities; -using Roslyn.Utilities; using Xunit; namespace Roslyn.VisualStudio.Next.UnitTests.EditAndContinue; diff --git a/src/Features/Test/EditAndContinue/UnitTestingHotReloadServiceTests.cs b/src/Features/Test/EditAndContinue/UnitTestingHotReloadServiceTests.cs index fe44ddf327e40..efbcd0fd292b5 100644 --- a/src/Features/Test/EditAndContinue/UnitTestingHotReloadServiceTests.cs +++ b/src/Features/Test/EditAndContinue/UnitTestingHotReloadServiceTests.cs @@ -4,7 +4,6 @@ #nullable disable -using System.Collections.Immutable; using System.Linq; using System.Text; using System.Threading; diff --git a/src/Features/Test/EditAndContinue/WatchHotReloadServiceTests.cs b/src/Features/Test/EditAndContinue/WatchHotReloadServiceTests.cs index 60062cf1b21f2..a222cda9bbcff 100644 --- a/src/Features/Test/EditAndContinue/WatchHotReloadServiceTests.cs +++ b/src/Features/Test/EditAndContinue/WatchHotReloadServiceTests.cs @@ -34,10 +34,11 @@ public async Task Test() // See https://github.com/dotnet/sdk/blob/main/src/BuiltInTools/dotnet-watch/HotReload/CompilationHandler.cs#L125 var source1 = "class C { void M() { System.Console.WriteLine(1); } }"; - var source2 = "class C { void M() { System.Console.WriteLine(2); } }"; - var source3 = "class C { void M() { System.Console.WriteLine(2); } }"; - var source4 = "class C { void M() { System.Console.WriteLine(2)/* missing semicolon */ }"; - var source5 = "class C { void M() { Unknown(); } }"; + var source2 = "class C { void M() { System.Console.WriteLine(2); /*2*/} }"; + var source3 = "class C { void M() { System.Console.WriteLine(2); /*3*/} }"; + var source4 = "class C { void M() { System.Console.WriteLine(2); } }"; + var source5 = "class C { void M() { System.Console.WriteLine(2)/* missing semicolon */ }"; + var source6 = "class C { void M() { Unknown(); } }"; var dir = Temp.CreateDirectory(); var sourceFileA = dir.CreateFile("A.cs").WriteAllText(source1, Encoding.UTF8); @@ -79,9 +80,29 @@ public async Task Test() Assert.Equal(1, result.ProjectUpdates.Length); AssertEx.Equal([0x02000002], result.ProjectUpdates[0].UpdatedTypes); - // Rude edit: + // Insignificant change: solution = solution.WithDocumentText(documentIdA, CreateText(source3)); + result = await hotReload.GetUpdatesAsync(solution, runningProjects: [], CancellationToken.None); + Assert.Empty(result.Diagnostics); + Assert.Empty(result.Diagnostics); + Assert.Empty(result.ProjectUpdates); + Assert.Equal(ModuleUpdateStatus.None, result.Status); + + var updatedText = await ((EditAndContinueService)hotReload.GetTestAccessor().EncService) + .GetTestAccessor() + .GetActiveDebuggingSessions() + .Single() + .LastCommittedSolution + .GetRequiredProject(documentIdA.ProjectId) + .GetRequiredDocument(documentIdA) + .GetTextAsync(); + + Assert.Equal(source3, updatedText.ToString()); + + // Rude edit: + solution = solution.WithDocumentText(documentIdA, CreateText(source4)); + result = await hotReload.GetUpdatesAsync(solution, runningProjects: solution.ProjectIds.ToImmutableHashSet(), CancellationToken.None); 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)], @@ -91,7 +112,7 @@ public async Task Test() AssertEx.SetEqual(["P"], result.ProjectIdsToRebuild.Select(p => solution.GetRequiredProject(p).Name)); // Syntax error: - solution = solution.WithDocumentText(documentIdA, CreateText(source4)); + solution = solution.WithDocumentText(documentIdA, CreateText(source5)); result = await hotReload.GetUpdatesAsync(solution, runningProjects: solution.ProjectIds.ToImmutableHashSet(), CancellationToken.None); AssertEx.Equal( @@ -102,7 +123,7 @@ public async Task Test() Assert.Empty(result.ProjectIdsToRebuild); // Semantic error: - solution = solution.WithDocumentText(documentIdA, CreateText(source5)); + solution = solution.WithDocumentText(documentIdA, CreateText(source6)); result = await hotReload.GetUpdatesAsync(solution, runningProjects: solution.ProjectIds.ToImmutableHashSet(), CancellationToken.None); AssertEx.Equal( diff --git a/src/Features/TestUtilities/EditAndContinue/MatchingPair.cs b/src/Features/TestUtilities/EditAndContinue/MatchingPair.cs index 6b266d515fe13..3705f66c904cc 100644 --- a/src/Features/TestUtilities/EditAndContinue/MatchingPair.cs +++ b/src/Features/TestUtilities/EditAndContinue/MatchingPair.cs @@ -6,7 +6,6 @@ using System.Collections; using System.Collections.Generic; -using System.Linq; using Roslyn.Test.Utilities; namespace Microsoft.CodeAnalysis.EditAndContinue.UnitTests diff --git a/src/Features/TestUtilities/EditAndContinue/SyntaxMapDescription.cs b/src/Features/TestUtilities/EditAndContinue/SyntaxMapDescription.cs index dad5ba2fe15ee..282c408ab49f1 100644 --- a/src/Features/TestUtilities/EditAndContinue/SyntaxMapDescription.cs +++ b/src/Features/TestUtilities/EditAndContinue/SyntaxMapDescription.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Immutable; using System.Diagnostics; using Microsoft.CodeAnalysis.Differencing; diff --git a/src/Features/TestUtilities/Microsoft.CodeAnalysis.Features.Test.Utilities.csproj b/src/Features/TestUtilities/Microsoft.CodeAnalysis.Features.Test.Utilities.csproj index 2aa8f604ab261..766f43532bf19 100644 --- a/src/Features/TestUtilities/Microsoft.CodeAnalysis.Features.Test.Utilities.csproj +++ b/src/Features/TestUtilities/Microsoft.CodeAnalysis.Features.Test.Utilities.csproj @@ -10,10 +10,6 @@ true true - - - - @@ -37,6 +33,7 @@ + diff --git a/src/Features/VisualBasic/Portable/CodeRefactorings/MoveType/VisualBasicMoveTypeService.vb b/src/Features/VisualBasic/Portable/CodeRefactorings/MoveType/VisualBasicMoveTypeService.vb index 6c2b0e8efd6a6..4ff27cb564f00 100644 --- a/src/Features/VisualBasic/Portable/CodeRefactorings/MoveType/VisualBasicMoveTypeService.vb +++ b/src/Features/VisualBasic/Portable/CodeRefactorings/MoveType/VisualBasicMoveTypeService.vb @@ -20,6 +20,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.MoveType Public Sub New() End Sub + Protected Overrides Function GetSymbolNameAndArity(syntax As TypeBlockSyntax) As (name As String, arity As Integer) + Dim statement = syntax.BlockStatement + Return (statement.Identifier.ValueText, If(statement.TypeParameterList?.Parameters.Count, 0)) + End Function + Protected Overrides Function IsMemberDeclaration(syntaxNode As SyntaxNode) As Boolean Return TypeOf syntaxNode Is MethodBaseSyntax OrElse TypeOf syntaxNode Is MethodBlockBaseSyntax End Function diff --git a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/OverrideCompletionProvider.vb b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/OverrideCompletionProvider.vb index d57901b07dd5a..0214f41b3aa66 100644 --- a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/OverrideCompletionProvider.vb +++ b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/OverrideCompletionProvider.vb @@ -197,20 +197,20 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers Return False End Function - Protected Overrides Function GetTargetCaretPosition(caretTarget As SyntaxNode) As Integer + Protected Overrides Function GetTargetSelectionSpan(caretTarget As SyntaxNode) As TextSpan Dim node = DirectCast(caretTarget, SyntaxNode) ' MustOverride Sub | MustOverride Function: move to end of line Dim methodStatement = TryCast(node, MethodStatementSyntax) If methodStatement IsNot Nothing Then - Return methodStatement.GetLocation().SourceSpan.End + Return New TextSpan(methodStatement.GetLocation().SourceSpan.End, 0) End If Dim methodBlock = TryCast(node, MethodBlockBaseSyntax) If methodBlock IsNot Nothing Then Dim lastStatement = methodBlock.Statements.LastOrDefault() If lastStatement IsNot Nothing Then - Return lastStatement.GetLocation().SourceSpan.End + Return New TextSpan(lastStatement.GetLocation().SourceSpan.End, 0) End If End If @@ -220,12 +220,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers If firstAccessor IsNot Nothing Then Dim lastAccessorStatement = firstAccessor.Statements.LastOrDefault() If lastAccessorStatement IsNot Nothing Then - Return lastAccessorStatement.GetLocation().SourceSpan.End + Return New TextSpan(lastAccessorStatement.GetLocation().SourceSpan.End, 0) End If End If End If - Return -1 + Return New TextSpan(0, 0) End Function End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/ConvertToInterpolatedString/VisualBasicConvertPlaceholderToInterpolatedStringRefactoringProvider.vb b/src/Features/VisualBasic/Portable/ConvertToInterpolatedString/VisualBasicConvertPlaceholderToInterpolatedStringRefactoringProvider.vb index 8ef9b016e58ea..0bbc2ea490efe 100644 --- a/src/Features/VisualBasic/Portable/ConvertToInterpolatedString/VisualBasicConvertPlaceholderToInterpolatedStringRefactoringProvider.vb +++ b/src/Features/VisualBasic/Portable/ConvertToInterpolatedString/VisualBasicConvertPlaceholderToInterpolatedStringRefactoringProvider.vb @@ -10,7 +10,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.ConvertToInterpolatedString - Partial Friend Class VisualBasicConvertPlaceholderToInterpolatedStringRefactoringProvider + Partial Friend NotInheritable Class VisualBasicConvertPlaceholderToInterpolatedStringRefactoringProvider Inherits AbstractConvertPlaceholderToInterpolatedStringRefactoringProvider(Of ExpressionSyntax, LiteralExpressionSyntax, diff --git a/src/Features/VisualBasic/Portable/NavigateTo/VisualBasicNavigateToSearchService.vb b/src/Features/VisualBasic/Portable/NavigateTo/VisualBasicNavigateToSearchService.vb index 6e2901f52da73..5ba3943fdc734 100644 --- a/src/Features/VisualBasic/Portable/NavigateTo/VisualBasicNavigateToSearchService.vb +++ b/src/Features/VisualBasic/Portable/NavigateTo/VisualBasicNavigateToSearchService.vb @@ -8,7 +8,7 @@ Imports Microsoft.CodeAnalysis.NavigateTo Namespace Microsoft.CodeAnalysis.VisualBasic.NavigateTo - Friend Class VisualBasicNavigateToSearchService + Friend NotInheritable Class VisualBasicNavigateToSearchService Inherits AbstractNavigateToSearchService diff --git a/src/Features/VisualBasic/Portable/NavigationBar/VisualBasicNavigationBarItemService.vb b/src/Features/VisualBasic/Portable/NavigationBar/VisualBasicNavigationBarItemService.vb index aa8ef5c25ad8f..1302e602d6ec6 100644 --- a/src/Features/VisualBasic/Portable/NavigationBar/VisualBasicNavigationBarItemService.vb +++ b/src/Features/VisualBasic/Portable/NavigationBar/VisualBasicNavigationBarItemService.vb @@ -19,7 +19,7 @@ Imports Roslyn.Utilities Namespace Microsoft.CodeAnalysis.NavigationBar - Partial Friend Class VisualBasicNavigationBarItemService + Partial Friend NotInheritable Class VisualBasicNavigationBarItemService Inherits AbstractNavigationBarItemService Private ReadOnly _typeFormat As SymbolDisplayFormat = New SymbolDisplayFormat( diff --git a/src/Features/VisualBasic/Portable/SolutionCrawler/VisualBasicDocumentDifferenceService.vb b/src/Features/VisualBasic/Portable/SolutionCrawler/VisualBasicDocumentDifferenceService.vb index decb93449bacf..c41980b0cb5ea 100644 --- a/src/Features/VisualBasic/Portable/SolutionCrawler/VisualBasicDocumentDifferenceService.vb +++ b/src/Features/VisualBasic/Portable/SolutionCrawler/VisualBasicDocumentDifferenceService.vb @@ -5,15 +5,69 @@ Imports System.Composition Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.SolutionCrawler +Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.SolutionCrawler - Friend Class VisualBasicDocumentDifferenceService + Friend NotInheritable Class VisualBasicDocumentDifferenceService Inherits AbstractDocumentDifferenceService Public Sub New() End Sub + + Protected Overrides Function IsContainedInMemberBody(node As SyntaxNode, span As Text.TextSpan) As Boolean + Dim method = TryCast(node, MethodBlockBaseSyntax) + If method IsNot Nothing Then + Return method.Statements.Count > 0 AndAlso ContainsExclusively(GetSyntaxListSpan(method.Statements), span) + End If + + Dim [event] = TryCast(node, EventBlockSyntax) + If [event] IsNot Nothing Then + Return [event].Accessors.Count > 0 AndAlso ContainsExclusively(GetSyntaxListSpan([event].Accessors), span) + End If + + Dim [property] = TryCast(node, PropertyBlockSyntax) + If [property] IsNot Nothing Then + Return [property].Accessors.Count > 0 AndAlso ContainsExclusively(GetSyntaxListSpan([property].Accessors), span) + End If + + Dim field = TryCast(node, FieldDeclarationSyntax) + If field IsNot Nothing Then + Return field.Declarators.Count > 0 AndAlso ContainsExclusively(GetSeparatedSyntaxListSpan(field.Declarators), span) + End If + + Dim [enum] = TryCast(node, EnumMemberDeclarationSyntax) + If [enum] IsNot Nothing Then + Return [enum].Initializer IsNot Nothing AndAlso ContainsExclusively([enum].Initializer.Span, span) + End If + + Dim propStatement = TryCast(node, PropertyStatementSyntax) + If propStatement IsNot Nothing Then + Return propStatement.Initializer IsNot Nothing AndAlso ContainsExclusively(propStatement.Initializer.Span, span) + End If + + Return False + End Function + + Private Shared Function ContainsExclusively(outerSpan As TextSpan, innerSpan As TextSpan) As Boolean + If innerSpan.IsEmpty Then + Return outerSpan.Contains(innerSpan.Start) + End If + + Return outerSpan.Contains(innerSpan) + End Function + + Private Shared Function GetSyntaxListSpan(Of T As SyntaxNode)(list As SyntaxList(Of T)) As TextSpan + Debug.Assert(list.Count > 0) + Return TextSpan.FromBounds(list.First.SpanStart, list.Last.Span.End) + End Function + + Private Shared Function GetSeparatedSyntaxListSpan(Of T As SyntaxNode)(list As SeparatedSyntaxList(Of T)) As TextSpan + Debug.Assert(list.Count > 0) + Return TextSpan.FromBounds(list.First.SpanStart, list.Last.Span.End) + End Function End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/UseAutoProperty/VisualBasicUseAutoPropertyCodeFixProvider.vb b/src/Features/VisualBasic/Portable/UseAutoProperty/VisualBasicUseAutoPropertyCodeFixProvider.vb index 7bbfd6ed38090..ddabdd4e4c3e3 100644 --- a/src/Features/VisualBasic/Portable/UseAutoProperty/VisualBasicUseAutoPropertyCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/UseAutoProperty/VisualBasicUseAutoPropertyCodeFixProvider.vb @@ -60,7 +60,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UseAutoProperty Dim generator = SyntaxGenerator.GetGenerator(propertyDocument.Project) Dim canBeReadOnly = Not isWrittenToOutsideOfConstructor AndAlso Not propertyDeclaration.Accessors.Any(SyntaxKind.SetAccessorBlock) - statement = DirectCast(generator.WithModifiers(statement, generator.GetModifiers(propertyDeclaration).WithIsReadOnly(canBeReadOnly)), PropertyStatementSyntax) + statement = generator.WithModifiers(statement, generator.GetModifiers(propertyDeclaration).WithIsReadOnly(canBeReadOnly)) Dim initializer = Await GetFieldInitializerAsync(fieldSymbol, cancellationToken).ConfigureAwait(False) If initializer.equalsValue IsNot Nothing Then diff --git a/src/Features/VisualBasicTest/CodeActions/AbstractVisualBasicCodeActionTest_NoEditor.vb b/src/Features/VisualBasicTest/CodeActions/AbstractVisualBasicCodeActionTest_NoEditor.vb index 8a077a9b0adc5..3373cd2cba8f3 100644 --- a/src/Features/VisualBasicTest/CodeActions/AbstractVisualBasicCodeActionTest_NoEditor.vb +++ b/src/Features/VisualBasicTest/CodeActions/AbstractVisualBasicCodeActionTest_NoEditor.vb @@ -26,7 +26,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeRefactorings Return input.Replace("\n", vbCrLf) End Function - Protected Overloads Async Function TestAsync(initialMarkup As XElement, expected As XElement, Optional index As Integer = 0, Optional parseOptions As ParseOptions = Nothing) As Threading.Tasks.Task + Protected Overloads Async Function TestAsync(initialMarkup As XElement, expected As XElement, Optional index As Integer = 0, Optional parseOptions As ParseOptions = Nothing) As Task Dim initialMarkupStr = initialMarkup.ConvertTestSourceTag() Dim expectedStr = expected.ConvertTestSourceTag() If parseOptions Is Nothing Then @@ -36,7 +36,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeRefactorings End If End Function - Protected Overloads Async Function TestMissingAsync(initialMarkup As XElement) As Threading.Tasks.Task + Protected Overloads Async Function TestMissingAsync(initialMarkup As XElement) As Task Dim initialMarkupStr = initialMarkup.ConvertTestSourceTag() Await MyBase.TestMissingAsync(initialMarkupStr, diff --git a/src/Features/VisualBasicTest/Diagnostics/AbstractVisualBasicDiagnosticProviderBasedUserDiagnosticTest_NoEditor.vb b/src/Features/VisualBasicTest/Diagnostics/AbstractVisualBasicDiagnosticProviderBasedUserDiagnosticTest_NoEditor.vb index da635844e6056..279b58ab310ff 100644 --- a/src/Features/VisualBasicTest/Diagnostics/AbstractVisualBasicDiagnosticProviderBasedUserDiagnosticTest_NoEditor.vb +++ b/src/Features/VisualBasicTest/Diagnostics/AbstractVisualBasicDiagnosticProviderBasedUserDiagnosticTest_NoEditor.vb @@ -28,7 +28,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics End Function Friend Overloads Async Function TestAsync( - initialMarkup As XElement, expected As XElement, Optional index As Integer = 0) As Threading.Tasks.Task + initialMarkup As XElement, expected As XElement, Optional index As Integer = 0) As Task Dim initialMarkupStr = initialMarkup.ConvertTestSourceTag() Dim expectedStr = expected.ConvertTestSourceTag() @@ -37,7 +37,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics index:=index) End Function - Protected Overloads Async Function TestMissingAsync(initialMarkup As XElement) As Threading.Tasks.Task + Protected Overloads Async Function TestMissingAsync(initialMarkup As XElement) As Task Dim initialMarkupStr = initialMarkup.ConvertTestSourceTag() Await MyBase.TestMissingAsync(initialMarkupStr, New TestParameters(parseOptions:=Nothing, compilationOptions:=_compilationOptions)) diff --git a/src/Features/VisualBasicTest/EditAndContinue/TopLevelEditingTests.vb b/src/Features/VisualBasicTest/EditAndContinue/TopLevelEditingTests.vb index e329b02dea940..c315a384a20df 100644 --- a/src/Features/VisualBasicTest/EditAndContinue/TopLevelEditingTests.vb +++ b/src/Features/VisualBasicTest/EditAndContinue/TopLevelEditingTests.vb @@ -6029,11 +6029,7 @@ End Interface EditAndContinueValidation.VerifySemantics( {GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2)}, { - DocumentResults( - semanticEdits:= - { - SemanticEdit(SemanticEditKind.Delete, Function(c) c.GetMember(Of MethodSymbol)("C.F").PartialImplementationPart, deletedSymbolContainerProvider:=Function(c) c.GetMember("C"), partialType:="C") - }), + DocumentResults(), DocumentResults( semanticEdits:= { diff --git a/src/Features/VisualBasicTest/GenerateVariable/GenerateVariableTests.vb b/src/Features/VisualBasicTest/GenerateVariable/GenerateVariableTests.vb index bd95346f49e3a..ff58f72d0e3ca 100644 --- a/src/Features/VisualBasicTest/GenerateVariable/GenerateVariableTests.vb +++ b/src/Features/VisualBasicTest/GenerateVariable/GenerateVariableTests.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Collections.Immutable +Imports System.Threading.Tasks Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.Diagnostics @@ -22,7 +23,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics.Genera End Function - Public Async Function TestGenerateSimpleProperty() As Threading.Tasks.Task + Public Async Function TestGenerateSimpleProperty() As Task Await TestInRegularAndScriptAsync( "Module Program Sub Main(args As String()) @@ -39,7 +40,7 @@ End Module") End Function - Public Async Function TestGenerateSimpleField() As Threading.Tasks.Task + Public Async Function TestGenerateSimpleField() As Task Await TestInRegularAndScriptAsync( "Module Program Sub Main(args As String()) @@ -57,7 +58,7 @@ index:=1) End Function - Public Async Function TestGenerateReadOnlyField() As Threading.Tasks.Task + Public Async Function TestGenerateReadOnlyField() As Task Await TestInRegularAndScriptAsync( "Module Program Sub Main(args As String()) @@ -75,7 +76,7 @@ index:=2) End Function - Public Async Function TestGenerateFromAssignment() As Threading.Tasks.Task + Public Async Function TestGenerateFromAssignment() As Task Await TestInRegularAndScriptAsync( "Class C Shared Sub M @@ -138,7 +139,7 @@ index:=1) End Function - Public Async Function TestGenerateProtectedSharedFieldIntoBase() As Threading.Tasks.Task + Public Async Function TestGenerateProtectedSharedFieldIntoBase() As Task Await TestInRegularAndScriptAsync( "Class Base End Class @@ -173,7 +174,7 @@ End Class") End Function - Public Async Function TestGenerateFriendAccessibilityForField() As Threading.Tasks.Task + Public Async Function TestGenerateFriendAccessibilityForField() As Task Await TestInRegularAndScriptAsync( "Class A End Class @@ -194,7 +195,7 @@ index:=1) End Function - Public Async Function TestGeneratePropertyOnInterface1() As Threading.Tasks.Task + Public Async Function TestGeneratePropertyOnInterface1() As Task Await TestInRegularAndScriptAsync( "Interface IGoo End Interface @@ -216,7 +217,7 @@ End Class") End Function - Public Async Function TestGeneratePropertyOnInterface2() As Threading.Tasks.Task + Public Async Function TestGeneratePropertyOnInterface2() As Task Await TestInRegularAndScriptAsync( "Interface IGoo End Interface @@ -238,7 +239,7 @@ End Class", index:=1) End Function - Public Async Function TestGeneratePropertyIntoModule() As Threading.Tasks.Task + Public Async Function TestGeneratePropertyIntoModule() As Task Await TestInRegularAndScriptAsync( "Module Program Sub Main(args As String()) @@ -263,7 +264,7 @@ End Class") End Function - Public Async Function TestFieldPropertyIntoModule() As Threading.Tasks.Task + Public Async Function TestFieldPropertyIntoModule() As Task Await TestInRegularAndScriptAsync( "Module Program Sub Main(args As String()) @@ -947,7 +948,7 @@ End Class") End Function - Public Async Function TestFieldWithAnonymousTypeType() As Threading.Tasks.Task + Public Async Function TestFieldWithAnonymousTypeType() As Task Await TestInRegularAndScriptAsync( "Imports System Imports System.Collections.Generic @@ -2712,7 +2713,7 @@ end class", index:=1) End Function - Public Async Function TestGenerateSimplePropertyInSyncLock() As Threading.Tasks.Task + Public Async Function TestGenerateSimplePropertyInSyncLock() As Task Await TestInRegularAndScriptAsync( "Module Program Sub Main(args As String()) @@ -2731,7 +2732,7 @@ End Module") End Function - Public Async Function TestGenerateSimpleFieldInSyncLock() As Threading.Tasks.Task + Public Async Function TestGenerateSimpleFieldInSyncLock() As Task Await TestInRegularAndScriptAsync( "Module Program Sub Main(args As String()) @@ -2751,7 +2752,7 @@ index:=1) End Function - Public Async Function TestGenerateReadOnlyFieldInSyncLock() As Threading.Tasks.Task + Public Async Function TestGenerateReadOnlyFieldInSyncLock() As Task Await TestInRegularAndScriptAsync( "Module Program Sub Main(args As String()) diff --git a/src/Interactive/Host/Microsoft.CodeAnalysis.InteractiveHost.csproj b/src/Interactive/Host/Microsoft.CodeAnalysis.InteractiveHost.csproj index d06fa7a7bee4a..778289fdaf640 100644 --- a/src/Interactive/Host/Microsoft.CodeAnalysis.InteractiveHost.csproj +++ b/src/Interactive/Host/Microsoft.CodeAnalysis.InteractiveHost.csproj @@ -36,20 +36,11 @@ - - - - - - - - - @@ -61,6 +52,8 @@ + + @@ -76,4 +69,7 @@ + + + \ No newline at end of file diff --git a/src/Interactive/HostProcess/x86/InteractiveHost32.csproj b/src/Interactive/HostProcess/x86/InteractiveHost32.csproj index 70e32290b8987..3f5e9f3862b8e 100644 --- a/src/Interactive/HostProcess/x86/InteractiveHost32.csproj +++ b/src/Interactive/HostProcess/x86/InteractiveHost32.csproj @@ -9,6 +9,7 @@ true true true + win-x86 diff --git a/src/LanguageServer/ExternalAccess/Copilot/Handler/AbstractCopilotLspServiceDocumentRequestHandler.cs b/src/LanguageServer/ExternalAccess/Copilot/Handler/AbstractCopilotLspServiceDocumentRequestHandler.cs new file mode 100644 index 0000000000000..a9965a35987e7 --- /dev/null +++ b/src/LanguageServer/ExternalAccess/Copilot/Handler/AbstractCopilotLspServiceDocumentRequestHandler.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.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Microsoft.CommonLanguageServerProtocol.Framework; +using Roslyn.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot; + +/// +internal abstract class AbstractCopilotLspServiceDocumentRequestHandler : ILspServiceDocumentRequestHandler +{ + public abstract Task HandleRequestAsync(TRequest request, CopilotRequestContext context, CancellationToken cancellationToken); + public abstract Uri GetTextDocumentUri(TRequest request); + + bool IMethodHandler.MutatesSolutionState => false; + bool ISolutionRequiredHandler.RequiresLSPSolution => true; + + TextDocumentIdentifier ITextDocumentIdentifierHandler.GetTextDocumentIdentifier(TRequest request) + => new() { Uri = GetTextDocumentUri(request) }; + + Task IRequestHandler.HandleRequestAsync(TRequest request, RequestContext context, CancellationToken cancellationToken) + => HandleRequestAsync(request, new CopilotRequestContext(context), cancellationToken); +} diff --git a/src/LanguageServer/ExternalAccess/Copilot/Handler/CopilotRequestContext.cs b/src/LanguageServer/ExternalAccess/Copilot/Handler/CopilotRequestContext.cs new file mode 100644 index 0000000000000..ee5a6713c96bf --- /dev/null +++ b/src/LanguageServer/ExternalAccess/Copilot/Handler/CopilotRequestContext.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; +using Microsoft.CodeAnalysis.LanguageServer.Handler; + +namespace Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot; + +/// +/// Context for requests handled by +/// +internal readonly struct CopilotRequestContext(RequestContext context) +{ + /// + /// The solution state that the request should operate on. + /// + public Solution Solution => context.Solution ?? throw new InvalidOperationException(); + + /// + public Document? Document => context.Document; + + public T GetRequiredService() where T : class => context.GetRequiredService(); +} diff --git a/src/Tools/ExternalAccess/Razor/InternalAPI.Shipped.txt b/src/LanguageServer/ExternalAccess/Copilot/InternalAPI.Shipped.txt similarity index 100% rename from src/Tools/ExternalAccess/Razor/InternalAPI.Shipped.txt rename to src/LanguageServer/ExternalAccess/Copilot/InternalAPI.Shipped.txt diff --git a/src/LanguageServer/ExternalAccess/Copilot/InternalAPI.Unshipped.txt b/src/LanguageServer/ExternalAccess/Copilot/InternalAPI.Unshipped.txt new file mode 100644 index 0000000000000..49ab443409011 --- /dev/null +++ b/src/LanguageServer/ExternalAccess/Copilot/InternalAPI.Unshipped.txt @@ -0,0 +1,20 @@ +#nullable enable +abstract Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot.AbstractCopilotLspServiceDocumentRequestHandler.GetTextDocumentUri(TRequest request) -> System.Uri! +abstract Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot.AbstractCopilotLspServiceDocumentRequestHandler.HandleRequestAsync(TRequest request, Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot.CopilotRequestContext context, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot.AbstractCopilotLspServiceDocumentRequestHandler +Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot.AbstractCopilotLspServiceDocumentRequestHandler.AbstractCopilotLspServiceDocumentRequestHandler() -> void +Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot.CopilotLspServices +Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot.CopilotLspServices.CopilotLspServices() -> void +Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot.CopilotLspServices.CopilotLspServices(Microsoft.CodeAnalysis.LanguageServer.LspServices! lspServices) -> void +Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot.CopilotLspServices.GetService() -> T? +Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot.CopilotMethodAttribute +Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot.CopilotMethodAttribute.CopilotMethodAttribute(string! method) -> void +Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot.CopilotRequestContext +Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot.CopilotRequestContext.CopilotRequestContext() -> void +Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot.CopilotRequestContext.CopilotRequestContext(Microsoft.CodeAnalysis.LanguageServer.Handler.RequestContext context) -> void +Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot.CopilotRequestContext.Document.get -> Microsoft.CodeAnalysis.Document? +Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot.CopilotRequestContext.GetRequiredService() -> T! +Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot.CopilotRequestContext.Solution.get -> Microsoft.CodeAnalysis.Solution! +Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot.ExportCopilotStatelessLspServiceAttribute +Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot.ExportCopilotStatelessLspServiceAttribute.ExportCopilotStatelessLspServiceAttribute(System.Type! type) -> void +Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot.ICopilotLspService \ No newline at end of file diff --git a/src/LanguageServer/ExternalAccess/Copilot/LspServices/CopilotLspServices.cs b/src/LanguageServer/ExternalAccess/Copilot/LspServices/CopilotLspServices.cs new file mode 100644 index 0000000000000..b3b4030c31b38 --- /dev/null +++ b/src/LanguageServer/ExternalAccess/Copilot/LspServices/CopilotLspServices.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot; + +internal readonly struct CopilotLspServices(LspServices lspServices) +{ + public T? GetService() where T : notnull + => lspServices.GetService(); +} diff --git a/src/LanguageServer/ExternalAccess/Copilot/LspServices/CopilotMethodAttribute.cs b/src/LanguageServer/ExternalAccess/Copilot/LspServices/CopilotMethodAttribute.cs new file mode 100644 index 0000000000000..024493d3aafee --- /dev/null +++ b/src/LanguageServer/ExternalAccess/Copilot/LspServices/CopilotMethodAttribute.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.LanguageServer.Handler; + +namespace Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot; + +/// +/// An attribute which identifies the method which a Copilot request handler like +/// implements. +/// +internal sealed class CopilotMethodAttribute(string method) : MethodAttribute(method); diff --git a/src/LanguageServer/ExternalAccess/Copilot/LspServices/ExportCopilotStatelessLspServiceAttribute.cs b/src/LanguageServer/ExternalAccess/Copilot/LspServices/ExportCopilotStatelessLspServiceAttribute.cs new file mode 100644 index 0000000000000..c07744f489501 --- /dev/null +++ b/src/LanguageServer/ExternalAccess/Copilot/LspServices/ExportCopilotStatelessLspServiceAttribute.cs @@ -0,0 +1,12 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Microsoft.CodeAnalysis.LanguageServer.Handler; + +namespace Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot; + +/// +internal sealed class ExportCopilotStatelessLspServiceAttribute(Type type) : + ExportCSharpVisualBasicStatelessLspServiceAttribute(type, WellKnownLspServerKinds.Any); diff --git a/src/LanguageServer/ExternalAccess/Copilot/LspServices/ICopilotLspService.cs b/src/LanguageServer/ExternalAccess/Copilot/LspServices/ICopilotLspService.cs new file mode 100644 index 0000000000000..593eba8b3fbe3 --- /dev/null +++ b/src/LanguageServer/ExternalAccess/Copilot/LspServices/ICopilotLspService.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. + +namespace Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot; + +/// +/// Interface to mark a Copilot LSP service. +/// +internal interface ICopilotLspService : ILspService +{ +} diff --git a/src/LanguageServer/ExternalAccess/Copilot/Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot.csproj b/src/LanguageServer/ExternalAccess/Copilot/Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot.csproj new file mode 100644 index 0000000000000..00cc2c94fe23a --- /dev/null +++ b/src/LanguageServer/ExternalAccess/Copilot/Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot.csproj @@ -0,0 +1,34 @@ + + + + + Library + Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot + netstandard2.0 + + true + Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot + + A supporting package for the GitHub Copilot in Visual Studio Code. + + + + + + + + + + + + + + + + + + + + diff --git a/src/Tools/ExternalAccess/Razor/PublicAPI.Shipped.txt b/src/LanguageServer/ExternalAccess/Copilot/PublicAPI.Shipped.txt similarity index 100% rename from src/Tools/ExternalAccess/Razor/PublicAPI.Shipped.txt rename to src/LanguageServer/ExternalAccess/Copilot/PublicAPI.Shipped.txt diff --git a/src/Tools/ExternalAccess/Razor/PublicAPI.Unshipped.txt b/src/LanguageServer/ExternalAccess/Copilot/PublicAPI.Unshipped.txt similarity index 100% rename from src/Tools/ExternalAccess/Razor/PublicAPI.Unshipped.txt rename to src/LanguageServer/ExternalAccess/Copilot/PublicAPI.Unshipped.txt diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/ExportProviderBuilderTests.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/ExportProviderBuilderTests.cs index 1cc57db6f508f..e7f9da1ce42ea 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/ExportProviderBuilderTests.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/ExportProviderBuilderTests.cs @@ -86,7 +86,7 @@ public async Task CanFindCodeBaseWhenReservedCharactersInPath(string reservedCha var dllPath = GenerateDll(reservedCharacter, out var assemblyName); - await using var testServer = await TestLspServer.CreateAsync(new Roslyn.LanguageServer.Protocol.ClientCapabilities(), TestOutputLogger, MefCacheDirectory.Path, includeDevKitComponents: true, [dllPath]); + await using var testServer = await TestLspServer.CreateAsync(new Roslyn.LanguageServer.Protocol.ClientCapabilities(), LoggerFactory, MefCacheDirectory.Path, includeDevKitComponents: true, [dllPath]); var assemblies = AppDomain.CurrentDomain.GetAssemblies(); var assembly = Assert.Single(assemblies, a => a.GetName().Name == assemblyName); diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/LspFileChangeWatcherTests.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/LspFileChangeWatcherTests.cs index 900cf1a438c89..8cacd0b6bbb71 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/LspFileChangeWatcherTests.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/LspFileChangeWatcherTests.cs @@ -28,7 +28,7 @@ public class LspFileChangeWatcherTests(ITestOutputHelper testOutputHelper) [Fact] public async Task LspFileWatcherNotSupportedWithoutClientSupport() { - await using var testLspServer = await TestLspServer.CreateAsync(new ClientCapabilities(), TestOutputLogger, MefCacheDirectory.Path); + await using var testLspServer = await TestLspServer.CreateAsync(new ClientCapabilities(), LoggerFactory, MefCacheDirectory.Path); Assert.False(LspFileChangeWatcher.SupportsLanguageServerHost(testLspServer.LanguageServerHost)); } @@ -36,7 +36,7 @@ public async Task LspFileWatcherNotSupportedWithoutClientSupport() [Fact] public async Task LspFileWatcherSupportedWithClientSupport() { - await using var testLspServer = await TestLspServer.CreateAsync(_clientCapabilitiesWithFileWatcherSupport, TestOutputLogger, MefCacheDirectory.Path); + await using var testLspServer = await TestLspServer.CreateAsync(_clientCapabilitiesWithFileWatcherSupport, LoggerFactory, MefCacheDirectory.Path); Assert.True(LspFileChangeWatcher.SupportsLanguageServerHost(testLspServer.LanguageServerHost)); } @@ -46,7 +46,7 @@ public async Task CreatingDirectoryWatchRequestsDirectoryWatch() { AsynchronousOperationListenerProvider.Enable(enable: true); - await using var testLspServer = await TestLspServer.CreateAsync(_clientCapabilitiesWithFileWatcherSupport, TestOutputLogger, MefCacheDirectory.Path); + await using var testLspServer = await TestLspServer.CreateAsync(_clientCapabilitiesWithFileWatcherSupport, LoggerFactory, MefCacheDirectory.Path); var lspFileChangeWatcher = new LspFileChangeWatcher( testLspServer.LanguageServerHost, testLspServer.ExportProvider.GetExportedValue()); @@ -76,7 +76,7 @@ public async Task CreatingFileWatchRequestsFileWatch() { AsynchronousOperationListenerProvider.Enable(enable: true); - await using var testLspServer = await TestLspServer.CreateAsync(_clientCapabilitiesWithFileWatcherSupport, TestOutputLogger, MefCacheDirectory.Path); + await using var testLspServer = await TestLspServer.CreateAsync(_clientCapabilitiesWithFileWatcherSupport, LoggerFactory, MefCacheDirectory.Path); var lspFileChangeWatcher = new LspFileChangeWatcher( testLspServer.LanguageServerHost, testLspServer.ExportProvider.GetExportedValue()); 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 1a0f088e2eed0..0f61561851842 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 @@ -15,6 +15,11 @@ + + + + + diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/TelemetryReporterTests.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/TelemetryReporterTests.cs index 641514d4eff5d..0a678d0b4fd44 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/TelemetryReporterTests.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/TelemetryReporterTests.cs @@ -15,7 +15,7 @@ public sealed class TelemetryReporterTests(ITestOutputHelper testOutputHelper) private async Task CreateReporterAsync() { var exportProvider = await LanguageServerTestComposition.CreateExportProviderAsync( - TestOutputLogger.Factory, + LoggerFactory, includeDevKitComponents: true, MefCacheDirectory.Path, [], diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerClientTests.TestLspClient.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerClientTests.TestLspClient.cs index d3dcb2f7f6b91..b55dfe6160fdd 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerClientTests.TestLspClient.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerClientTests.TestLspClient.cs @@ -26,7 +26,7 @@ internal sealed class TestLspClient : ILspClient, IAsyncDisposable private readonly Process _process; private readonly Dictionary _documents; private readonly Dictionary> _locations; - private readonly TestOutputLogger _logger; + private readonly ILoggerFactory _loggerFactory; private readonly JsonRpc _clientRpc; @@ -37,7 +37,7 @@ internal static async Task CreateAsync( string extensionLogsPath, bool includeDevKitComponents, bool debugLsp, - TestOutputLogger logger, + ILoggerFactory loggerFactory, Dictionary? documents = null, Dictionary>? locations = null) { @@ -47,7 +47,7 @@ internal static async Task CreateAsync( var process = Process.Start(processStartInfo); Assert.NotNull(process); - var lspClient = new TestLspClient(process, pipeName, documents ?? [], locations ?? [], logger); + var lspClient = new TestLspClient(process, pipeName, documents ?? [], locations ?? [], loggerFactory); // We've subscribed to Disconnected, but if the process crashed before that point we might have not seen it if (process.HasExited) @@ -124,11 +124,11 @@ static ProcessStartInfo CreateLspStartInfo(string pipeName, string extensionLogs internal ServerCapabilities ServerCapabilities => _serverCapabilities ?? throw new InvalidOperationException("Initialize has not been called"); - private TestLspClient(Process process, string pipeName, Dictionary documents, Dictionary> locations, TestOutputLogger logger) + private TestLspClient(Process process, string pipeName, Dictionary documents, Dictionary> locations, ILoggerFactory loggerFactory) { _documents = documents; _locations = locations; - _logger = logger; + _loggerFactory = loggerFactory; _process = process; _process.EnableRaisingEvents = true; @@ -160,6 +160,8 @@ private TestLspClient(Process process, string pipeName, Dictionary GetMessageLogger(string method) { + var logger = _loggerFactory.CreateLogger($"LSP {method}"); + return (int type, string message) => { var logLevel = (MessageType)type switch @@ -171,19 +173,20 @@ Action GetMessageLogger(string method) MessageType.Debug => LogLevel.Debug, _ => LogLevel.Trace, }; - _logger.Log(logLevel, "[LSP {Method}] {Message}", method, message); + + logger.Log(logLevel, message); }; } } private void Process_OutputDataReceived(object sender, DataReceivedEventArgs e) { - _logger.LogInformation("[LSP STDOUT] {Data}", e.Data); + _loggerFactory.CreateLogger("LSP STDOUT").LogInformation(e.Data); } private void Process_ErrorDataReceived(object sender, DataReceivedEventArgs e) { - _logger.LogCritical("[LSP STDERR] {Data}", e.Data); + _loggerFactory.CreateLogger("LSP STDERR").LogInformation(e.Data); } public async Task ExecuteRequestAsync(string methodName, TRequestType request, CancellationToken cancellationToken) where TRequestType : class @@ -249,9 +252,11 @@ public async ValueTask DisposeAsync() if (Interlocked.CompareExchange(ref _disposed, value: 1, comparand: 0) != 0) return; + var logger = _loggerFactory.CreateLogger("Shutdown"); + if (!_process.HasExited) { - _logger.LogTrace("Sending a Shutdown request to the LSP."); + logger.LogTrace("Sending a Shutdown request to the LSP."); await _clientRpc.InvokeAsync(Methods.ShutdownName); await _clientRpc.NotifyAsync(Methods.ExitName); @@ -262,7 +267,7 @@ public async ValueTask DisposeAsync() _clientRpc.Dispose(); _process.Dispose(); - _logger.LogTrace("Process shut down."); + logger.LogTrace("Process shut down."); } } } diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerClientTests.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerClientTests.cs index 72fd371bb1504..971033a4d5d12 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerClientTests.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerClientTests.cs @@ -8,6 +8,8 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.UnitTests; +using Microsoft.Extensions.Logging; using Roslyn.LanguageServer.Protocol; using Roslyn.Test.Utilities; using Roslyn.Utilities; @@ -18,7 +20,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests; public abstract partial class AbstractLanguageServerClientTests(ITestOutputHelper testOutputHelper) : IDisposable { - protected TestOutputLogger TestOutputLogger => new(testOutputHelper); + protected ILoggerFactory LoggerFactory => new LoggerFactory([new TestOutputLoggerProvider(testOutputHelper)]); protected TempRoot TempRoot => new(); protected TempDirectory ExtensionLogsDirectory => TempRoot.CreateDirectory(); @@ -69,7 +71,7 @@ await File.WriteAllTextAsync(projectPath, $""" ExtensionLogsDirectory.Path, includeDevKitComponents, debugLsp, - TestOutputLogger, + LoggerFactory, documents: files, locations: annotatedLocations); diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerHostTests.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerHostTests.cs index b543d17c01d00..ae12838c614a2 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerHostTests.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerHostTests.cs @@ -4,6 +4,8 @@ using Microsoft.CodeAnalysis.LanguageServer.LanguageServer; using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.UnitTests; +using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.Composition; using Nerdbank.Streams; using Roslyn.LanguageServer.Protocol; @@ -14,20 +16,20 @@ namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests; public abstract class AbstractLanguageServerHostTests : IDisposable { - protected TestOutputLogger TestOutputLogger { get; } + protected ILoggerFactory LoggerFactory { get; } protected TempRoot TempRoot { get; } protected TempDirectory MefCacheDirectory { get; } protected AbstractLanguageServerHostTests(ITestOutputHelper testOutputHelper) { - TestOutputLogger = new TestOutputLogger(testOutputHelper); + LoggerFactory = new LoggerFactory([new TestOutputLoggerProvider(testOutputHelper)]); TempRoot = new(); MefCacheDirectory = TempRoot.CreateDirectory(); } protected Task CreateLanguageServerAsync(bool includeDevKitComponents = true) { - return TestLspServer.CreateAsync(new ClientCapabilities(), TestOutputLogger, MefCacheDirectory.Path, includeDevKitComponents); + return TestLspServer.CreateAsync(new ClientCapabilities(), LoggerFactory, MefCacheDirectory.Path, includeDevKitComponents); } public void Dispose() @@ -42,11 +44,11 @@ protected sealed class TestLspServer : ILspClient, IAsyncDisposable private ServerCapabilities? _serverCapabilities; - internal static async Task CreateAsync(ClientCapabilities clientCapabilities, TestOutputLogger logger, string cacheDirectory, bool includeDevKitComponents = true, string[]? extensionPaths = null) + internal static async Task CreateAsync(ClientCapabilities clientCapabilities, ILoggerFactory loggerFactory, string cacheDirectory, bool includeDevKitComponents = true, string[]? extensionPaths = null) { var exportProvider = await LanguageServerTestComposition.CreateExportProviderAsync( - logger.Factory, includeDevKitComponents, cacheDirectory, extensionPaths, out var _, out var assemblyLoader); - var testLspServer = new TestLspServer(exportProvider, logger, assemblyLoader); + loggerFactory, includeDevKitComponents, cacheDirectory, extensionPaths, out var _, out var assemblyLoader); + var testLspServer = new TestLspServer(exportProvider, loggerFactory, assemblyLoader); var initializeResponse = await testLspServer.ExecuteRequestAsync(Methods.InitializeName, new InitializeParams { Capabilities = clientCapabilities }, CancellationToken.None); Assert.NotNull(initializeResponse?.Capabilities); testLspServer._serverCapabilities = initializeResponse!.Capabilities; @@ -61,12 +63,12 @@ internal static async Task CreateAsync(ClientCapabilities clientC internal ServerCapabilities ServerCapabilities => _serverCapabilities ?? throw new InvalidOperationException("Initialize has not been called"); - private TestLspServer(ExportProvider exportProvider, TestOutputLogger logger, IAssemblyLoader assemblyLoader) + private TestLspServer(ExportProvider exportProvider, ILoggerFactory loggerFactory, IAssemblyLoader assemblyLoader) { - var typeRefResolver = new ExtensionTypeRefResolver(assemblyLoader, logger.Factory); + var typeRefResolver = new ExtensionTypeRefResolver(assemblyLoader, loggerFactory); var (clientStream, serverStream) = FullDuplexStream.CreatePair(); - LanguageServerHost = new LanguageServerHost(serverStream, serverStream, exportProvider, logger, typeRefResolver); + LanguageServerHost = new LanguageServerHost(serverStream, serverStream, exportProvider, loggerFactory.CreateLogger(), typeRefResolver); var messageFormatter = RoslynLanguageServer.CreateJsonMessageFormatter(); _clientRpc = new JsonRpc(new HeaderDelimitedMessageHandler(clientStream, clientStream, messageFormatter)) diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/TestLoggerProvider.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/TestLoggerProvider.cs deleted file mode 100644 index 3ebda77fd10db..0000000000000 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/TestLoggerProvider.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Extensions.Logging; - -namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests; - -internal class TestLoggerProvider : ILoggerProvider -{ - private readonly ILogger _testLogger; - public TestLoggerProvider(ILogger testLogger) - { - _testLogger = testLogger; - } - - public ILogger CreateLogger(string categoryName) - { - return _testLogger; - } - - public void Dispose() - { - } -} diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/TestOutputLogger.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/TestOutputLogger.cs deleted file mode 100644 index ea77589b3d0f7..0000000000000 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/TestOutputLogger.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Extensions.Logging; -using Xunit.Abstractions; - -namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests; - -public class TestOutputLogger : ILogger -{ - private readonly ITestOutputHelper _testOutputHelper; - public readonly ILoggerFactory Factory; - - public TestOutputLogger(ITestOutputHelper testOutputHelper) - { - _testOutputHelper = testOutputHelper; - Factory = new LoggerFactory([new TestLoggerProvider(this)]); - } - - public IDisposable BeginScope(TState state) where TState : notnull - { - return new NoOpDisposable(); - } - - public bool IsEnabled(LogLevel logLevel) - { - return true; - } - - public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) - { - _testOutputHelper.WriteLine($"[{DateTime.UtcNow:hh:mm:ss.fff}][{logLevel}]{formatter(state, exception)}"); - } - - private sealed class NoOpDisposable : IDisposable - { - public void Dispose() - { - } - } -} diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/MefServiceBrokerOfExportedServices.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/MefServiceBrokerOfExportedServices.cs index 2e6436f80af37..c50758a7db4c3 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/MefServiceBrokerOfExportedServices.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/MefServiceBrokerOfExportedServices.cs @@ -6,7 +6,6 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.VisualStudio.Shell.ServiceBroker; using Microsoft.VisualStudio.Utilities.ServiceBroker; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.BrokeredServices; diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/ServiceBrokerFactory.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/ServiceBrokerFactory.cs index 4f8294626029f..4e6b65efb69a7 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/ServiceBrokerFactory.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/ServiceBrokerFactory.cs @@ -9,7 +9,6 @@ using Microsoft.ServiceHub.Framework; using Microsoft.VisualStudio.Composition; using Microsoft.VisualStudio.Shell.ServiceBroker; -using Roslyn.Utilities; using ExportProvider = Microsoft.VisualStudio.Composition.ExportProvider; namespace Microsoft.CodeAnalysis.LanguageServer.BrokeredServices; diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/Services/BrokeredServiceBridgeManifest/BrokeredServiceBridgeManifestService.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/Services/BrokeredServiceBridgeManifest/BrokeredServiceBridgeManifestService.cs index b77955279d70b..a789a3d276ea0 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/Services/BrokeredServiceBridgeManifest/BrokeredServiceBridgeManifestService.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/Services/BrokeredServiceBridgeManifest/BrokeredServiceBridgeManifestService.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.Immutable; using System.ComponentModel.Composition; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.Extensions.Logging; diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/WrappedServiceBroker.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/WrappedServiceBroker.cs index 5acad362275c8..ae04a1b06efe7 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/WrappedServiceBroker.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/WrappedServiceBroker.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. @@ -8,7 +8,6 @@ using Microsoft.ServiceHub.Framework; using Microsoft.VisualStudio.Composition; using Microsoft.VisualStudio.Shell.ServiceBroker; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.BrokeredServices; #pragma warning restore RS0030 // Do not used banned APIs diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LanguageServerProjectSystem.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LanguageServerProjectSystem.cs index 781feabf5d46e..9a6376252f3cf 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LanguageServerProjectSystem.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LanguageServerProjectSystem.cs @@ -16,6 +16,7 @@ using Microsoft.CodeAnalysis.ProjectSystem; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Shared.Utilities; +using Microsoft.CodeAnalysis.Threading; using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.Composition; diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LanguageServerWorkspaceFactory.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LanguageServerWorkspaceFactory.cs index 9822e7020a5ab..2461b9b2c136c 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LanguageServerWorkspaceFactory.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LanguageServerWorkspaceFactory.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServer.Handler.DebugConfiguration; using Microsoft.CodeAnalysis.ProjectSystem; -using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.Composition; @@ -43,7 +42,8 @@ public LanguageServerWorkspaceFactory( var razorSourceGenerator = serverConfigurationFactory?.ServerConfiguration?.RazorSourceGenerator; ProjectSystemHostInfo = new ProjectSystemHostInfo( DynamicFileInfoProviders: [.. dynamicFileInfoProviders], - new HostDiagnosticAnalyzerProvider(razorSourceGenerator)); + new HostDiagnosticAnalyzerProvider(razorSourceGenerator), + AnalyzerAssemblyRedirectors: []); TargetFrameworkManager = projectTargetFrameworkManager; } diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LoadedProject.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LoadedProject.cs index 72a9d11a5612e..c2cae1e5418ee 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LoadedProject.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LoadedProject.cs @@ -133,6 +133,7 @@ public void Dispose() _projectSystemProject.OutputRefFilePath = newProjectInfo.OutputRefFilePath; _projectSystemProject.GeneratedFilesOutputDirectory = newProjectInfo.GeneratedFilesOutputDirectory; _projectSystemProject.CompilationOutputAssemblyFilePath = newProjectInfo.IntermediateOutputFilePath; + _projectSystemProject.DefaultNamespace = newProjectInfo.DefaultNamespace; if (newProjectInfo.TargetFrameworkIdentifier != null) { diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/ProjectDependencyHelper.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/ProjectDependencyHelper.cs index e52224ce1e0aa..f94f1f82d111c 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/ProjectDependencyHelper.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/ProjectDependencyHelper.cs @@ -11,7 +11,6 @@ using NuGet.ProjectModel; using NuGet.Versioning; using Roslyn.Utilities; -using StreamJsonRpc; namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace; internal static class ProjectDependencyHelper diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorClientLanguageServerManagerFactory.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorClientLanguageServerManagerFactory.cs new file mode 100644 index 0000000000000..dcdb0854b7425 --- /dev/null +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorClientLanguageServerManagerFactory.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.Composition; +using Microsoft.CodeAnalysis.ExternalAccess.Razor; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.LanguageServer; + +namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.Razor; + +[Shared] +[ExportLspServiceFactory(typeof(IRazorClientLanguageServerManager), ProtocolConstants.RoslynLspLanguagesContract)] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal class RazorClientLanguageServerManagerFactory() : ILspServiceFactory +{ + public ILspService CreateILspService(LspServices lspServices, WellKnownLspServerKinds serverKind) + { + var notificationManager = lspServices.GetRequiredService(); + + return new RazorClientLanguageServerManager(notificationManager); + } +} diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileChangedHandler.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileChangedHandler.cs deleted file mode 100644 index 48c1c3fa8595f..0000000000000 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileChangedHandler.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServer.Handler; - -namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.Razor; - -[Shared] -[ExportCSharpVisualBasicStatelessLspService(typeof(RazorDynamicFileChangedHandler))] -[Method("razor/dynamicFileInfoChanged")] -internal class RazorDynamicFileChangedHandler : ILspServiceNotificationHandler -{ - private readonly RazorDynamicFileInfoProvider _razorDynamicFileInfoProvider; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public RazorDynamicFileChangedHandler(RazorDynamicFileInfoProvider razorDynamicFileInfoProvider) - { - _razorDynamicFileInfoProvider = razorDynamicFileInfoProvider; - } - - public bool MutatesSolutionState => false; - public bool RequiresLSPSolution => false; - - public Task HandleNotificationAsync(RazorDynamicFileChangedParams request, RequestContext requestContext, CancellationToken cancellationToken) - { - var filePath = ProtocolConversions.GetDocumentFilePathFromUri(request.RazorDocument.Uri); - _razorDynamicFileInfoProvider.Update(filePath); - return Task.CompletedTask; - } -} diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileChangedParams.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileChangedParams.cs deleted file mode 100644 index 73a2cf4dd186c..0000000000000 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileChangedParams.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Text.Json.Serialization; -using Roslyn.LanguageServer.Protocol; - -namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.Razor; - -internal class RazorDynamicFileChangedParams -{ - [JsonPropertyName("razorDocument")] - public required TextDocumentIdentifier RazorDocument { get; set; } -} diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileInfoProvider.TextChangesTextLoader.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileInfoProvider.TextChangesTextLoader.cs deleted file mode 100644 index 0f62d58b1d221..0000000000000 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileInfoProvider.TextChangesTextLoader.cs +++ /dev/null @@ -1,113 +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; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.LanguageServer.LanguageServer; -using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.Razor; - -internal partial class RazorDynamicFileInfoProvider -{ - private sealed class TextChangesTextLoader( - TextDocument? document, - IEnumerable updates, - byte[] checksum, - SourceHashAlgorithm checksumAlgorithm, - int? codePage, - Uri razorUri) : TextLoader - { - private readonly TextDocument? _document = document; - private readonly IEnumerable _updates = updates; - private readonly byte[] _checksum = checksum; - private readonly SourceHashAlgorithm _checksumAlgorithm = checksumAlgorithm; - private readonly int? _codePage = codePage; - private readonly Uri _razorUri = razorUri; - - private readonly Lazy _emptySourceText = new Lazy(() => - { - var encoding = codePage is null ? null : Encoding.GetEncoding(codePage.Value); - return SourceText.From("", checksumAlgorithm: checksumAlgorithm, encoding: encoding); - }); - - public override async Task LoadTextAndVersionAsync(LoadTextOptions options, CancellationToken cancellationToken) - { - if (_document is null) - { - var text = UpdateSourceTextWithEdits(_emptySourceText.Value, _updates); - return TextAndVersion.Create(text, VersionStamp.Default.GetNewerVersion()); - } - - var sourceText = await _document.GetTextAsync(cancellationToken).ConfigureAwait(false); - - // Validate the checksum information so the edits are known to be correct - if (IsSourceTextMatching(sourceText)) - { - var version = await _document.GetTextVersionAsync(cancellationToken).ConfigureAwait(false); - var newText = UpdateSourceTextWithEdits(sourceText, _updates); - return TextAndVersion.Create(newText, version.GetNewerVersion()); - } - - return await GetFullDocumentFromServerAsync(cancellationToken).ConfigureAwait(false); - } - - private bool IsSourceTextMatching(SourceText sourceText) - { - if (sourceText.ChecksumAlgorithm != _checksumAlgorithm) - { - return false; - } - - if (sourceText.Encoding?.CodePage != _codePage) - { - return false; - } - - if (!sourceText.GetChecksum().SequenceEqual(_checksum)) - { - return false; - } - - return true; - } - - private async Task GetFullDocumentFromServerAsync(CancellationToken cancellationToken) - { - Contract.ThrowIfNull(LanguageServerHost.Instance, "We don't have an LSP channel yet to send this request through."); - var clientLanguageServerManager = LanguageServerHost.Instance.GetRequiredLspService(); - - var response = await clientLanguageServerManager.SendRequestAsync( - ProvideRazorDynamicFileInfoMethodName, - new RazorProvideDynamicFileParams - { - RazorDocument = new() - { - Uri = _razorUri, - }, - FullText = true - }, - cancellationToken); - - RoslynDebug.AssertNotNull(response.Updates); - RoslynDebug.Assert(response.Updates.IsSingle()); - - var text = UpdateSourceTextWithEdits(_emptySourceText.Value, response.Updates); - return TextAndVersion.Create(text, VersionStamp.Default.GetNewerVersion()); - } - - private static SourceText UpdateSourceTextWithEdits(SourceText sourceText, IEnumerable updates) - { - foreach (var update in updates) - { - var changes = update.Edits.Select(e => new TextChange(e.Span.ToTextSpan(), e.NewText)); - sourceText = sourceText.WithChanges(changes); - } - - return sourceText; - } - } - -} diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileInfoProvider.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileInfoProvider.cs index b064fb31132c3..07d0ecc9a73f6 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileInfoProvider.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileInfoProvider.cs @@ -3,145 +3,80 @@ // See the LICENSE file in the project root for more information. using System.Composition; -using System.Text; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Collections; +using Microsoft.CodeAnalysis.ExternalAccess.Razor.Features; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServer.LanguageServer; -using Microsoft.CodeAnalysis.Shared.TestHooks; -using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; +using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Microsoft.Extensions.Logging; +using Roslyn.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.Razor; [Shared] [Export(typeof(IDynamicFileInfoProvider))] -[Export(typeof(RazorDynamicFileInfoProvider))] +[ExportRazorStatelessLspService(typeof(RazorDynamicFileInfoProvider))] [ExportMetadata("Extensions", new string[] { "cshtml", "razor", })] -internal partial class RazorDynamicFileInfoProvider : IDynamicFileInfoProvider +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal partial class RazorDynamicFileInfoProvider(Lazy workspaceFactory, ILoggerFactory loggerFactory) : IDynamicFileInfoProvider, ILspService, IOnInitialized { - private const string ProvideRazorDynamicFileInfoMethodName = "razor/provideDynamicFileInfo"; - private const string RemoveRazorDynamicFileInfoMethodName = "razor/removeDynamicFileInfo"; - - private readonly Lazy _razorWorkspaceListenerInitializer; - private readonly LanguageServerWorkspaceFactory _workspaceFactory; - private readonly AsyncBatchingWorkQueue _updateWorkQueue; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public RazorDynamicFileInfoProvider( - Lazy razorWorkspaceListenerInitializer, - LanguageServerWorkspaceFactory workspaceFactory, - IAsynchronousOperationListenerProvider listenerProvider) - { - _razorWorkspaceListenerInitializer = razorWorkspaceListenerInitializer; - _updateWorkQueue = new AsyncBatchingWorkQueue( - TimeSpan.FromMilliseconds(200), - UpdateAsync, - listenerProvider.GetListener(nameof(RazorDynamicFileInfoProvider)), - CancellationToken.None); - _workspaceFactory = workspaceFactory; - } + private RazorWorkspaceService? _razorWorkspaceService; + private RazorLspDynamicFileInfoProvider? _dynamicFileInfoProvider; public event EventHandler? Updated; - public void Update(string filePath) - { - _updateWorkQueue.AddWork(filePath); - } + private readonly ILogger _logger = loggerFactory.CreateLogger(); public async Task GetDynamicFileInfoAsync(ProjectId projectId, string? projectFilePath, string filePath, CancellationToken cancellationToken) { - _razorWorkspaceListenerInitializer.Value.NotifyDynamicFile(projectId); - - var razorUri = ProtocolConversions.CreateAbsoluteUri(filePath); - var requestParams = new RazorProvideDynamicFileParams - { - RazorDocument = new() - { - Uri = razorUri - } - }; - - Contract.ThrowIfNull(LanguageServerHost.Instance, "We don't have an LSP channel yet to send this request through."); - var clientLanguageServerManager = LanguageServerHost.Instance.GetRequiredLspService(); - - var response = await clientLanguageServerManager.SendRequestAsync( - ProvideRazorDynamicFileInfoMethodName, requestParams, cancellationToken); - - if (response.CSharpDocument is null) + if (_dynamicFileInfoProvider is null || _razorWorkspaceService is null) { return null; } - // Since we only sent one file over, we should get either zero or one URI back - var responseUri = response.CSharpDocument.Uri; - var dynamicFileInfoFilePath = ProtocolConversions.GetDocumentFilePathFromUri(responseUri); + _razorWorkspaceService.NotifyDynamicFile(projectId); - if (response.Updates is not null) + var dynamicInfo = await _dynamicFileInfoProvider.GetDynamicFileInfoAsync(workspaceFactory.Value.Workspace, projectId, projectFilePath, filePath, cancellationToken).ConfigureAwait(false); + if (dynamicInfo is null) { - var textDocument = await _workspaceFactory.Workspace.CurrentSolution.GetTextDocumentAsync(response.CSharpDocument, cancellationToken).ConfigureAwait(false); - var checksum = Convert.FromBase64String(response.Checksum); - var textLoader = new TextChangesTextLoader( - textDocument, - response.Updates, - checksum, - response.ChecksumAlgorithm, - response.SourceEncodingCodePage, - razorUri); - - return new DynamicFileInfo( - dynamicFileInfoFilePath, - SourceCodeKind.Regular, - textLoader, - designTimeOnly: true, - documentServiceProvider: null); + return null; } return new DynamicFileInfo( - dynamicFileInfoFilePath, - SourceCodeKind.Regular, - EmptyStringTextLoader.Instance, + dynamicInfo.FilePath, + dynamicInfo.SourceCodeKind, + dynamicInfo.TextLoader, designTimeOnly: true, documentServiceProvider: null); } - public Task RemoveDynamicFileInfoAsync(ProjectId projectId, string? projectFilePath, string filePath, CancellationToken cancellationToken) + public Task OnInitializedAsync(ClientCapabilities clientCapabilities, RequestContext context, CancellationToken cancellationToken) { - var notificationParams = new RazorRemoveDynamicFileParams - { - 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(); - - return clientLanguageServerManager.SendNotificationAsync( - RemoveRazorDynamicFileInfoMethodName, notificationParams, cancellationToken).AsTask(); - } + _razorWorkspaceService = context.GetService(); + _dynamicFileInfoProvider = context.GetService(); - private ValueTask UpdateAsync(ImmutableSegmentedList paths, CancellationToken token) - { - foreach (var path in paths) + if (_razorWorkspaceService is null || _dynamicFileInfoProvider is null) { - token.ThrowIfCancellationRequested(); - Updated?.Invoke(this, path); + _logger.LogError("RazorDynamicFileInfoProvider not initialized. RazorWorkspaceService or RazorLspDynamicFileInfoProvider is null."); + return Task.CompletedTask; } - return ValueTask.CompletedTask; + _dynamicFileInfoProvider.Updated += (s, uri) => + { + var filePath = ProtocolConversions.GetDocumentFilePathFromUri(uri); + Updated?.Invoke(this, filePath); + }; + + return Task.CompletedTask; } - private sealed class EmptyStringTextLoader() : TextLoader + public async Task RemoveDynamicFileInfoAsync(ProjectId projectId, string? projectFilePath, string filePath, CancellationToken cancellationToken) { - public static readonly TextLoader Instance = new EmptyStringTextLoader(); - - public override Task LoadTextAndVersionAsync(LoadTextOptions options, CancellationToken cancellationToken) + if (_dynamicFileInfoProvider is null) { - return Task.FromResult(TextAndVersion.Create(SourceText.From(""), VersionStamp.Default)); + return; } + + await _dynamicFileInfoProvider.RemoveDynamicFileInfoAsync(workspaceFactory.Value.Workspace, projectId, projectFilePath, filePath, cancellationToken).ConfigureAwait(false); } } diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileUpdate.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileUpdate.cs deleted file mode 100644 index 4853793e33e84..0000000000000 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileUpdate.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. - -using System.Text.Json.Serialization; -using Microsoft.CodeAnalysis.Text; -using Roslyn.LanguageServer.Protocol; - -namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.Razor; - -class RazorDynamicFileUpdate -{ - [JsonPropertyName("edits")] - public required ServerTextChange[] Edits { get; set; } -} diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorInitializeHandler.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorInitializeHandler.cs deleted file mode 100644 index 546b0a3f6edd7..0000000000000 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorInitializeHandler.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.Composition; -using System.Text.Json.Serialization; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServer.Handler; -using Microsoft.CommonLanguageServerProtocol.Framework; - -namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.Razor; - -[ExportCSharpVisualBasicStatelessLspService(typeof(RazorInitializeHandler)), Shared] -[Method("razor/initialize")] -internal class RazorInitializeHandler : ILspServiceNotificationHandler -{ - private readonly Lazy _razorWorkspaceListenerInitializer; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public RazorInitializeHandler(Lazy razorWorkspaceListenerInitializer) - { - _razorWorkspaceListenerInitializer = razorWorkspaceListenerInitializer; - } - - public bool MutatesSolutionState => false; - public bool RequiresLSPSolution => false; - - Task INotificationHandler.HandleNotificationAsync(RazorInitializeParams request, RequestContext requestContext, CancellationToken cancellationToken) - { - _razorWorkspaceListenerInitializer.Value.Initialize(request.PipeName); - - return Task.CompletedTask; - } -} - -internal class RazorInitializeParams -{ - [JsonPropertyName("pipeName")] - public required string PipeName { get; set; } -} diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorProvideDynamicFileParams.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorProvideDynamicFileParams.cs deleted file mode 100644 index 1d6f4a24dbd22..0000000000000 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorProvideDynamicFileParams.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.Text.Json.Serialization; -using Roslyn.LanguageServer.Protocol; - -namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.Razor; - -internal class RazorProvideDynamicFileParams -{ - [JsonPropertyName("razorDocument")] - public required TextDocumentIdentifier RazorDocument { get; set; } - - /// - /// When true, the full text of the document will be sent over as a single - /// edit instead of diff edits - /// - [JsonPropertyName("fullText")] - public bool FullText { get; set; } -} diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorProvideDynamicFileResponse.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorProvideDynamicFileResponse.cs deleted file mode 100644 index 6d51c27199d86..0000000000000 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorProvideDynamicFileResponse.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Text.Json.Serialization; -using Microsoft.CodeAnalysis.Text; -using Roslyn.LanguageServer.Protocol; - -namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.Razor; - -internal class RazorProvideDynamicFileResponse -{ - [JsonPropertyName("csharpDocument")] - public required TextDocumentIdentifier CSharpDocument { get; set; } - - [JsonPropertyName("updates")] - public RazorDynamicFileUpdate[]? Updates { get; set; } - - [JsonPropertyName("checksum")] - public required string Checksum { get; set; } - - [JsonPropertyName("checksumAlgorithm")] - public SourceHashAlgorithm ChecksumAlgorithm { get; set; } - - [JsonPropertyName("encodingCodePage")] - public int? SourceEncodingCodePage { get; set; } -} diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorRemoveDynamicFileParams.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorRemoveDynamicFileParams.cs deleted file mode 100644 index 2388208108769..0000000000000 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorRemoveDynamicFileParams.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Text.Json.Serialization; -using Roslyn.LanguageServer.Protocol; - -namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.Razor; - -internal class RazorRemoveDynamicFileParams -{ - [JsonPropertyName("csharpDocument")] - public required TextDocumentIdentifier CSharpDocument { get; set; } -} diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorWorkspaceListenerInitializer.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorWorkspaceListenerInitializer.cs deleted file mode 100644 index 80d366ca58c13..0000000000000 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorWorkspaceListenerInitializer.cs +++ /dev/null @@ -1,80 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Composition; -using Microsoft.AspNetCore.Razor.ExternalAccess.RoslynWorkspace; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.Extensions.Logging; - -namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.Razor; - -[Export(typeof(RazorWorkspaceListenerInitializer)), Shared] -internal sealed class RazorWorkspaceListenerInitializer -{ - private readonly ILogger _logger; - private readonly Workspace _workspace; - private readonly ILoggerFactory _loggerFactory; - - // Locks all access to _razorWorkspaceListener and _projectIdWithDynamicFiles - private readonly object _initializeGate = new(); - private HashSet _projectIdWithDynamicFiles = []; - - private RazorWorkspaceListener? _razorWorkspaceListener; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public RazorWorkspaceListenerInitializer(LanguageServerWorkspaceFactory workspaceFactory, ILoggerFactory loggerFactory) - { - _logger = loggerFactory.CreateLogger(nameof(RazorWorkspaceListenerInitializer)); - - _workspace = workspaceFactory.Workspace; - _loggerFactory = loggerFactory; - } - - internal void Initialize(string pipeName) - { - HashSet projectsToInitialize; - lock (_initializeGate) - { - // Only initialize once - if (_razorWorkspaceListener is not null) - { - return; - } - - _logger.LogTrace("Initializing the Razor workspace listener with pipe name {0}", pipeName); - _razorWorkspaceListener = new RazorWorkspaceListener(_loggerFactory); - _razorWorkspaceListener.EnsureInitialized(_workspace, pipeName); - - projectsToInitialize = _projectIdWithDynamicFiles; - // May as well clear out the collection, it will never get used again anyway. - _projectIdWithDynamicFiles = []; - } - - foreach (var projectId in projectsToInitialize) - { - _logger.LogTrace("{projectId} notifying a dynamic file for the first time", projectId); - _razorWorkspaceListener.NotifyDynamicFile(projectId); - } - } - - internal void NotifyDynamicFile(ProjectId projectId) - { - lock (_initializeGate) - { - if (_razorWorkspaceListener is null) - { - // We haven't been initialized by the extension yet, so just store the project id, to tell Razor later - _logger.LogTrace("{projectId} queuing up a dynamic file notify for later", projectId); - _projectIdWithDynamicFiles.Add(projectId); - - return; - } - } - - // We've been initialized, so just pass the information along - _logger.LogTrace("{projectId} forwarding on a dynamic file notification because we're initialized", projectId); - _razorWorkspaceListener.NotifyDynamicFile(projectId); - } -} diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/ServerTextChange.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/ServerTextChange.cs deleted file mode 100644 index 272a69316d4b0..0000000000000 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/ServerTextChange.cs +++ /dev/null @@ -1,16 +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 Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.Razor; - -internal class ServerTextChange -{ - [JsonPropertyName("span")] - public required ServerTextSpan Span { get; set; } - - [JsonPropertyName("newText")] - public required string NewText { get; set; } -} diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/ServerTextSpan.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/ServerTextSpan.cs deleted file mode 100644 index 80d3d035aeb3e..0000000000000 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/ServerTextSpan.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Text.Json.Serialization; -using Microsoft.CodeAnalysis.Text; - -namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.Razor; - -internal class ServerTextSpan -{ - [JsonPropertyName("start")] - public int Start { get; set; } - - [JsonPropertyName("length")] - public int Length { get; set; } - - public TextSpan ToTextSpan() - => new(Start, Length); -} diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/WorkspaceProject.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/WorkspaceProject.cs index daa449f14596d..954d292b2c95b 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/WorkspaceProject.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/WorkspaceProject.cs @@ -7,7 +7,6 @@ using Microsoft.CodeAnalysis.Remote.ProjectSystem; using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; using Microsoft.Extensions.Logging; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace; diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/WorkspaceProjectFactoryService.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/WorkspaceProjectFactoryService.cs index 255be35a19bd2..eba2a8218aff9 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/WorkspaceProjectFactoryService.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/WorkspaceProjectFactoryService.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.Immutable; using System.ComponentModel.Composition; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServer.Telemetry; @@ -10,7 +9,6 @@ using Microsoft.Extensions.Logging; using Microsoft.ServiceHub.Framework; using Microsoft.VisualStudio.Shell.ServiceBroker; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace; #pragma warning disable RS0030 // This is intentionally using System.ComponentModel.Composition for compatibility with MEF service broker. diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServer/Handler/Logging/UpdateLogLevelHandler.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServer/Handler/Logging/UpdateLogLevelHandler.cs index 0fb33697f2b09..2ff0032ea4c69 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServer/Handler/Logging/UpdateLogLevelHandler.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServer/Handler/Logging/UpdateLogLevelHandler.cs @@ -6,9 +6,7 @@ using System.Text.Json.Serialization; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServer.Handler; -using Microsoft.CodeAnalysis.LanguageServer.Logging; using Microsoft.Extensions.Logging; -using Roslyn.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.LanguageServer.LanguageServer.Handler.Logging; diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServer/Handler/Restore/RestorableProjectsHandler.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServer/Handler/Restore/RestorableProjectsHandler.cs index a943bb91eeacf..dff2f53aa8ce6 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServer/Handler/Restore/RestorableProjectsHandler.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServer/Handler/Restore/RestorableProjectsHandler.cs @@ -6,7 +6,6 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServer.Handler; using Microsoft.CodeAnalysis.LanguageServer.Handler.DebugConfiguration; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer; diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServer/LanguageServerHost.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServer/LanguageServerHost.cs index 4432adc2f49f4..a874f6049f8c6 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServer/LanguageServerHost.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServer/LanguageServerHost.cs @@ -7,7 +7,6 @@ using Microsoft.CommonLanguageServerProtocol.Framework; using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.Composition; -using Roslyn.LanguageServer.Protocol; using StreamJsonRpc; namespace Microsoft.CodeAnalysis.LanguageServer.LanguageServer; diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Logging/LspLogMessageLogger.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Logging/LspLogMessageLogger.cs index 9e0c92b8975a6..65014672ddb91 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Logging/LspLogMessageLogger.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Logging/LspLogMessageLogger.cs @@ -6,7 +6,6 @@ using Microsoft.Extensions.Logging; using Roslyn.LanguageServer.Protocol; using StreamJsonRpc; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.Logging; diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Logging/RoslynLogger.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Logging/RoslynLogger.cs index 8cb9f6d920bbb..8eaf22ddc745f 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Logging/RoslynLogger.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Logging/RoslynLogger.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.PooledObjects; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.Logging { diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Logging/ServerLoggerFactory.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Logging/ServerLoggerFactory.cs index 84ea12bffbd89..c284b33a547f5 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Logging/ServerLoggerFactory.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Logging/ServerLoggerFactory.cs @@ -5,7 +5,6 @@ using System.Composition; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.Extensions.Logging; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.Logging; diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Logging/ShowToastNotification.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Logging/ShowToastNotification.cs index f223114d93364..0e62c7912c8e0 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Logging/ShowToastNotification.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Logging/ShowToastNotification.cs @@ -4,7 +4,6 @@ using System.Text.Json.Serialization; using Microsoft.CodeAnalysis.LanguageServer.LanguageServer; -using Roslyn.Utilities; using LSP = Roslyn.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.LanguageServer; diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Microsoft.CodeAnalysis.LanguageServer.csproj b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Microsoft.CodeAnalysis.LanguageServer.csproj index a76305b4a2923..365f2b404315d 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Microsoft.CodeAnalysis.LanguageServer.csproj +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Microsoft.CodeAnalysis.LanguageServer.csproj @@ -44,16 +44,9 @@ $(ArtifactsDir)/LanguageServer/$(Configuration)/$(TargetFramework)/$(RuntimeIdentifier) $(ArtifactsDir)/LanguageServer/$(Configuration)/$(TargetFramework)/neutral - - - $(TargetRid) - $(BaseOS) - win-x64;win-arm64;linux-x64;linux-arm64;linux-musl-x64;linux-musl-arm64;osx-x64;osx-arm64 true + + + + + + + + $(PublishReadyToRunCrossgen2ExtraArgs);--opt-cross-module:*;--non-local-generics-module:"$(TargetName)" + + + @@ -80,6 +85,8 @@ + + diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/PackAllRids.targets b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/PackAllRids.targets index 53ced13fbc184..e8d708eafaa74 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/PackAllRids.targets +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/PackAllRids.targets @@ -4,18 +4,28 @@ false <_RoslynPublishReadyToRun>false <_RoslynPublishReadyToRun Condition="'$(Configuration)' == 'Release'">true - - - - + + $(TargetRid) + $(BaseOS) + win-x64;win-arm64;linux-x64;linux-arm64;linux-musl-x64;linux-musl-arm64;osx-x64;osx-arm64 + + @@ -27,6 +37,15 @@ + + + diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Program.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Program.cs index 5c80f55e9dde6..a7fe81642d7c9 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Program.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Program.cs @@ -181,7 +181,7 @@ static async Task RunAsync(ServerConfiguration serverConfiguration, Cancellation } } -static CliRootCommand CreateCommandLineParser() +static CliConfiguration CreateCommandLineParser() { var debugOption = new CliOption("--debug") { @@ -277,6 +277,7 @@ static CliRootCommand CreateCommandLineParser() serverPipeNameOption, useStdIoOption }; + rootCommand.SetAction((parseResult, cancellationToken) => { var launchDebugger = parseResult.GetValue(debugOption); @@ -308,7 +309,16 @@ static CliRootCommand CreateCommandLineParser() return RunAsync(serverConfiguration, cancellationToken); }); - return rootCommand; + + var config = new CliConfiguration(rootCommand) + { + // By default, System.CommandLine will catch all exceptions, log them to the console, and return a non-zero exit code. + // Unfortunately this makes .NET's crash dump collection environment variables (e.g. 'DOTNET_DbgEnableMiniDump') + // entirely useless as it never detects an actual crash. Disable this behavior so we can collect crash dumps when asked to. + EnableDefaultExceptionHandler = false + }; + + return config; } static (string clientPipe, string serverPipe) CreateNewPipeNames() diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/ServerConfigurationFactory.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/ServerConfigurationFactory.cs index 6aec0eaaf9256..dc4715ae9bae4 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/ServerConfigurationFactory.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/ServerConfigurationFactory.cs @@ -6,7 +6,6 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.Extensions.Logging; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer; diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/ExtensionAssemblyManager.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/ExtensionAssemblyManager.cs index 03f3a0ee97477..d1ca799deec39 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/ExtensionAssemblyManager.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/ExtensionAssemblyManager.cs @@ -8,7 +8,6 @@ using Microsoft.CodeAnalysis.LanguageServer.StarredSuggestions; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.Extensions.Logging; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.Services; diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/ExtensionAssemblyManagerProvider.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/ExtensionAssemblyManagerProvider.cs index 143e63a8aebb2..821d3dfeb9063 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/ExtensionAssemblyManagerProvider.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/ExtensionAssemblyManagerProvider.cs @@ -2,14 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Generic; using System.Composition; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.Extensions.Logging; namespace Microsoft.CodeAnalysis.LanguageServer.Services; diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/LspExtractInterfaceOptionsService.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/LspExtractInterfaceOptionsService.cs index bdfe8b6031bc6..f081f59ccbad8 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/LspExtractInterfaceOptionsService.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/LspExtractInterfaceOptionsService.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.Composition; using Microsoft.CodeAnalysis.ExtractInterface; using Microsoft.CodeAnalysis.Host.Mef; @@ -15,17 +16,16 @@ internal sealed class LspExtractInterfaceOptionsService() : IExtractInterfaceOpt { public ExtractInterfaceOptionsResult GetExtractInterfaceOptions( Document document, - List extractableMembers, + ImmutableArray extractableMembers, string defaultInterfaceName, - List conflictingTypeNames, + ImmutableArray conflictingTypeNames, string defaultNamespace, - string generatedNameTypeParameterSuffix, - CancellationToken cancellationToken) + string generatedNameTypeParameterSuffix) { var extension = document.Project.Language == LanguageNames.CSharp ? ".cs" : ".vb"; return new( isCancelled: false, - [.. extractableMembers], + extractableMembers, defaultInterfaceName, defaultInterfaceName + extension, ExtractInterfaceOptionsResult.ExtractLocation.SameFile); diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/StarredCompletions/StarredCompletionProvider.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/StarredCompletions/StarredCompletionProvider.cs index 889fb234e22c8..df65727c0de59 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/StarredCompletions/StarredCompletionProvider.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/StarredCompletions/StarredCompletionProvider.cs @@ -5,7 +5,6 @@ using System.Composition; using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Host.Mef; -using Roslyn.Utilities; using Microsoft.CodeAnalysis.LanguageService; namespace Microsoft.CodeAnalysis.LanguageServer.StarredSuggestions; diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Telemetry/VSCodeRequestTelemetryLogger.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Telemetry/VSCodeRequestTelemetryLogger.cs index b16907c53cdb9..632c3c0ecb1ab 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Telemetry/VSCodeRequestTelemetryLogger.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Telemetry/VSCodeRequestTelemetryLogger.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.Concurrent; using System.Composition; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/RunTestsHandler.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/RunTestsHandler.cs index 2f8424fabb26d..028c4e181f342 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/RunTestsHandler.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/RunTestsHandler.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.LanguageServer.Handler.Testing; using Microsoft.Extensions.Logging; using Microsoft.TestPlatform.VsTestConsole.TranslationLayer; -using Roslyn.Utilities; using LSP = Roslyn.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.LanguageServer.Testing; @@ -50,6 +49,8 @@ public async Task HandleRequestAsync(RunTestsParams req // Find the appropriate vstest.console.dll from the SDK. var vsTestConsolePath = await dotnetCliHelper.GetVsTestConsolePathAsync(projectOutputDirectory, cancellationToken); + var dotnetRootUser = Environment.GetEnvironmentVariable("DOTNET_ROOT_USER"); + // Instantiate the test platform wrapper. var vsTestConsoleWrapper = new VsTestConsoleWrapper(vsTestConsolePath, new ConsoleParameters { @@ -58,7 +59,7 @@ public async Task HandleRequestAsync(RunTestsParams req EnvironmentVariables = new() { // Reset dotnet root so that vs test console can find the right runtimes. - { DotnetCliHelper.DotnetRootEnvVar, string.Empty }, + { DotnetCliHelper.DotnetRootEnvVar, string.IsNullOrEmpty(dotnetRootUser) || dotnetRootUser == "EMPTY" ? string.Empty : dotnetRootUser } } }); diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/TestDiscoverer.DiscoveryHandler.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/TestDiscoverer.DiscoveryHandler.cs index a166543886f52..92e0905dfcd99 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/TestDiscoverer.DiscoveryHandler.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/TestDiscoverer.DiscoveryHandler.cs @@ -9,7 +9,6 @@ using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.Testing; diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/TestRunner.TestRunHandler.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/TestRunner.TestRunHandler.cs index 106f36090ad14..3a54e7d98e90b 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/TestRunner.TestRunHandler.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/TestRunner.TestRunHandler.cs @@ -12,7 +12,6 @@ using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.Testing; diff --git a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.Example/Microsoft.CommonLanguageServerProtocol.Framework.Example.csproj b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.Example/Microsoft.CommonLanguageServerProtocol.Framework.Example.csproj index 1e3c944072843..6b419a03f3fcf 100644 --- a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.Example/Microsoft.CommonLanguageServerProtocol.Framework.Example.csproj +++ b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.Example/Microsoft.CommonLanguageServerProtocol.Framework.Example.csproj @@ -21,7 +21,5 @@ - - - + diff --git a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.UnitTests/Mocks/TestHandlerProvider.cs b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.UnitTests/Mocks/TestHandlerProvider.cs index e7db7579a3646..9a67004e774a7 100644 --- a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.UnitTests/Mocks/TestHandlerProvider.cs +++ b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.UnitTests/Mocks/TestHandlerProvider.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; diff --git a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/AbstractHandlerProvider.cs b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/AbstractHandlerProvider.cs index 14516ad074984..a7fdcb95e1994 100644 --- a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/AbstractHandlerProvider.cs +++ b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/AbstractHandlerProvider.cs @@ -5,7 +5,6 @@ // This is consumed as 'generated' code in a source package and therefore requires an explicit nullable enable #nullable enable -using System; using System.Collections.Immutable; namespace Microsoft.CommonLanguageServerProtocol.Framework; diff --git a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/AbstractLanguageServer.cs b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/AbstractLanguageServer.cs index a375878201a7e..071edc9649eaa 100644 --- a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/AbstractLanguageServer.cs +++ b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/AbstractLanguageServer.cs @@ -27,6 +27,7 @@ internal abstract class AbstractLanguageServer /// private readonly Lazy> _queue; private readonly Lazy _lspServices; + private readonly Lazy _handlerProvider; public bool IsInitialized { get; private set; } @@ -67,6 +68,13 @@ protected AbstractLanguageServer( _jsonRpc.Disconnected += JsonRpc_Disconnected; _lspServices = new Lazy(() => ConstructLspServices()); _queue = new Lazy>(() => ConstructRequestExecutionQueue()); + _handlerProvider = new Lazy(() => + { + var lspServices = _lspServices.Value; + var handlerProvider = new HandlerProvider(lspServices, TypeRefResolver); + SetupRequestDispatcher(handlerProvider); + return handlerProvider; + }); } /// @@ -89,10 +97,7 @@ protected virtual AbstractHandlerProvider HandlerProvider { get { - var lspServices = _lspServices.Value; - var handlerProvider = new HandlerProvider(lspServices, TypeRefResolver); - SetupRequestDispatcher(handlerProvider); - return handlerProvider; + return _handlerProvider.Value; } } diff --git a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/IQueueItem.cs b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/IQueueItem.cs index 36e80aee8e73a..cc8135a6ef0ec 100644 --- a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/IQueueItem.cs +++ b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/IQueueItem.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.Threading; using System.Threading.Tasks; diff --git a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/IRequestExecutionQueue.cs b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/IRequestExecutionQueue.cs index 084293272ded8..b5452ab6728f0 100644 --- a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/IRequestExecutionQueue.cs +++ b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/IRequestExecutionQueue.cs @@ -6,7 +6,6 @@ #nullable enable using System; -using System.Collections.Frozen; using System.Threading; using System.Threading.Tasks; diff --git a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/Microsoft.CommonLanguageServerProtocol.Framework.Package.csproj b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/Microsoft.CommonLanguageServerProtocol.Framework.Package.csproj index ce4ed2a289ace..432407fd46ce9 100644 --- a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/Microsoft.CommonLanguageServerProtocol.Framework.Package.csproj +++ b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/Microsoft.CommonLanguageServerProtocol.Framework.Package.csproj @@ -25,10 +25,6 @@ - - - - @@ -43,4 +39,5 @@ contentFiles\cs\$(TargetFramework)\ + diff --git a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/Microsoft.CommonLanguageServerProtocol.Framework.Shared.projitems b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/Microsoft.CommonLanguageServerProtocol.Framework.Shared.projitems index ef9c653643d6e..dd8785f1ae8f5 100644 --- a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/Microsoft.CommonLanguageServerProtocol.Framework.Shared.projitems +++ b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/Microsoft.CommonLanguageServerProtocol.Framework.Shared.projitems @@ -41,6 +41,5 @@ - \ No newline at end of file diff --git a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/NewtonsoftLanguageServer.cs b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/NewtonsoftLanguageServer.cs index 59c45026e2543..aed9fde0728e9 100644 --- a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/NewtonsoftLanguageServer.cs +++ b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/NewtonsoftLanguageServer.cs @@ -6,7 +6,6 @@ #nullable enable using System; -using System.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; diff --git a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/RequestExecutionQueue.cs b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/RequestExecutionQueue.cs index 6da78c6e625f2..94a7f59b2da03 100644 --- a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/RequestExecutionQueue.cs +++ b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/RequestExecutionQueue.cs @@ -10,13 +10,11 @@ using System.Collections.Frozen; using System.Collections.Generic; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; using Microsoft.VisualStudio.Threading; -using StreamJsonRpc; namespace Microsoft.CommonLanguageServerProtocol.Framework; diff --git a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/SystemTextJsonLanguageServer.cs b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/SystemTextJsonLanguageServer.cs index 8006a68d0c905..05821074cdf12 100644 --- a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/SystemTextJsonLanguageServer.cs +++ b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/SystemTextJsonLanguageServer.cs @@ -6,7 +6,6 @@ #nullable enable using System; -using System.Linq; using System.Reflection; using System.Text.Json; using System.Threading; diff --git a/src/LanguageServer/Protocol.TestUtilities/Diagnostics/DiagnosticProviderTestUtilities.cs b/src/LanguageServer/Protocol.TestUtilities/Diagnostics/DiagnosticProviderTestUtilities.cs index db6414fea196f..9ec56260fca0f 100644 --- a/src/LanguageServer/Protocol.TestUtilities/Diagnostics/DiagnosticProviderTestUtilities.cs +++ b/src/LanguageServer/Protocol.TestUtilities/Diagnostics/DiagnosticProviderTestUtilities.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.Threading.Tasks; using Microsoft.CodeAnalysis.Text; diff --git a/src/LanguageServer/Protocol.TestUtilities/Diagnostics/TestDiagnosticAnalyzerDriver.cs b/src/LanguageServer/Protocol.TestUtilities/Diagnostics/TestDiagnosticAnalyzerDriver.cs index 04e23cd3ff207..7dd8669e53a19 100644 --- a/src/LanguageServer/Protocol.TestUtilities/Diagnostics/TestDiagnosticAnalyzerDriver.cs +++ b/src/LanguageServer/Protocol.TestUtilities/Diagnostics/TestDiagnosticAnalyzerDriver.cs @@ -8,9 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; @@ -21,7 +19,7 @@ namespace Microsoft.CodeAnalysis.UnitTests.Diagnostics { public class TestDiagnosticAnalyzerDriver { - private readonly DiagnosticAnalyzerService _diagnosticAnalyzerService; + private readonly IDiagnosticAnalyzerService _diagnosticAnalyzerService; private readonly bool _includeSuppressedDiagnostics; private readonly bool _includeNonLocalDocumentDiagnostics; @@ -29,8 +27,7 @@ public TestDiagnosticAnalyzerDriver(Workspace workspace, bool includeSuppressedD { var mefServices = workspace.Services.SolutionServices.ExportProvider; - _diagnosticAnalyzerService = Assert.IsType(mefServices.GetExportedValue()); - _diagnosticAnalyzerService.CreateIncrementalAnalyzer(workspace); + _diagnosticAnalyzerService = mefServices.GetExportedValue(); _includeSuppressedDiagnostics = includeSuppressedDiagnostics; _includeNonLocalDocumentDiagnostics = includeNonLocalDocumentDiagnostics; } @@ -49,7 +46,7 @@ private async Task> GetDiagnosticsAsync( { var text = await document.GetTextAsync().ConfigureAwait(false); var dxs = await _diagnosticAnalyzerService.GetDiagnosticsForIdsAsync( - project.Solution, project.Id, document.Id, diagnosticIds: null, shouldIncludeAnalyzer: null, + project, document.Id, diagnosticIds: null, shouldIncludeAnalyzer: null, includeLocalDocumentDiagnostics: true, _includeNonLocalDocumentDiagnostics, CancellationToken.None); dxs = dxs.WhereAsArray(d => _includeSuppressedDiagnostics || !d.IsSuppressed); documentDiagnostics = await CodeAnalysis.Diagnostics.Extensions.ToDiagnosticsAsync( @@ -63,7 +60,7 @@ filterSpan is null if (getProjectDiagnostics) { var dxs = await _diagnosticAnalyzerService.GetDiagnosticsForIdsAsync( - project.Solution, project.Id, documentId: null, diagnosticIds: null, shouldIncludeAnalyzer: null, + project, documentId: null, diagnosticIds: null, shouldIncludeAnalyzer: null, includeLocalDocumentDiagnostics: true, _includeNonLocalDocumentDiagnostics, CancellationToken.None); dxs = dxs.WhereAsArray(d => _includeSuppressedDiagnostics || !d.IsSuppressed); projectDiagnostics = await CodeAnalysis.Diagnostics.Extensions.ToDiagnosticsAsync(dxs.Where(d => d.DocumentId is null), project, CancellationToken.None); diff --git a/src/EditorFeatures/TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.InitializationOptions.cs b/src/LanguageServer/Protocol.TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.InitializationOptions.cs similarity index 94% rename from src/EditorFeatures/TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.InitializationOptions.cs rename to src/LanguageServer/Protocol.TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.InitializationOptions.cs index 8998fcec76edd..751c7367ff9df 100644 --- a/src/EditorFeatures/TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.InitializationOptions.cs +++ b/src/LanguageServer/Protocol.TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.InitializationOptions.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.LanguageServer; using Microsoft.CodeAnalysis.Options; @@ -29,6 +30,7 @@ internal readonly record struct InitializationOptions() internal string? Locale { get; init; } = null; internal IEnumerable? AdditionalAnalyzers { get; init; } = null; internal IJsonRpcMessageFormatter? ClientMessageFormatter { get; init; } = null; + internal ParseOptions? ParseOptions { get; init; } = null; } } } diff --git a/src/EditorFeatures/TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs b/src/LanguageServer/Protocol.TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs similarity index 82% rename from src/EditorFeatures/TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs rename to src/LanguageServer/Protocol.TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs index 29071e6c24179..5222521aed0c0 100644 --- a/src/EditorFeatures/TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs +++ b/src/LanguageServer/Protocol.TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs @@ -15,16 +15,12 @@ using System.Xml.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Editor.Shared.Extensions; -using Microsoft.CodeAnalysis.Editor.Test; -using Microsoft.CodeAnalysis.Editor.UnitTests; using Microsoft.CodeAnalysis.Extensions; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.LanguageServer; using Microsoft.CodeAnalysis.LanguageServer.Handler; using Microsoft.CodeAnalysis.LanguageServer.Handler.CodeActions; using Microsoft.CodeAnalysis.LanguageServer.Handler.Completion; -using Microsoft.CodeAnalysis.LanguageServer.UnitTests; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; @@ -51,10 +47,6 @@ protected AbstractLanguageServerProtocolTests(ITestOutputHelper? testOutputHelpe TestOutputLspLogger = testOutputHelper != null ? new TestOutputLspLogger(testOutputHelper) : NoOpLspLogger.Instance; } - protected static readonly TestComposition EditorFeaturesLspComposition = EditorTestCompositions.LanguageServerProtocolEditorFeatures - .AddParts(typeof(TestDocumentTrackingService)) - .AddParts(typeof(TestWorkspaceRegistrationService)); - protected static readonly TestComposition FeaturesLspComposition = LspTestCompositions.LanguageServerProtocol .AddParts(typeof(TestDocumentTrackingService)) .AddParts(typeof(TestWorkspaceRegistrationService)); @@ -108,7 +100,7 @@ private protected class OrderLocations : Comparer public override int Compare(LSP.Location? x, LSP.Location? y) => CompareLocations(x, y); } - protected virtual TestComposition Composition => EditorFeaturesLspComposition; + protected virtual TestComposition Composition => FeaturesLspComposition; private protected virtual TestAnalyzerReferenceByLanguage CreateTestAnalyzersReference() => new(DiagnosticExtensions.GetCompilerDiagnosticAnalyzersMap()); @@ -180,7 +172,7 @@ private protected static string ApplyTextEdits(LSP.TextEdit[]? edits, SourceText internal static LSP.SymbolInformation CreateSymbolInformation(LSP.SymbolKind kind, string name, LSP.Location location, Glyph glyph, string? containerName = null) { - var imageId = glyph.GetImageId(); + var (guid, id) = glyph.GetVsImageData(); #pragma warning disable CS0618 // SymbolInformation is obsolete, need to switch to DocumentSymbol/WorkspaceSymbol var info = new LSP.VSSymbolInformation() @@ -188,7 +180,7 @@ internal static LSP.SymbolInformation CreateSymbolInformation(LSP.SymbolKind kin Kind = kind, Name = name, Location = location, - Icon = new LSP.VSImageId { Guid = imageId.Guid, Id = imageId.Id }, + Icon = new LSP.VSImageId { Guid = guid, Id = id }, }; if (containerName != null) @@ -279,7 +271,7 @@ private protected static LSP.CompletionParams CreateCompletionParams( }; if (tags != null) - item.Icon = tags.ToImmutableArray().GetFirstGlyph().GetImageElement().ToLSPImageElement(); + item.Icon = new(tags.ToImmutableArray().GetFirstGlyph().ToLSPImageId()); if (commitCharacters != null) item.CommitCharacters = [.. commitCharacters.Value.Select(c => c.ToString())]; @@ -321,13 +313,19 @@ private protected Task CreateTestLspServerAsync( var workspace = CreateWorkspace(lspOptions, workspaceKind: null, mutatingLspWorkspace, composition); workspace.InitializeDocuments( - TestWorkspace.CreateWorkspaceElement(languageName, files: markups, fileContainingFolders: lspOptions.DocumentFileContainingFolders, sourceGeneratedFiles: lspOptions.SourceGeneratedMarkups, commonReferences: commonReferences), + LspTestWorkspace.CreateWorkspaceElement( + languageName, + parseOptions: lspOptions.ParseOptions, + files: markups, + fileContainingFolders: lspOptions.DocumentFileContainingFolders, + sourceGeneratedFiles: lspOptions.SourceGeneratedMarkups, + commonReferences: commonReferences), openDocuments: false); return CreateTestLspServerAsync(workspace, lspOptions, languageName); } - private async Task CreateTestLspServerAsync(EditorTestWorkspace workspace, InitializationOptions initializationOptions, string languageName) + private async Task CreateTestLspServerAsync(LspTestWorkspace workspace, InitializationOptions initializationOptions, string languageName) { var solution = workspace.CurrentSolution; @@ -374,10 +372,10 @@ private protected async Task CreateXmlTestLspServerAsync( return await TestLspServer.CreateAsync(workspace, lspOptions, TestOutputLspLogger); } - internal EditorTestWorkspace CreateWorkspace( + internal LspTestWorkspace CreateWorkspace( InitializationOptions? options, string? workspaceKind, bool mutatingLspWorkspace, TestComposition? composition = null) { - var workspace = new EditorTestWorkspace( + var workspace = new LspTestWorkspace( composition ?? Composition, workspaceKind, configurationOptions: new WorkspaceConfigurationOptions(ValidateCompilationTrackerStates: true), supportsLspMutation: mutatingLspWorkspace); options?.OptionUpdater?.Invoke(workspace.GetService()); @@ -390,13 +388,19 @@ internal EditorTestWorkspace CreateWorkspace( /// Waits for the async operations on the workspace to complete. /// This ensures that events like workspace registration / workspace changes are processed by the time we exit this method. /// - protected static async Task WaitForWorkspaceOperationsAsync(EditorTestWorkspace workspace) + protected static async Task WaitForWorkspaceOperationsAsync(TestWorkspace workspace) + where TDocument : TestHostDocument + where TProject : TestHostProject + where TSolution : TestHostSolution { var workspaceWaiter = GetWorkspaceWaiter(workspace); await workspaceWaiter.ExpeditedWaitAsync(); } - private static IAsynchronousOperationWaiter GetWorkspaceWaiter(EditorTestWorkspace workspace) + private static IAsynchronousOperationWaiter GetWorkspaceWaiter(TestWorkspace workspace) + where TDocument : TestHostDocument + where TProject : TestHostProject + where TSolution : TestHostSolution { var operations = workspace.ExportProvider.GetExportedValue(); return operations.GetWaiter(FeatureAttribute.Workspace); @@ -419,7 +423,7 @@ protected static void AddMappedDocument(Workspace workspace, string markup) workspace.TryApplyChanges(newSolution); } - protected static async Task AddGeneratorAsync(ISourceGenerator generator, EditorTestWorkspace workspace) + protected static async Task AddGeneratorAsync(ISourceGenerator generator, LspTestWorkspace workspace) { var analyzerReference = new TestGeneratorReference(generator); @@ -433,7 +437,7 @@ protected static async Task AddGeneratorAsync(ISourceGenerato return analyzerReference; } - protected static async Task RemoveGeneratorAsync(AnalyzerReference reference, EditorTestWorkspace workspace) + protected static async Task RemoveGeneratorAsync(AnalyzerReference reference, LspTestWorkspace workspace) { var solution = workspace.CurrentSolution .Projects.Single() @@ -444,7 +448,10 @@ protected static async Task RemoveGeneratorAsync(AnalyzerReference reference, Ed await WaitForWorkspaceOperationsAsync(workspace); } - internal static async Task>> GetAnnotatedLocationsAsync(EditorTestWorkspace workspace, Solution solution) + internal static async Task>> GetAnnotatedLocationsAsync(TestWorkspace workspace, Solution solution) + where TDocument : TestHostDocument + where TProject : TestHostProject + where TSolution : TestHostSolution { var locations = new Dictionary>(); foreach (var testDocument in workspace.Documents) @@ -531,44 +538,71 @@ private static LSP.DidCloseTextDocumentParams CreateDidCloseTextDocumentParams(U } }; - internal sealed class TestLspServer : IAsyncDisposable + /// + /// Implementation of + /// using the workspace. + /// + internal sealed class TestLspServer : AbstractTestLspServer { - public readonly EditorTestWorkspace TestWorkspace; - private readonly Dictionary> _locations; + public TestLspServer(LspTestWorkspace testWorkspace, Dictionary> locations, InitializationOptions initializationOptions, AbstractLspLogger logger) + : base(testWorkspace, locations, initializationOptions, logger) + { + } + + public static async Task CreateAsync(LspTestWorkspace testWorkspace, InitializationOptions initializationOptions, AbstractLspLogger logger) + { + var locations = await GetAnnotatedLocationsAsync(testWorkspace, testWorkspace.CurrentSolution); + var server = new TestLspServer(testWorkspace, locations, initializationOptions, logger); + await server.InitializeAsync(); + return server; + } + } + + internal abstract class AbstractTestLspServer : IAsyncDisposable + where TDocument : TestHostDocument + where TProject : TestHostProject + where TSolution : TestHostSolution + where TWorkspace : TestWorkspace + { + public readonly TWorkspace TestWorkspace; private readonly JsonRpc _clientRpc; + private readonly Dictionary> _locations; private readonly ICodeAnalysisDiagnosticAnalyzerService _codeAnalysisService; - - private readonly RoslynLanguageServer LanguageServer; + private readonly InitializationOptions _initializationOptions; + private readonly Lazy _languageServer; public LSP.ClientCapabilities ClientCapabilities { get; } - private TestLspServer( - EditorTestWorkspace testWorkspace, + public AbstractTestLspServer( + TWorkspace testWorkspace, Dictionary> locations, - LSP.ClientCapabilities clientCapabilities, - RoslynLanguageServer target, - Stream clientStream, - object? clientTarget = null, - IJsonRpcMessageFormatter? clientMessageFormatter = null) + InitializationOptions initializationOptions, + AbstractLspLogger logger) { TestWorkspace = testWorkspace; - ClientCapabilities = clientCapabilities; + _initializationOptions = initializationOptions; _locations = locations; _codeAnalysisService = testWorkspace.Services.GetRequiredService(); - LanguageServer = target; + ClientCapabilities = initializationOptions.ClientCapabilities; - clientMessageFormatter ??= RoslynLanguageServer.CreateJsonMessageFormatter(); + var clientMessageFormatter = initializationOptions.ClientMessageFormatter ?? RoslynLanguageServer.CreateJsonMessageFormatter(); - _clientRpc = new JsonRpc(new HeaderDelimitedMessageHandler(clientStream, clientStream, clientMessageFormatter), clientTarget) + var (clientStream, serverStream) = FullDuplexStream.CreatePair(); + + _clientRpc = new JsonRpc(new HeaderDelimitedMessageHandler(clientStream, clientStream, clientMessageFormatter), initializationOptions.ClientTarget) { ExceptionStrategy = ExceptionProcessing.ISerializable, }; - // Workspace listener events do not run in tests, so we manually register the lsp misc workspace. - TestWorkspace.GetService().Register(GetManagerAccessor().GetLspMiscellaneousFilesWorkspace()); + _languageServer = new(() => + { + var server = CreateLanguageServer(serverStream, serverStream, _initializationOptions.ServerKind, logger); + + InitializeClientRpc(); + return server; + }); - InitializeClientRpc(); } private void InitializeClientRpc() @@ -579,56 +613,39 @@ private void InitializeClientRpc() Assert.False(workspaceWaiter.HasPendingWork); } - internal static async Task CreateAsync(EditorTestWorkspace testWorkspace, InitializationOptions initializationOptions, AbstractLspLogger logger) + internal async Task InitializeAsync() { // Important: We must wait for workspace creation operations to finish. // Otherwise we could have a race where workspace change events triggered by creation are changing the state // created by the initial test steps. This can interfere with the expected test state. - await WaitForWorkspaceOperationsAsync(testWorkspace); + await WaitForWorkspaceOperationsAsync(TestWorkspace); - var locations = await GetAnnotatedLocationsAsync(testWorkspace, testWorkspace.CurrentSolution); + // Initialize the language server + _ = _languageServer.Value; - var (clientStream, serverStream) = FullDuplexStream.CreatePair(); - var languageServer = CreateLanguageServer(serverStream, serverStream, testWorkspace, initializationOptions.ServerKind, logger); - - var server = new TestLspServer(testWorkspace, locations, initializationOptions.ClientCapabilities, languageServer, clientStream, initializationOptions.ClientTarget, initializationOptions.ClientMessageFormatter); + // Workspace listener events do not run in tests, so we manually register the lsp misc workspace. + // This must be done after the language server is created in order to access the misc workspace off of the LSP workspace manager. + TestWorkspace.GetService().Register(GetManagerAccessor().GetLspMiscellaneousFilesWorkspace()); - if (initializationOptions.CallInitialize) + if (_initializationOptions.CallInitialize) { - await server.ExecuteRequestAsync(LSP.Methods.InitializeName, new LSP.InitializeParams + await this.ExecuteRequestAsync(LSP.Methods.InitializeName, new LSP.InitializeParams { - Capabilities = initializationOptions.ClientCapabilities, - Locale = initializationOptions.Locale, + Capabilities = _initializationOptions.ClientCapabilities, + Locale = _initializationOptions.Locale, }, CancellationToken.None); } - if (initializationOptions.CallInitialized) + if (_initializationOptions.CallInitialized) { - await server.ExecuteRequestAsync(LSP.Methods.InitializedName, new LSP.InitializedParams { }, CancellationToken.None); + await this.ExecuteRequestAsync(LSP.Methods.InitializedName, new LSP.InitializedParams { }, CancellationToken.None); } - - return server; - } - - internal static async Task CreateAsync(EditorTestWorkspace testWorkspace, LSP.ClientCapabilities clientCapabilities, RoslynLanguageServer target, Stream clientStream) - { - var locations = await GetAnnotatedLocationsAsync(testWorkspace, testWorkspace.CurrentSolution); - var server = new TestLspServer(testWorkspace, locations, clientCapabilities, target, clientStream); - - await server.ExecuteRequestAsync(LSP.Methods.InitializeName, new LSP.InitializeParams - { - Capabilities = clientCapabilities, - }, CancellationToken.None); - - await server.ExecuteRequestAsync(LSP.Methods.InitializedName, new LSP.InitializedParams { }, CancellationToken.None); - - return server; } - private static RoslynLanguageServer CreateLanguageServer(Stream inputStream, Stream outputStream, EditorTestWorkspace workspace, WellKnownLspServerKinds serverKind, AbstractLspLogger logger) + protected virtual RoslynLanguageServer CreateLanguageServer(Stream inputStream, Stream outputStream, WellKnownLspServerKinds serverKind, AbstractLspLogger logger) { - var capabilitiesProvider = workspace.ExportProvider.GetExportedValue(); - var factory = workspace.ExportProvider.GetExportedValue(); + var capabilitiesProvider = TestWorkspace.ExportProvider.GetExportedValue(); + var factory = TestWorkspace.ExportProvider.GetExportedValue(); var jsonMessageFormatter = RoslynLanguageServer.CreateJsonMessageFormatter(); var jsonRpc = new JsonRpc(new HeaderDelimitedMessageHandler(outputStream, inputStream, jsonMessageFormatter)) @@ -636,7 +653,7 @@ private static RoslynLanguageServer CreateLanguageServer(Stream inputStream, Str ExceptionStrategy = ExceptionProcessing.ISerializable, }; - var languageServer = (RoslynLanguageServer)factory.Create(jsonRpc, jsonMessageFormatter.JsonSerializerOptions, capabilitiesProvider, serverKind, logger, workspace.Services.HostServices); + var languageServer = (RoslynLanguageServer)factory.Create(jsonRpc, jsonMessageFormatter.JsonSerializerOptions, capabilitiesProvider, serverKind, logger, TestWorkspace.Services.HostServices); jsonRpc.StartListening(); return languageServer; @@ -698,6 +715,33 @@ public async Task OpenDocumentAsync(Uri documentUri, string? text = null, string await ExecuteRequestAsync(LSP.Methods.TextDocumentDidOpenName, didOpenParams, CancellationToken.None); } + /// + /// Opens a document in the workspace only, and waits for workspace operations. + /// Use if the document should be opened in LSP"/> + /// + public async Task OpenDocumentInWorkspaceAsync(DocumentId documentId, bool openAllLinkedDocuments, SourceText? text = null) + { + var document = TestWorkspace.CurrentSolution.GetDocument(documentId); + Contract.ThrowIfNull(document); + + text ??= await TestWorkspace.CurrentSolution.GetDocument(documentId)!.GetTextAsync(CancellationToken.None); + + List linkedDocuments = [documentId]; + if (openAllLinkedDocuments) + { + linkedDocuments.AddRange(document.GetLinkedDocumentIds()); + } + + var container = new TestStaticSourceTextContainer(text); + + foreach (var documentIdToOpen in linkedDocuments) + { + TestWorkspace.OnDocumentOpened(documentIdToOpen, container); + } + + await WaitForWorkspaceOperationsAsync(TestWorkspace); + } + public Task ReplaceTextAsync(Uri documentUri, params (LSP.Range Range, string Text)[] changes) { var didChangeParams = CreateDidChangeTextDocumentParams( @@ -741,7 +785,7 @@ public async Task ExitTestServerAsync() // of the request itself since it will throw a ConnectionLostException. // Instead we wait for the server's exit task to be completed. await _clientRpc.NotifyAsync(LSP.Methods.ExitName).ConfigureAwait(false); - await LanguageServer.WaitForExitAsync().ConfigureAwait(false); + await _languageServer.Value.WaitForExitAsync().ConfigureAwait(false); } public IList GetLocations(string locationName) => _locations[locationName]; @@ -772,15 +816,21 @@ internal async Task WaitForDiagnosticsAsync() await listenerProvider.GetWaiter(FeatureAttribute.DiagnosticService).ExpeditedWaitAsync(); } - internal RequestExecutionQueue.TestAccessor? GetQueueAccessor() => LanguageServer.GetTestAccessor().GetQueueAccessor(); + internal async Task WaitForSourceGeneratorsAsync() + { + var operations = TestWorkspace.ExportProvider.GetExportedValue(); + await operations.WaitAllAsync(TestWorkspace, [FeatureAttribute.Workspace, FeatureAttribute.SourceGenerators]); + } + + internal RequestExecutionQueue.TestAccessor? GetQueueAccessor() => _languageServer.Value.GetTestAccessor().GetQueueAccessor(); internal LspWorkspaceManager.TestAccessor GetManagerAccessor() => GetRequiredLspService().GetTestAccessor(); internal LspWorkspaceManager GetManager() => GetRequiredLspService(); - internal AbstractLanguageServer.TestAccessor GetServerAccessor() => LanguageServer.GetTestAccessor(); + internal AbstractLanguageServer.TestAccessor GetServerAccessor() => _languageServer.Value.GetTestAccessor(); - internal T GetRequiredLspService() where T : class, ILspService => LanguageServer.GetTestAccessor().GetRequiredLspService(); + internal T GetRequiredLspService() where T : class, ILspService => _languageServer.Value.GetTestAccessor().GetRequiredLspService(); internal ImmutableArray GetTrackedTexts() => [.. GetManager().GetTrackedLspText().Values.Select(v => v.Text)]; @@ -794,14 +844,14 @@ public async ValueTask DisposeAsync() // Some tests will manually call shutdown and exit, so attempting to call this during dispose // will fail as the server's jsonrpc instance will be disposed of. - if (!LanguageServer.GetTestAccessor().HasShutdownStarted()) + if (!_languageServer.Value.GetTestAccessor().HasShutdownStarted()) { await ShutdownTestServerAsync(); await ExitTestServerAsync(); } // Wait for all the exit notifications to run to completion. - await LanguageServer.WaitForExitAsync(); + await _languageServer.Value.WaitForExitAsync(); TestWorkspace.Dispose(); _clientRpc.Dispose(); diff --git a/src/EditorFeatures/TestUtilities/LanguageServer/AbstractLspBuildOnlyDiagnosticsTests.cs b/src/LanguageServer/Protocol.TestUtilities/LanguageServer/AbstractLspBuildOnlyDiagnosticsTests.cs similarity index 97% rename from src/EditorFeatures/TestUtilities/LanguageServer/AbstractLspBuildOnlyDiagnosticsTests.cs rename to src/LanguageServer/Protocol.TestUtilities/LanguageServer/AbstractLspBuildOnlyDiagnosticsTests.cs index 30726fc3aaa9b..0b09f4041b37e 100644 --- a/src/EditorFeatures/TestUtilities/LanguageServer/AbstractLspBuildOnlyDiagnosticsTests.cs +++ b/src/LanguageServer/Protocol.TestUtilities/LanguageServer/AbstractLspBuildOnlyDiagnosticsTests.cs @@ -22,7 +22,7 @@ public abstract class AbstractLspBuildOnlyDiagnosticsTests [Fact] public void TestExportedDiagnosticIds() { - var attribute = this.LspBuildOnlyDiagnosticsType.GetCustomAttribute(); + var attribute = this.LspBuildOnlyDiagnosticsType.GetCustomAttribute()!; var actualDiagnosticCodes = attribute.BuildOnlyDiagnostics; var missing = ExpectedDiagnosticCodes.Except(actualDiagnosticCodes).OrderBy(k => k).ToList(); diff --git a/src/EditorFeatures/TestUtilities/LanguageServer/TestOutputLspLogger.cs b/src/LanguageServer/Protocol.TestUtilities/LanguageServer/TestOutputLspLogger.cs similarity index 95% rename from src/EditorFeatures/TestUtilities/LanguageServer/TestOutputLspLogger.cs rename to src/LanguageServer/Protocol.TestUtilities/LanguageServer/TestOutputLspLogger.cs index c8ba5e8bdbd99..8b7dfa57e4db3 100644 --- a/src/EditorFeatures/TestUtilities/LanguageServer/TestOutputLspLogger.cs +++ b/src/LanguageServer/Protocol.TestUtilities/LanguageServer/TestOutputLspLogger.cs @@ -3,10 +3,11 @@ // See the LICENSE file in the project root for more information. using System; +using Microsoft.CodeAnalysis.LanguageServer; using Microsoft.CommonLanguageServerProtocol.Framework; using Xunit.Abstractions; -namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests; +namespace Roslyn.Test.Utilities; internal sealed class TestOutputLspLogger : AbstractLspLogger, ILspService { diff --git a/src/EditorFeatures/TestUtilities/LanguageServer/TestWorkspaceRegistrationService.cs b/src/LanguageServer/Protocol.TestUtilities/LanguageServer/TestWorkspaceRegistrationService.cs similarity index 50% rename from src/EditorFeatures/TestUtilities/LanguageServer/TestWorkspaceRegistrationService.cs rename to src/LanguageServer/Protocol.TestUtilities/LanguageServer/TestWorkspaceRegistrationService.cs index f83897f0c6930..db393fa2ad034 100644 --- a/src/EditorFeatures/TestUtilities/LanguageServer/TestWorkspaceRegistrationService.cs +++ b/src/LanguageServer/Protocol.TestUtilities/LanguageServer/TestWorkspaceRegistrationService.cs @@ -10,15 +10,9 @@ namespace Roslyn.Test.Utilities; -public abstract partial class AbstractLanguageServerProtocolTests +[Export(typeof(LspWorkspaceRegistrationService)), Shared, PartNotDiscoverable] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal class TestWorkspaceRegistrationService() : LspWorkspaceRegistrationService { - [Export(typeof(LspWorkspaceRegistrationService)), Shared, PartNotDiscoverable] - internal class TestWorkspaceRegistrationService : LspWorkspaceRegistrationService - { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public TestWorkspaceRegistrationService() - { - } - } } diff --git a/src/LanguageServer/Protocol.TestUtilities/Microsoft.CodeAnalysis.LanguageServer.Protocol.Test.Utilities.csproj b/src/LanguageServer/Protocol.TestUtilities/Microsoft.CodeAnalysis.LanguageServer.Protocol.Test.Utilities.csproj index 81266477a3850..91693179de616 100644 --- a/src/LanguageServer/Protocol.TestUtilities/Microsoft.CodeAnalysis.LanguageServer.Protocol.Test.Utilities.csproj +++ b/src/LanguageServer/Protocol.TestUtilities/Microsoft.CodeAnalysis.LanguageServer.Protocol.Test.Utilities.csproj @@ -10,15 +10,16 @@ true true - - - - + + + + + \ No newline at end of file diff --git a/src/LanguageServer/Protocol.TestUtilities/Workspaces/TestStaticSourceTextContainer.cs b/src/LanguageServer/Protocol.TestUtilities/Workspaces/TestStaticSourceTextContainer.cs new file mode 100644 index 0000000000000..40b0f2bd9a904 --- /dev/null +++ b/src/LanguageServer/Protocol.TestUtilities/Workspaces/TestStaticSourceTextContainer.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 Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Test.Utilities; + +/// +/// Various tests often need a source text container to simulate workspace OnDocumentOpened calls. +/// +internal class TestStaticSourceTextContainer(SourceText text) : SourceTextContainer +{ + public override SourceText CurrentText => text; + + public override event EventHandler TextChanged + { + add { } + remove { } + } +} diff --git a/src/LanguageServer/Protocol/DefaultCapabilitiesProvider.cs b/src/LanguageServer/Protocol/DefaultCapabilitiesProvider.cs index 07bfdbf829b13..067785580f1e9 100644 --- a/src/LanguageServer/Protocol/DefaultCapabilitiesProvider.cs +++ b/src/LanguageServer/Protocol/DefaultCapabilitiesProvider.cs @@ -90,10 +90,13 @@ public ServerCapabilities GetCapabilities(ClientCapabilities clientCapabilities) // Using only range handling has shown to be more performant than using a combination of full/edits/range // handling, especially for larger files. With range handling, we only need to compute tokens for whatever // is in view, while with full/edits handling we need to compute tokens for the entire file and then - // potentially run a diff between the old and new tokens. + // potentially run a diff between the old and new tokens. Therefore, we only enable full handling if + // the client does not support ranges. + var rangeCapabilities = clientCapabilities.TextDocument?.SemanticTokens?.Requests?.Range; + var supportsSemanticTokensRange = rangeCapabilities?.Value is not (false or null); capabilities.SemanticTokensOptions = new SemanticTokensOptions { - Full = false, + Full = !supportsSemanticTokensRange, Range = true, Legend = new SemanticTokensLegend { diff --git a/src/LanguageServer/Protocol/Extensions/Extensions.cs b/src/LanguageServer/Protocol/Extensions/Extensions.cs index 8b49f8c0e80fb..b00ddde24a9e5 100644 --- a/src/LanguageServer/Protocol/Extensions/Extensions.cs +++ b/src/LanguageServer/Protocol/Extensions/Extensions.cs @@ -308,14 +308,13 @@ public static ClassifiedTextElement ToLSPElement(this QuickInfoClassifiedTextEle public static ContainerElement ToLSPElement(this QuickInfoContainerElement element) => new((ContainerElementStyle)element.Style, element.Elements.Select(ToLSPElement)); - private static object? ToLSPElement(QuickInfoElement value) + private static object ToLSPElement(QuickInfoElement value) { return value switch { QuickInfoGlyphElement element => element.ToLSPElement(), QuickInfoContainerElement element => element.ToLSPElement(), QuickInfoClassifiedTextElement element => element.ToLSPElement(), - _ => value }; } diff --git a/src/LanguageServer/Protocol/Extensions/ProtocolConversions.Diagnostics.cs b/src/LanguageServer/Protocol/Extensions/ProtocolConversions.Diagnostics.cs index 9d084b8076d00..5c30d938549e2 100644 --- a/src/LanguageServer/Protocol/Extensions/ProtocolConversions.Diagnostics.cs +++ b/src/LanguageServer/Protocol/Extensions/ProtocolConversions.Diagnostics.cs @@ -107,7 +107,7 @@ private static LSP.VSDiagnostic CreateLspDiagnostic( Code = diagnosticData.Id, CodeDescription = ProtocolConversions.HelpLinkToCodeDescription(diagnosticData.GetValidHelpLinkUri()), Message = diagnosticData.Message, - Severity = ConvertDiagnosticSeverity(diagnosticData.Severity, supportsVisualStudioExtensions), + Severity = ConvertDiagnosticSeverity(diagnosticData.Severity), Tags = ConvertTags(diagnosticData, isLiveSource, potentialDuplicate), DiagnosticRank = ConvertRank(diagnosticData), Range = GetRange(diagnosticData.DataLocation) @@ -207,14 +207,13 @@ private static bool ShouldIncludeHiddenDiagnostic(DiagnosticData diagnosticData, return null; } - private static LSP.DiagnosticSeverity ConvertDiagnosticSeverity(DiagnosticSeverity severity, bool supportsVisualStudioExtensions) + private static LSP.DiagnosticSeverity ConvertDiagnosticSeverity(DiagnosticSeverity severity) => severity switch { // Hidden is translated in ConvertTags to pass along appropriate _ms tags // that will hide the item in a client that knows about those tags. DiagnosticSeverity.Hidden => LSP.DiagnosticSeverity.Hint, - // VSCode shows information diagnostics as blue squiggles, and hint diagnostics as 3 dots. We prefer the latter rendering so we return hint diagnostics in vscode. - DiagnosticSeverity.Info => supportsVisualStudioExtensions ? LSP.DiagnosticSeverity.Information : LSP.DiagnosticSeverity.Hint, + DiagnosticSeverity.Info => LSP.DiagnosticSeverity.Information, DiagnosticSeverity.Warning => LSP.DiagnosticSeverity.Warning, DiagnosticSeverity.Error => LSP.DiagnosticSeverity.Error, _ => throw ExceptionUtilities.UnexpectedValue(severity), diff --git a/src/LanguageServer/Protocol/Extensions/SourceGeneratedDocumentUri.cs b/src/LanguageServer/Protocol/Extensions/SourceGeneratedDocumentUri.cs index c42bc1002eae8..2f31d44d03f40 100644 --- a/src/LanguageServer/Protocol/Extensions/SourceGeneratedDocumentUri.cs +++ b/src/LanguageServer/Protocol/Extensions/SourceGeneratedDocumentUri.cs @@ -4,8 +4,6 @@ using System; using System.Collections.Specialized; -using System.Linq; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer; diff --git a/src/LanguageServer/Protocol/ExternalAccess/Razor/SemanticTokensRangesHandler.cs b/src/LanguageServer/Protocol/ExternalAccess/Razor/SemanticTokensRangesHandler.cs index f5eeb317f5e83..d329f0ebc21b0 100644 --- a/src/LanguageServer/Protocol/ExternalAccess/Razor/SemanticTokensRangesHandler.cs +++ b/src/LanguageServer/Protocol/ExternalAccess/Razor/SemanticTokensRangesHandler.cs @@ -8,29 +8,24 @@ using Microsoft.CodeAnalysis.LanguageServer.Handler.SemanticTokens; using Microsoft.CodeAnalysis.Options; using Roslyn.LanguageServer.Protocol; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Razor; [Method(SemanticRangesMethodName)] -internal class SemanticTokensRangesHandler : ILspServiceDocumentRequestHandler +internal sealed class SemanticTokensRangesHandler( + IGlobalOptionService globalOptions, + SemanticTokensRefreshQueue semanticTokensRefreshQueue) + : ILspServiceDocumentRequestHandler { public const string SemanticRangesMethodName = "roslyn/semanticTokenRanges"; - private readonly IGlobalOptionService _globalOptions; - private readonly SemanticTokensRefreshQueue _semanticTokenRefreshQueue; + + private readonly IGlobalOptionService _globalOptions = globalOptions; + private readonly SemanticTokensRefreshQueue _semanticTokenRefreshQueue = semanticTokensRefreshQueue; public bool MutatesSolutionState => false; public bool RequiresLSPSolution => true; - public SemanticTokensRangesHandler( - IGlobalOptionService globalOptions, - SemanticTokensRefreshQueue semanticTokensRefreshQueue) - { - _globalOptions = globalOptions; - _semanticTokenRefreshQueue = semanticTokensRefreshQueue; - } - public TextDocumentIdentifier GetTextDocumentIdentifier(SemanticTokensRangesParams request) { Contract.ThrowIfNull(request.TextDocument); @@ -38,12 +33,14 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(SemanticTokensRangesPara } public async Task HandleRequestAsync( - SemanticTokensRangesParams request, - RequestContext context, - CancellationToken cancellationToken) + SemanticTokensRangesParams request, + RequestContext context, + CancellationToken cancellationToken) { Contract.ThrowIfNull(request.TextDocument, "TextDocument is null."); - var tokensData = await SemanticTokensHelpers.HandleRequestHelperAsync(_globalOptions, _semanticTokenRefreshQueue, request.Ranges, context, cancellationToken).ConfigureAwait(false); + + var tokensData = await SemanticTokensHelpers.HandleRequestHelperAsync( + _globalOptions, _semanticTokenRefreshQueue, request.Ranges, context, cancellationToken).ConfigureAwait(false); return new SemanticTokens { Data = tokensData }; } } diff --git a/src/LanguageServer/Protocol/ExternalAccess/VSMac/API/VSMacLspLoggerFactory.cs b/src/LanguageServer/Protocol/ExternalAccess/VSMac/API/VSMacLspLoggerFactory.cs deleted file mode 100644 index d4d94e2f6f238..0000000000000 --- a/src/LanguageServer/Protocol/ExternalAccess/VSMac/API/VSMacLspLoggerFactory.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Threading; -using System.Threading.Tasks; -using StreamJsonRpc; - -namespace Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.VSMac.API; - -internal interface IVSMacLspLoggerFactory -{ - Task CreateLoggerAsync(string serverTypeName, JsonRpc jsonRpc, CancellationToken cancellationToken); -} - -internal interface IVSMacLspLogger -{ - void TraceInformation(string message); - void TraceWarning(string message); - void TraceError(string message); - void TraceException(Exception exception); - void TraceStart(string message); - void TraceStop(string message); -} diff --git a/src/LanguageServer/Protocol/ExternalAccess/VSMac/AnalyzerHelper.cs b/src/LanguageServer/Protocol/ExternalAccess/VSMac/AnalyzerHelper.cs deleted file mode 100644 index c32a8a926d36e..0000000000000 --- a/src/LanguageServer/Protocol/ExternalAccess/VSMac/AnalyzerHelper.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.CodeAnalysis.Diagnostics; - -namespace Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.VSMac; - -internal static class AnalyzerHelper -{ - public static DiagnosticData CreateAnalyzerLoadFailureDiagnostic(AnalyzerLoadFailureEventArgs e, string fullPath, ProjectId? projectId, string? language) - => DocumentAnalysisExecutor.CreateAnalyzerLoadFailureDiagnostic(e, fullPath, projectId, language); -} - diff --git a/src/LanguageServer/Protocol/ExternalAccess/VSMac/CompletionOptionsAccessor.cs b/src/LanguageServer/Protocol/ExternalAccess/VSMac/CompletionOptionsAccessor.cs deleted file mode 100644 index 72cfaa7d93563..0000000000000 --- a/src/LanguageServer/Protocol/ExternalAccess/VSMac/CompletionOptionsAccessor.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 Microsoft.CodeAnalysis.Completion; -using Microsoft.CodeAnalysis.Options; - -namespace Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.VSMac; - -internal static class CompletionOptionsAccessor -{ - public static PerLanguageOption2 ShowItemsFromUnimportedNamespaces - => CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces; - - public static PerLanguageOption2 TriggerOnTypingLetters - => CompletionOptionsStorage.TriggerOnTypingLetters; - - public static PerLanguageOption2 TriggerOnDeletion - => CompletionOptionsStorage.TriggerOnDeletion; -} - diff --git a/src/LanguageServer/Protocol/ExternalAccess/VSMac/SolutionCrawlerOptionsAccessor.cs b/src/LanguageServer/Protocol/ExternalAccess/VSMac/SolutionCrawlerOptionsAccessor.cs deleted file mode 100644 index f13ac0778309c..0000000000000 --- a/src/LanguageServer/Protocol/ExternalAccess/VSMac/SolutionCrawlerOptionsAccessor.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.Options; -using Microsoft.CodeAnalysis.SolutionCrawler; - -namespace Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.VSMac; - -internal static class SolutionCrawlerOptionsAccessor -{ - public static bool LowMemoryForcedMinimalBackgroundAnalysis - { - get => SolutionCrawlerOptionsStorage.LowMemoryForcedMinimalBackgroundAnalysis; - set => SolutionCrawlerOptionsStorage.LowMemoryForcedMinimalBackgroundAnalysis = value; - } - - public static PerLanguageOption2 BackgroundAnalysisScopeOption - => SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption; - - public static BackgroundAnalysisScope GetBackgroundAnalysisScope(IGlobalOptionService globalOptions, string language) - => SolutionCrawlerOptionsStorage.GetBackgroundAnalysisScope(globalOptions, language); -} diff --git a/src/LanguageServer/Protocol/Features/CodeCleanup/AbstractCodeCleanupService.cs b/src/LanguageServer/Protocol/Features/CodeCleanup/AbstractCodeCleanupService.cs index 6f546fa963e47..67409f355e2ae 100644 --- a/src/LanguageServer/Protocol/Features/CodeCleanup/AbstractCodeCleanupService.cs +++ b/src/LanguageServer/Protocol/Features/CodeCleanup/AbstractCodeCleanupService.cs @@ -188,7 +188,7 @@ private async Task ApplyCodeFixesForSpecificDiagnosticIdAsync( var fixAllService = document.Project.Solution.Services.GetRequiredService(); var solution = await fixAllService.GetFixAllChangedSolutionAsync( - new FixAllContext(fixCollection.FixAllState, progressTracker, cancellationToken)).ConfigureAwait(false); + new FixAllContext(fixCollection.FixAllState!, progressTracker, cancellationToken)).ConfigureAwait(false); Contract.ThrowIfNull(solution); return solution.GetDocument(document.Id) ?? throw new NotSupportedException(FeaturesResources.Removal_of_document_not_supported); @@ -202,7 +202,6 @@ private async Task ApplyCodeFixesForSpecificDiagnosticIdAsync( // Compute diagnostics for everything that is not an IDE analyzer var diagnostics = await _diagnosticService.GetDiagnosticsForSpanAsync(document, range, shouldIncludeDiagnostic: static diagnosticId => !(IDEDiagnosticIdToOptionMappingHelper.IsKnownIDEDiagnosticId(diagnosticId)), - includeCompilerDiagnostics: true, priorityProvider: new DefaultCodeActionRequestPriorityProvider(), DiagnosticKind.All, isExplicit: false, cancellationToken).ConfigureAwait(false); diff --git a/src/LanguageServer/Protocol/Features/CodeCleanup/EnabledDiagnosticOptions.cs b/src/LanguageServer/Protocol/Features/CodeCleanup/EnabledDiagnosticOptions.cs index 5095d988cace9..e524d18aed23d 100644 --- a/src/LanguageServer/Protocol/Features/CodeCleanup/EnabledDiagnosticOptions.cs +++ b/src/LanguageServer/Protocol/Features/CodeCleanup/EnabledDiagnosticOptions.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; namespace Microsoft.CodeAnalysis.CodeCleanup diff --git a/src/LanguageServer/Protocol/Features/CodeCleanup/ICodeCleanupService.cs b/src/LanguageServer/Protocol/Features/CodeCleanup/ICodeCleanupService.cs index 64ac9a965739c..320d9ea7b7ef7 100644 --- a/src/LanguageServer/Protocol/Features/CodeCleanup/ICodeCleanupService.cs +++ b/src/LanguageServer/Protocol/Features/CodeCleanup/ICodeCleanupService.cs @@ -5,7 +5,6 @@ using System; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.CodeCleanup diff --git a/src/LanguageServer/Protocol/Features/CodeCleanup/OrganizeUsingsSettings.cs b/src/LanguageServer/Protocol/Features/CodeCleanup/OrganizeUsingsSettings.cs index 7e9033178f39b..b9f01c93bfeeb 100644 --- a/src/LanguageServer/Protocol/Features/CodeCleanup/OrganizeUsingsSettings.cs +++ b/src/LanguageServer/Protocol/Features/CodeCleanup/OrganizeUsingsSettings.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.CodeCleanup { /// diff --git a/src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.FixAllDiagnosticProvider.cs b/src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.FixAllDiagnosticProvider.cs index 55bde7157b61e..46e18b82466e5 100644 --- a/src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.FixAllDiagnosticProvider.cs +++ b/src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.FixAllDiagnosticProvider.cs @@ -12,74 +12,72 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.CodeFixes +namespace Microsoft.CodeAnalysis.CodeFixes; + +internal partial class CodeFixService { - internal partial class CodeFixService + private sealed class FixAllDiagnosticProvider : FixAllContext.SpanBasedDiagnosticProvider { - private sealed class FixAllDiagnosticProvider : FixAllContext.SpanBasedDiagnosticProvider + private readonly IDiagnosticAnalyzerService _diagnosticService; + private readonly ImmutableHashSet? _diagnosticIds; + private readonly bool _includeSuppressedDiagnostics; + + public FixAllDiagnosticProvider(IDiagnosticAnalyzerService diagnosticService, ImmutableHashSet diagnosticIds) { - private readonly IDiagnosticAnalyzerService _diagnosticService; - private readonly ImmutableHashSet? _diagnosticIds; - private readonly bool _includeSuppressedDiagnostics; + _diagnosticService = diagnosticService; - public FixAllDiagnosticProvider(IDiagnosticAnalyzerService diagnosticService, ImmutableHashSet diagnosticIds) + // When computing FixAll for unnecessary pragma suppression diagnostic, + // we need to include suppressed diagnostics, as well as reported compiler and analyzer diagnostics. + // A null value for '_diagnosticIds' ensures the latter. + if (diagnosticIds.Contains(IDEDiagnosticIds.RemoveUnnecessarySuppressionDiagnosticId)) { - _diagnosticService = diagnosticService; - - // When computing FixAll for unnecessary pragma suppression diagnostic, - // we need to include suppressed diagnostics, as well as reported compiler and analyzer diagnostics. - // A null value for '_diagnosticIds' ensures the latter. - if (diagnosticIds.Contains(IDEDiagnosticIds.RemoveUnnecessarySuppressionDiagnosticId)) - { - _diagnosticIds = null; - _includeSuppressedDiagnostics = true; - } - else - { - _diagnosticIds = diagnosticIds; - _includeSuppressedDiagnostics = false; - } + _diagnosticIds = null; + _includeSuppressedDiagnostics = true; } - - private ImmutableArray Filter(ImmutableArray diagnostics) - => diagnostics.WhereAsArray(d => _includeSuppressedDiagnostics || !d.IsSuppressed); - - public override async Task> GetDocumentDiagnosticsAsync(Document document, CancellationToken cancellationToken) + else { - var solution = document.Project.Solution; - var diagnostics = Filter(await _diagnosticService.GetDiagnosticsForIdsAsync( - solution, projectId: null, document.Id, _diagnosticIds, shouldIncludeAnalyzer: null, includeLocalDocumentDiagnostics: true, includeNonLocalDocumentDiagnostics: false, cancellationToken).ConfigureAwait(false)); - Contract.ThrowIfFalse(diagnostics.All(d => d.DocumentId != null)); - return await diagnostics.ToDiagnosticsAsync(document.Project, cancellationToken).ConfigureAwait(false); + _diagnosticIds = diagnosticIds; + _includeSuppressedDiagnostics = false; } + } - public override async Task> GetDocumentSpanDiagnosticsAsync(Document document, TextSpan fixAllSpan, CancellationToken cancellationToken) - { - bool shouldIncludeDiagnostic(string id) => _diagnosticIds == null || _diagnosticIds.Contains(id); - var diagnostics = Filter(await _diagnosticService.GetDiagnosticsForSpanAsync( - document, fixAllSpan, shouldIncludeDiagnostic, includeCompilerDiagnostics: true, - priorityProvider: new DefaultCodeActionRequestPriorityProvider(), - DiagnosticKind.All, isExplicit: false, cancellationToken).ConfigureAwait(false)); - Contract.ThrowIfFalse(diagnostics.All(d => d.DocumentId != null)); - return await diagnostics.ToDiagnosticsAsync(document.Project, cancellationToken).ConfigureAwait(false); - } + private ImmutableArray Filter(ImmutableArray diagnostics) + => diagnostics.WhereAsArray(d => _includeSuppressedDiagnostics || !d.IsSuppressed); - public override async Task> GetAllDiagnosticsAsync(Project project, CancellationToken cancellationToken) - { - // Get all diagnostics for the entire project, including document diagnostics. - var diagnostics = Filter(await _diagnosticService.GetDiagnosticsForIdsAsync( - project.Solution, project.Id, documentId: null, _diagnosticIds, shouldIncludeAnalyzer: null, includeLocalDocumentDiagnostics: true, includeNonLocalDocumentDiagnostics: false, cancellationToken).ConfigureAwait(false)); - return await diagnostics.ToDiagnosticsAsync(project, cancellationToken).ConfigureAwait(false); - } + public override async Task> GetDocumentDiagnosticsAsync(Document document, CancellationToken cancellationToken) + { + var diagnostics = Filter(await _diagnosticService.GetDiagnosticsForIdsAsync( + document.Project, document.Id, _diagnosticIds, shouldIncludeAnalyzer: null, includeLocalDocumentDiagnostics: true, includeNonLocalDocumentDiagnostics: false, cancellationToken).ConfigureAwait(false)); + Contract.ThrowIfFalse(diagnostics.All(d => d.DocumentId != null)); + return await diagnostics.ToDiagnosticsAsync(document.Project, cancellationToken).ConfigureAwait(false); + } - public override async Task> GetProjectDiagnosticsAsync(Project project, CancellationToken cancellationToken) - { - // Get all no-location diagnostics for the project, doesn't include document diagnostics. - var diagnostics = Filter(await _diagnosticService.GetProjectDiagnosticsForIdsAsync( - project.Solution, project.Id, _diagnosticIds, shouldIncludeAnalyzer: null, includeNonLocalDocumentDiagnostics: false, cancellationToken).ConfigureAwait(false)); - Contract.ThrowIfFalse(diagnostics.All(d => d.DocumentId == null)); - return await diagnostics.ToDiagnosticsAsync(project, cancellationToken).ConfigureAwait(false); - } + public override async Task> GetDocumentSpanDiagnosticsAsync(Document document, TextSpan fixAllSpan, CancellationToken cancellationToken) + { + bool shouldIncludeDiagnostic(string id) => _diagnosticIds == null || _diagnosticIds.Contains(id); + var diagnostics = Filter(await _diagnosticService.GetDiagnosticsForSpanAsync( + document, fixAllSpan, shouldIncludeDiagnostic, + priorityProvider: new DefaultCodeActionRequestPriorityProvider(), + DiagnosticKind.All, isExplicit: false, cancellationToken).ConfigureAwait(false)); + Contract.ThrowIfFalse(diagnostics.All(d => d.DocumentId != null)); + return await diagnostics.ToDiagnosticsAsync(document.Project, cancellationToken).ConfigureAwait(false); + } + + public override async Task> GetAllDiagnosticsAsync(Project project, CancellationToken cancellationToken) + { + // Get all diagnostics for the entire project, including document diagnostics. + var diagnostics = Filter(await _diagnosticService.GetDiagnosticsForIdsAsync( + project, documentId: null, _diagnosticIds, shouldIncludeAnalyzer: null, includeLocalDocumentDiagnostics: true, includeNonLocalDocumentDiagnostics: false, cancellationToken).ConfigureAwait(false)); + return await diagnostics.ToDiagnosticsAsync(project, cancellationToken).ConfigureAwait(false); + } + + public override async Task> GetProjectDiagnosticsAsync(Project project, CancellationToken cancellationToken) + { + // Get all no-location diagnostics for the project, doesn't include document diagnostics. + var diagnostics = Filter(await _diagnosticService.GetProjectDiagnosticsForIdsAsync( + project, _diagnosticIds, shouldIncludeAnalyzer: null, includeNonLocalDocumentDiagnostics: false, cancellationToken).ConfigureAwait(false)); + Contract.ThrowIfFalse(diagnostics.All(d => d.DocumentId == null)); + return await diagnostics.ToDiagnosticsAsync(project, cancellationToken).ConfigureAwait(false); } } } diff --git a/src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.FixAllPredefinedDiagnosticProvider.cs b/src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.FixAllPredefinedDiagnosticProvider.cs index e6afa1afad67c..9e99b4c45c0b2 100644 --- a/src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.FixAllPredefinedDiagnosticProvider.cs +++ b/src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.FixAllPredefinedDiagnosticProvider.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; diff --git a/src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.cs b/src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.cs index c78d9bd421e96..1ffd392fbd3b1 100644 --- a/src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.cs +++ b/src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.cs @@ -109,7 +109,7 @@ public CodeFixService( { allDiagnostics = await _diagnosticService.GetDiagnosticsForSpanAsync( document, range, GetShouldIncludeDiagnosticPredicate(document, priorityProvider), - includeCompilerDiagnostics: true, priorityProvider, DiagnosticKind.All, isExplicit: false, cancellationToken).ConfigureAwait(false); + priorityProvider, DiagnosticKind.All, isExplicit: false, cancellationToken).ConfigureAwait(false); // NOTE(cyrusn): We do not include suppressed diagnostics here as they are effectively hidden from the // user in the editor. As far as the user is concerned, there is no squiggle for it and no lightbulb @@ -199,7 +199,7 @@ public async IAsyncEnumerable StreamFixesAsync( { diagnostics = await _diagnosticService.GetDiagnosticsForSpanAsync( document, range, GetShouldIncludeDiagnosticPredicate(document, priorityProvider), - includeCompilerDiagnostics: true, priorityProvider, DiagnosticKind.All, isExplicit: true, cancellationToken).ConfigureAwait(false); + priorityProvider, DiagnosticKind.All, isExplicit: true, cancellationToken).ConfigureAwait(false); if (!includeSuppressionFixes) diagnostics = diagnostics.WhereAsArray(d => !d.IsSuppressed); } @@ -358,7 +358,7 @@ public async Task ApplyCodeFixesForSpecificDiagnosticIdAsync(); var solution = await fixAllService.GetFixAllChangedSolutionAsync( - new FixAllContext(fixCollection.FixAllState, progressTracker, cancellationToken)).ConfigureAwait(false); + new FixAllContext(fixCollection.FixAllState!, progressTracker, cancellationToken)).ConfigureAwait(false); Contract.ThrowIfNull(solution); return (TDocument)(solution.GetTextDocument(document.Id) ?? throw new NotSupportedException(FeaturesResources.Removal_of_document_not_supported)); diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService.cs b/src/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService.cs index fbef8d15b4f76..d70c50f09b744 100644 --- a/src/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService.cs +++ b/src/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Composition; using System.Runtime.CompilerServices; @@ -11,7 +10,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.Diagnostics.EngineV2; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; @@ -21,8 +19,7 @@ namespace Microsoft.CodeAnalysis.Diagnostics { - [Export(typeof(IDiagnosticAnalyzerService))] - [Shared] + [Export(typeof(IDiagnosticAnalyzerService)), Shared] internal partial class DiagnosticAnalyzerService : IDiagnosticAnalyzerService { private static readonly Option2 s_crashOnAnalyzerException = new("dotnet_crash_on_analyzer_exception", defaultValue: false); @@ -30,7 +27,7 @@ internal partial class DiagnosticAnalyzerService : IDiagnosticAnalyzerService public DiagnosticAnalyzerInfoCache AnalyzerInfoCache { get; private set; } public IAsynchronousOperationListener Listener { get; } - public IGlobalOptionService GlobalOptions { get; } + private IGlobalOptionService GlobalOptions { get; } private readonly ConditionalWeakTable _map = new(); private readonly ConditionalWeakTable.CreateValueCallback _createIncrementalAnalyzer; @@ -59,6 +56,9 @@ public DiagnosticAnalyzerService( }); } + public static Task GetDiagnosticVersionAsync(Project project, CancellationToken cancellationToken) + => project.GetDependentVersionAsync(cancellationToken); + public bool CrashOnAnalyzerException => GlobalOptions.GetOption(s_crashOnAnalyzerException); @@ -68,16 +68,20 @@ public static bool IsGlobalOptionAffectingDiagnostics(IOption2 option) option == SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption || option == SolutionCrawlerOptionsStorage.SolutionBackgroundAnalysisScopeOption || option == SolutionCrawlerOptionsStorage.CompilerDiagnosticsScopeOption || - option == s_crashOnAnalyzerException; + option == s_crashOnAnalyzerException || + // Fading is controlled by reporting diagnostics for the faded region. So if a fading option changes we + // want to recompute and rereport up to date diagnostics. + option == FadingOptions.FadeOutUnusedImports || + option == FadingOptions.FadeOutUnusedMembers || + option == FadingOptions.FadeOutUnreachableCode; public void RequestDiagnosticRefresh() - => _diagnosticsRefresher?.RequestWorkspaceRefresh(); + => _diagnosticsRefresher.RequestWorkspaceRefresh(); public async Task> GetDiagnosticsForSpanAsync( TextDocument document, TextSpan? range, Func? shouldIncludeDiagnostic, - bool includeCompilerDiagnostics, ICodeActionRequestPriorityProvider priorityProvider, DiagnosticKind diagnosticKinds, bool isExplicit, @@ -90,36 +94,40 @@ public async Task> GetDiagnosticsForSpanAsync( priorityProvider ??= new DefaultCodeActionRequestPriorityProvider(); return await analyzer.GetDiagnosticsForSpanAsync( - document, range, shouldIncludeDiagnostic, includeCompilerDiagnostics, - priorityProvider, diagnosticKinds, isExplicit, cancellationToken).ConfigureAwait(false); - } - - public Task> GetCachedDiagnosticsAsync(Workspace workspace, ProjectId? projectId, DocumentId? documentId, bool includeLocalDocumentDiagnostics, bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken) - { - var analyzer = CreateIncrementalAnalyzer(workspace); - return analyzer.GetCachedDiagnosticsAsync(workspace.CurrentSolution, projectId, documentId, includeLocalDocumentDiagnostics, includeNonLocalDocumentDiagnostics, cancellationToken); + document, range, shouldIncludeDiagnostic, priorityProvider, diagnosticKinds, isExplicit, cancellationToken).ConfigureAwait(false); } - public async Task ForceAnalyzeProjectAsync(Project project, CancellationToken cancellationToken) + public async Task> ForceAnalyzeProjectAsync(Project project, CancellationToken cancellationToken) { var analyzer = CreateIncrementalAnalyzer(project.Solution.Workspace); - await analyzer.ForceAnalyzeProjectAsync(project, cancellationToken).ConfigureAwait(false); + return await analyzer.ForceAnalyzeProjectAsync(project, cancellationToken).ConfigureAwait(false); } public Task> GetDiagnosticsForIdsAsync( - Solution solution, ProjectId? projectId, DocumentId? documentId, ImmutableHashSet? diagnosticIds, Func? shouldIncludeAnalyzer, Func>? getDocuments, bool includeLocalDocumentDiagnostics, bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken) + Project project, DocumentId? documentId, ImmutableHashSet? diagnosticIds, Func? shouldIncludeAnalyzer, bool includeLocalDocumentDiagnostics, bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken) { - var analyzer = CreateIncrementalAnalyzer(solution.Workspace); - return analyzer.GetDiagnosticsForIdsAsync(solution, projectId, documentId, diagnosticIds, shouldIncludeAnalyzer, getDocuments, includeLocalDocumentDiagnostics, includeNonLocalDocumentDiagnostics, cancellationToken); + var analyzer = CreateIncrementalAnalyzer(project.Solution.Workspace); + return analyzer.GetDiagnosticsForIdsAsync(project, documentId, diagnosticIds, shouldIncludeAnalyzer, includeLocalDocumentDiagnostics, includeNonLocalDocumentDiagnostics, cancellationToken); } public Task> GetProjectDiagnosticsForIdsAsync( - Solution solution, ProjectId? projectId, ImmutableHashSet? diagnosticIds, + Project project, ImmutableHashSet? diagnosticIds, Func? shouldIncludeAnalyzer, bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken) { - var analyzer = CreateIncrementalAnalyzer(solution.Workspace); - return analyzer.GetProjectDiagnosticsForIdsAsync(solution, projectId, diagnosticIds, shouldIncludeAnalyzer, includeNonLocalDocumentDiagnostics, cancellationToken); + var analyzer = CreateIncrementalAnalyzer(project.Solution.Workspace); + return analyzer.GetProjectDiagnosticsForIdsAsync(project, diagnosticIds, shouldIncludeAnalyzer, includeNonLocalDocumentDiagnostics, cancellationToken); + } + + public TestAccessor GetTestAccessor() + => new(this); + + public readonly struct TestAccessor(DiagnosticAnalyzerService service) + { + public Task> GetAnalyzersAsync(Project project, CancellationToken cancellationToken) + { + return service.CreateIncrementalAnalyzer(project.Solution.Workspace).GetAnalyzersForTestingPurposesOnlyAsync(project, cancellationToken); + } } } } diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService_IncrementalAnalyzer.cs b/src/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService_IncrementalAnalyzer.cs index 99d9760bc40ca..9a0b3fa16fdb9 100644 --- a/src/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService_IncrementalAnalyzer.cs +++ b/src/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService_IncrementalAnalyzer.cs @@ -2,26 +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; -using Microsoft.CodeAnalysis.Diagnostics.EngineV2; -using Microsoft.CodeAnalysis.Host.Mef; - namespace Microsoft.CodeAnalysis.Diagnostics; internal partial class DiagnosticAnalyzerService { - public DiagnosticIncrementalAnalyzer CreateIncrementalAnalyzer(Workspace workspace) + private DiagnosticIncrementalAnalyzer CreateIncrementalAnalyzer(Workspace workspace) { return _map.GetValue(workspace, _createIncrementalAnalyzer); } - [Obsolete(MefConstruction.FactoryMethodMessage, error: true)] private DiagnosticIncrementalAnalyzer CreateIncrementalAnalyzerCallback(Workspace workspace) { // subscribe to active context changed event for new workspace workspace.DocumentActiveContextChanged += OnDocumentActiveContextChanged; - return new DiagnosticIncrementalAnalyzer(this, workspace, AnalyzerInfoCache); + return new DiagnosticIncrementalAnalyzer(this, AnalyzerInfoCache, this.GlobalOptions); } private void OnDocumentActiveContextChanged(object? sender, DocumentActiveContextChangedEventArgs e) diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/DocumentAnalysisExecutor_Helpers.cs b/src/LanguageServer/Protocol/Features/Diagnostics/DocumentAnalysisExecutor_Helpers.cs index eecd062437cec..ef96728725dcb 100644 --- a/src/LanguageServer/Protocol/Features/Diagnostics/DocumentAnalysisExecutor_Helpers.cs +++ b/src/LanguageServer/Protocol/Features/Diagnostics/DocumentAnalysisExecutor_Helpers.cs @@ -5,12 +5,8 @@ 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.Diagnostics.EngineV2; -using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.SolutionCrawler; using Microsoft.CodeAnalysis.Text; @@ -128,84 +124,6 @@ static string GetLanguageSpecificId(string? language, string noLanguageId, strin language: language); } - public static async Task CreateCompilationWithAnalyzersAsync( - Project project, - ImmutableArray projectAnalyzers, - ImmutableArray hostAnalyzers, - bool crashOnAnalyzerException, - CancellationToken cancellationToken) - { - var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); - if (compilation == null) - { - // project doesn't support compilation - return null; - } - - // Create driver that holds onto compilation and associated analyzers - var filteredProjectAnalyzers = projectAnalyzers.WhereAsArray(static a => !a.IsWorkspaceDiagnosticAnalyzer()); - var filteredHostAnalyzers = hostAnalyzers.WhereAsArray(static a => !a.IsWorkspaceDiagnosticAnalyzer()); - var filteredProjectSuppressors = filteredProjectAnalyzers.WhereAsArray(static a => a is DiagnosticSuppressor); - filteredHostAnalyzers = filteredHostAnalyzers.AddRange(filteredProjectSuppressors); - - // PERF: there is no analyzers for this compilation. - // compilationWithAnalyzer will throw if it is created with no analyzers which is perf optimization. - if (filteredProjectAnalyzers.IsEmpty && filteredHostAnalyzers.IsEmpty) - { - return null; - } - - Contract.ThrowIfFalse(project.SupportsCompilation); - AssertCompilation(project, compilation); - - // in IDE, we always set concurrentAnalysis == false otherwise, we can get into thread starvation due to - // async being used with synchronous blocking concurrency. - var projectAnalyzerOptions = new CompilationWithAnalyzersOptions( - options: project.AnalyzerOptions, - onAnalyzerException: null, - analyzerExceptionFilter: GetAnalyzerExceptionFilter(), - concurrentAnalysis: false, - logAnalyzerExecutionTime: true, - reportSuppressedDiagnostics: true); - var hostAnalyzerOptions = new CompilationWithAnalyzersOptions( - options: project.HostAnalyzerOptions, - onAnalyzerException: null, - analyzerExceptionFilter: GetAnalyzerExceptionFilter(), - concurrentAnalysis: false, - logAnalyzerExecutionTime: true, - reportSuppressedDiagnostics: true); - - // Create driver that holds onto compilation and associated analyzers - return new CompilationWithAnalyzersPair( - filteredProjectAnalyzers.Any() ? compilation.WithAnalyzers(filteredProjectAnalyzers, projectAnalyzerOptions) : null, - filteredHostAnalyzers.Any() ? compilation.WithAnalyzers(filteredHostAnalyzers, hostAnalyzerOptions) : null); - - Func GetAnalyzerExceptionFilter() - { - return ex => - { - if (ex is not OperationCanceledException && crashOnAnalyzerException) - { - // report telemetry - FatalError.ReportAndPropagate(ex); - - // force fail fast (the host might not crash when reporting telemetry): - FailFast.OnFatalException(ex); - } - - return true; - }; - } - } - - [Conditional("DEBUG")] - private static void AssertCompilation(Project project, Compilation compilation1) - { - // given compilation must be from given project. - Contract.ThrowIfFalse(project.TryGetCompilation(out var compilation2)); - Contract.ThrowIfFalse(compilation1 == compilation2); - } - /// /// Return true if the given is not suppressed for the given project. /// NOTE: This API is intended to be used only for performance optimization. diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.ActiveFileState.cs b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.ActiveFileState.cs deleted file mode 100644 index 80b3249e48739..0000000000000 --- a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.ActiveFileState.cs +++ /dev/null @@ -1,86 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Diagnostics.EngineV2 -{ - internal partial class DiagnosticIncrementalAnalyzer - { - /// - /// state that is responsible to hold onto local diagnostics data regarding active/opened files (depends on host) - /// in memory. - /// - private sealed class ActiveFileState - { - private readonly object _gate = new(); - - // file state this is for - public readonly DocumentId DocumentId; - - // analysis data for each kind - private DocumentAnalysisData _syntax = DocumentAnalysisData.Empty; - private DocumentAnalysisData _semantic = DocumentAnalysisData.Empty; - - public ActiveFileState(DocumentId documentId) - => DocumentId = documentId; - - public bool IsEmpty - { - get - { - lock (_gate) - { - return _syntax.Items.IsEmpty && _semantic.Items.IsEmpty; - } - } - } - - public void ResetVersion() - { - lock (_gate) - { - // reset version of cached data so that we can recalculate new data (ex, OnDocumentReset) - _syntax = new DocumentAnalysisData(VersionStamp.Default, _syntax.LineCount, _syntax.Items); - _semantic = new DocumentAnalysisData(VersionStamp.Default, _semantic.LineCount, _semantic.Items); - } - } - - public DocumentAnalysisData GetAnalysisData(AnalysisKind kind) - { - lock (_gate) - { - return kind switch - { - AnalysisKind.Syntax => _syntax, - AnalysisKind.Semantic => _semantic, - _ => throw ExceptionUtilities.UnexpectedValue(kind) - }; - } - } - - public void Save(AnalysisKind kind, DocumentAnalysisData data) - { - Contract.ThrowIfFalse(data.OldItems.IsDefault); - - lock (_gate) - { - switch (kind) - { - case AnalysisKind.Syntax: - _syntax = data; - return; - - case AnalysisKind.Semantic: - _semantic = data; - return; - - default: - throw ExceptionUtilities.UnexpectedValue(kind); - } - } - } - } - } -} diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.AnalysisData.cs b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.AnalysisData.cs deleted file mode 100644 index 3be6f73e60c14..0000000000000 --- a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.AnalysisData.cs +++ /dev/null @@ -1,148 +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.Diagnostics; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Workspaces.Diagnostics; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Diagnostics.EngineV2 -{ - internal partial class DiagnosticIncrementalAnalyzer - { - /// - /// Simple data holder for local diagnostics for an analyzer - /// - private readonly struct DocumentAnalysisData - { - public static readonly DocumentAnalysisData Empty = new(VersionStamp.Default, lineCount: 0, []); - - /// - /// Version of the diagnostic data. - /// - public readonly VersionStamp Version; - - /// - /// Number of lines in the document. - /// - public readonly int LineCount; - - /// - /// Current data that matches the version. - /// - public readonly ImmutableArray Items; - - /// - /// Last set of data we broadcasted to outer world, or . - /// - public readonly ImmutableArray OldItems; - - public DocumentAnalysisData(VersionStamp version, int lineCount, ImmutableArray items) - { - Debug.Assert(!items.IsDefault); - - Version = version; - LineCount = lineCount; - Items = items; - OldItems = default; - } - - public DocumentAnalysisData(VersionStamp version, int lineCount, ImmutableArray oldItems, ImmutableArray newItems) - : this(version, lineCount, newItems) - { - Debug.Assert(!oldItems.IsDefault); - OldItems = oldItems; - } - } - - /// - /// Data holder for all diagnostics for a project for an analyzer - /// - private readonly struct ProjectAnalysisData - { - /// - /// ProjectId of this data - /// - public readonly ProjectId ProjectId; - - /// - /// Version of the Items - /// - public readonly VersionStamp Version; - - /// - /// Current data that matches the version - /// - public readonly ImmutableDictionary Result; - - /// - /// When present, holds onto last data we broadcasted to outer world. - /// - public readonly ImmutableDictionary? OldResult; - - public ProjectAnalysisData(ProjectId projectId, VersionStamp version, ImmutableDictionary result) - { - ProjectId = projectId; - Version = version; - Result = result; - - OldResult = null; - } - - public ProjectAnalysisData( - ProjectId projectId, - VersionStamp version, - ImmutableDictionary oldResult, - ImmutableDictionary newResult) - : this(projectId, version, newResult) - { - OldResult = oldResult; - } - - public DiagnosticAnalysisResult GetResult(DiagnosticAnalyzer analyzer) - => GetResultOrEmpty(Result, analyzer, ProjectId, Version); - - public bool TryGetResult(DiagnosticAnalyzer analyzer, out DiagnosticAnalysisResult result) - => Result.TryGetValue(analyzer, out result); - - public static async Task CreateAsync(Project project, IEnumerable stateSets, bool avoidLoadingData, CancellationToken cancellationToken) - { - VersionStamp? version = null; - - var builder = ImmutableDictionary.CreateBuilder(); - foreach (var stateSet in stateSets) - { - var state = stateSet.GetOrCreateProjectState(project.Id); - var result = await state.GetAnalysisDataAsync(project, avoidLoadingData, cancellationToken).ConfigureAwait(false); - Contract.ThrowIfFalse(project.Id == result.ProjectId); - - if (!version.HasValue) - { - version = result.Version; - } - else if (version.Value != VersionStamp.Default && version.Value != result.Version) - { - // if not all version is same, set version as default. - // this can happen at the initial data loading or - // when document is closed and we put active file state to project state - version = VersionStamp.Default; - } - - builder.Add(stateSet.Analyzer, result); - } - - if (!version.HasValue) - { - // there is no saved data to return. - return new ProjectAnalysisData(project.Id, VersionStamp.Default, ImmutableDictionary.Empty); - } - - return new ProjectAnalysisData(project.Id, version.Value, builder.ToImmutable()); - } - } - } -} diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.CompilationManager.cs b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.CompilationManager.cs index 9775aef42f602..39715067f99ef 100644 --- a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.CompilationManager.cs +++ b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.CompilationManager.cs @@ -2,14 +2,128 @@ // The .NET Foundation 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.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.ErrorReporting; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Diagnostics.EngineV2; +namespace Microsoft.CodeAnalysis.Diagnostics; -internal partial class DiagnosticIncrementalAnalyzer +internal partial class DiagnosticAnalyzerService { - private static Task CreateCompilationWithAnalyzersAsync(Project project, ImmutableArray stateSets, bool crashOnAnalyzerException, CancellationToken cancellationToken) - => DocumentAnalysisExecutor.CreateCompilationWithAnalyzersAsync(project, stateSets.SelectAsArray(s => !s.IsHostAnalyzer, s => s.Analyzer), stateSets.SelectAsArray(s => s.IsHostAnalyzer, s => s.Analyzer), crashOnAnalyzerException, cancellationToken); + /// + /// Cached data from a to the last instance + /// created for it. Note: the CompilationWithAnalyzersPair instance is dependent on the set of s passed along with the project. As such, we might not be able to use a prior cached + /// value if the set of analyzers changes. In that case, a new instance will be created and will be cached for the + /// next caller. + /// + private static readonly ConditionalWeakTable analyzers, CompilationWithAnalyzersPair? compilationWithAnalyzersPair)>> s_projectToCompilationWithAnalyzers = new(); + + private static async Task GetOrCreateCompilationWithAnalyzersAsync( + Project project, + ImmutableArray analyzers, + HostAnalyzerInfo hostAnalyzerInfo, + bool crashOnAnalyzerException, + CancellationToken cancellationToken) + { + if (!project.SupportsCompilation) + return null; + + var projectState = project.State; + var checksum = await project.GetDiagnosticChecksumAsync(cancellationToken).ConfigureAwait(false); + + // Make sure the cached pair was computed with at least the same state sets we're asking about. if not, + // recompute and cache with the new state sets. + if (!s_projectToCompilationWithAnalyzers.TryGetValue(projectState, out var tupleBox) || + tupleBox.Value.checksum != checksum || + !analyzers.IsSubsetOf(tupleBox.Value.analyzers)) + { + var compilation = await project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); + var compilationWithAnalyzersPair = CreateCompilationWithAnalyzers(projectState, compilation); + tupleBox = new((checksum, analyzers, compilationWithAnalyzersPair)); + +#if NET + s_projectToCompilationWithAnalyzers.AddOrUpdate(projectState, tupleBox); +#else + // Make a best effort attempt to store the latest computed value against these state sets. If this + // fails (because another thread interleaves with this), that's ok. We still return the pair we + // computed, so our caller will still see the right data + s_projectToCompilationWithAnalyzers.Remove(projectState); + + // Intentionally ignore the result of this. We still want to use the value we computed above, even if + // another thread interleaves and sets a different value. + s_projectToCompilationWithAnalyzers.GetValue(projectState, _ => tupleBox); +#endif + } + + return tupleBox.Value.compilationWithAnalyzersPair; + + // + // Should only be called on a that . + // + CompilationWithAnalyzersPair? CreateCompilationWithAnalyzers( + ProjectState project, Compilation compilation) + { + var projectAnalyzers = analyzers.WhereAsArray(static (s, info) => !info.IsHostAnalyzer(s), hostAnalyzerInfo); + var hostAnalyzers = analyzers.WhereAsArray(static (s, info) => info.IsHostAnalyzer(s), hostAnalyzerInfo); + + // Create driver that holds onto compilation and associated analyzers + var filteredProjectAnalyzers = projectAnalyzers.WhereAsArray(static a => !a.IsWorkspaceDiagnosticAnalyzer()); + var filteredHostAnalyzers = hostAnalyzers.WhereAsArray(static a => !a.IsWorkspaceDiagnosticAnalyzer()); + var filteredProjectSuppressors = filteredProjectAnalyzers.WhereAsArray(static a => a is DiagnosticSuppressor); + filteredHostAnalyzers = filteredHostAnalyzers.AddRange(filteredProjectSuppressors); + + // PERF: there is no analyzers for this compilation. + // compilationWithAnalyzer will throw if it is created with no analyzers which is perf optimization. + if (filteredProjectAnalyzers.IsEmpty && filteredHostAnalyzers.IsEmpty) + { + return null; + } + + var exceptionFilter = (Exception ex) => + { + if (ex is not OperationCanceledException && crashOnAnalyzerException) + { + // report telemetry + FatalError.ReportAndPropagate(ex); + + // force fail fast (the host might not crash when reporting telemetry): + FailFast.OnFatalException(ex); + } + + return true; + }; + + // in IDE, we always set concurrentAnalysis == false otherwise, we can get into thread starvation due to + // async being used with synchronous blocking concurrency. + var projectCompilation = !filteredProjectAnalyzers.Any() + ? null + : compilation.WithAnalyzers(filteredProjectAnalyzers, new CompilationWithAnalyzersOptions( + options: project.ProjectAnalyzerOptions, + onAnalyzerException: null, + analyzerExceptionFilter: exceptionFilter, + concurrentAnalysis: false, + logAnalyzerExecutionTime: true, + reportSuppressedDiagnostics: true)); + + var hostCompilation = !filteredHostAnalyzers.Any() + ? null + : compilation.WithAnalyzers(filteredHostAnalyzers, new CompilationWithAnalyzersOptions( + options: project.HostAnalyzerOptions, + onAnalyzerException: null, + analyzerExceptionFilter: exceptionFilter, + concurrentAnalysis: false, + logAnalyzerExecutionTime: true, + reportSuppressedDiagnostics: true)); + + // Create driver that holds onto compilation and associated analyzers + return new CompilationWithAnalyzersPair(projectCompilation, hostCompilation); + } + } } diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.Executor.cs b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.Executor.cs index 82f948660ab2d..9083f2b77e0c4 100644 --- a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.Executor.cs +++ b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.Executor.cs @@ -11,342 +11,234 @@ using Microsoft.CodeAnalysis.Diagnostics.Telemetry; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Workspaces.Diagnostics; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Diagnostics.EngineV2 +namespace Microsoft.CodeAnalysis.Diagnostics; + +internal partial class DiagnosticAnalyzerService { - internal partial class DiagnosticIncrementalAnalyzer + private partial class DiagnosticIncrementalAnalyzer { /// - /// Return all diagnostics that belong to given project for the given StateSets (analyzers) either from cache or by calculating them + /// Return all diagnostics that belong to given project for the given either + /// from cache or by calculating them. /// - private async Task GetProjectAnalysisDataAsync( - CompilationWithAnalyzersPair? compilationWithAnalyzers, Project project, ImmutableArray stateSets, CancellationToken cancellationToken) + private async Task> ComputeDiagnosticAnalysisResultsAsync( + CompilationWithAnalyzersPair? compilationWithAnalyzers, + Project project, + ImmutableArray analyzers, + CancellationToken cancellationToken) { - using (Logger.LogBlock(FunctionId.Diagnostics_ProjectDiagnostic, GetProjectLogMessage, project, stateSets, cancellationToken)) + using (Logger.LogBlock(FunctionId.Diagnostics_ProjectDiagnostic, GetProjectLogMessage, project, analyzers, cancellationToken)) { try { - // PERF: We need to flip this to false when we do actual diffing. - var avoidLoadingData = true; - var version = await GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false); - var existingData = await ProjectAnalysisData.CreateAsync(project, stateSets, avoidLoadingData, cancellationToken).ConfigureAwait(false); - - if (existingData.Version == version) - return existingData; - - var result = await ComputeDiagnosticsAsync(compilationWithAnalyzers, project, stateSets, existingData.Result, cancellationToken).ConfigureAwait(false); + var result = await ComputeDiagnosticsForIDEAnalyzersAsync(analyzers).ConfigureAwait(false); // If project is not loaded successfully, get rid of any semantic errors from compiler analyzer. // Note: In the past when project was not loaded successfully we did not run any analyzers on the project. // Now we run analyzers but filter out some information. So on such projects, there will be some perf degradation. - result = await RemoveCompilerSemanticErrorsIfProjectNotLoadedAsync(result, project, cancellationToken).ConfigureAwait(false); + result = await RemoveCompilerSemanticErrorsIfProjectNotLoadedAsync(result).ConfigureAwait(false); - return new ProjectAnalysisData(project.Id, version, existingData.Result, result); + return result; } catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable(); } } - } - private static async Task> RemoveCompilerSemanticErrorsIfProjectNotLoadedAsync( - ImmutableDictionary result, Project project, CancellationToken cancellationToken) - { - // see whether solution is loaded successfully - var projectLoadedSuccessfully = await project.HasSuccessfullyLoadedAsync(cancellationToken).ConfigureAwait(false); - if (projectLoadedSuccessfully) + async Task> RemoveCompilerSemanticErrorsIfProjectNotLoadedAsync( + ImmutableDictionary result) { - return result; - } + // see whether solution is loaded successfully + var projectLoadedSuccessfully = await project.HasSuccessfullyLoadedAsync(cancellationToken).ConfigureAwait(false); + if (projectLoadedSuccessfully) + { + return result; + } - var compilerAnalyzer = project.Solution.SolutionState.Analyzers.GetCompilerDiagnosticAnalyzer(project.Language); - if (compilerAnalyzer == null) - { - // this language doesn't support compiler analyzer - return result; - } + var compilerAnalyzer = project.Solution.SolutionState.Analyzers.GetCompilerDiagnosticAnalyzer(project.Language); + if (compilerAnalyzer == null) + { + // this language doesn't support compiler analyzer + return result; + } - if (!result.TryGetValue(compilerAnalyzer, out var analysisResult)) - { - // no result from compiler analyzer - return result; - } + if (!result.TryGetValue(compilerAnalyzer, out var analysisResult)) + { + // no result from compiler analyzer + return result; + } - Logger.Log(FunctionId.Diagnostics_ProjectDiagnostic, p => $"Failed to Load Successfully ({p.FilePath ?? p.Name})", project); + Logger.Log(FunctionId.Diagnostics_ProjectDiagnostic, p => $"Failed to Load Successfully ({p.FilePath ?? p.Name})", project); - // get rid of any result except syntax from compiler analyzer result - var newCompilerAnalysisResult = analysisResult.DropExceptSyntax(); + // get rid of any result except syntax from compiler analyzer result + var newCompilerAnalysisResult = analysisResult.DropExceptSyntax(); - // return new result - return result.SetItem(compilerAnalyzer, newCompilerAnalysisResult); - } + // return new result + return result.SetItem(compilerAnalyzer, newCompilerAnalysisResult); + } - /// - /// Calculate all diagnostics for a given project using analyzers referenced by the project and specified IDE analyzers. - /// - private async Task> ComputeDiagnosticsAsync( - CompilationWithAnalyzersPair? compilationWithAnalyzers, Project project, ImmutableArray ideAnalyzers, CancellationToken cancellationToken) - { - try + // + // Calculate all diagnostics for a given project using analyzers referenced by the project and specified IDE analyzers. + // + async Task> ComputeDiagnosticsForAnalyzersAsync( + ImmutableArray ideAnalyzers) { - var result = ImmutableDictionary.Empty; - - // can be null if given project doesn't support compilation. - if (compilationWithAnalyzers?.ProjectAnalyzers.Length > 0 - || compilationWithAnalyzers?.HostAnalyzers.Length > 0) + try { - // calculate regular diagnostic analyzers diagnostics - var resultMap = await _diagnosticAnalyzerRunner.AnalyzeProjectAsync( - project, compilationWithAnalyzers, logPerformanceInfo: false, getTelemetryInfo: true, cancellationToken).ConfigureAwait(false); - - result = resultMap.AnalysisResult; + var result = ImmutableDictionary.Empty; - // record telemetry data - UpdateAnalyzerTelemetryData(resultMap.TelemetryInfo); - } + // can be null if given project doesn't support compilation. + if (compilationWithAnalyzers?.ProjectAnalyzers.Length > 0 + || compilationWithAnalyzers?.HostAnalyzers.Length > 0) + { + // calculate regular diagnostic analyzers diagnostics + var resultMap = await _diagnosticAnalyzerRunner.AnalyzeProjectAsync( + project, compilationWithAnalyzers, logPerformanceInfo: false, getTelemetryInfo: true, cancellationToken).ConfigureAwait(false); - // check whether there is IDE specific project diagnostic analyzer - Debug.Assert(ideAnalyzers.All(a => a is ProjectDiagnosticAnalyzer or DocumentDiagnosticAnalyzer)); - return await MergeProjectDiagnosticAnalyzerDiagnosticsAsync(project, ideAnalyzers, compilationWithAnalyzers?.HostCompilation, result, cancellationToken).ConfigureAwait(false); - } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) - { - throw ExceptionUtilities.Unreachable(); - } - } + result = resultMap.AnalysisResult; - private async Task> ComputeDiagnosticsAsync( - CompilationWithAnalyzersPair? compilationWithAnalyzers, Project project, ImmutableArray stateSets, - ImmutableDictionary existing, CancellationToken cancellationToken) - { - try - { - // PERF: check whether we can reduce number of analyzers we need to run. - // this can happen since caller could have created the driver with different set of analyzers that are different - // than what we used to create the cache. - var version = await GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false); - - var ideAnalyzers = stateSets.Select(s => s.Analyzer).Where(a => a is ProjectDiagnosticAnalyzer or DocumentDiagnosticAnalyzer).ToImmutableArrayOrEmpty(); + // record telemetry data + UpdateAnalyzerTelemetryData(resultMap.TelemetryInfo); + } - if (compilationWithAnalyzers != null && TryReduceAnalyzersToRun(compilationWithAnalyzers, version, existing, out var projectAnalyzersToRun, out var hostAnalyzersToRun)) + // check whether there is IDE specific project diagnostic analyzer + Debug.Assert(ideAnalyzers.All(a => a is ProjectDiagnosticAnalyzer or DocumentDiagnosticAnalyzer)); + return await MergeProjectDiagnosticAnalyzerDiagnosticsAsync(ideAnalyzers, result).ConfigureAwait(false); + } + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { - // it looks like we can reduce the set. create new CompilationWithAnalyzer. - // if we reduced to 0, we just pass in null for analyzer drvier. it could be reduced to 0 - // since we might have up to date results for analyzers from compiler but not for - // workspace analyzers. - - var compilationWithReducedAnalyzers = (projectAnalyzersToRun.Length == 0 && hostAnalyzersToRun.Length == 0) ? null : - await DocumentAnalysisExecutor.CreateCompilationWithAnalyzersAsync( - project, - projectAnalyzersToRun, - hostAnalyzersToRun, - AnalyzerService.CrashOnAnalyzerException, - cancellationToken).ConfigureAwait(false); - - var result = await ComputeDiagnosticsAsync(compilationWithReducedAnalyzers, project, ideAnalyzers, cancellationToken).ConfigureAwait(false); - return MergeExistingDiagnostics(version, existing, result); + throw ExceptionUtilities.Unreachable(); } - - // we couldn't reduce the set. - return await ComputeDiagnosticsAsync(compilationWithAnalyzers, project, ideAnalyzers, cancellationToken).ConfigureAwait(false); - } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) - { - throw ExceptionUtilities.Unreachable(); } - } - private static ImmutableDictionary MergeExistingDiagnostics( - VersionStamp version, ImmutableDictionary existing, ImmutableDictionary result) - { - // quick bail out. - if (existing.IsEmpty) + async Task> ComputeDiagnosticsForIDEAnalyzersAsync( + ImmutableArray analyzers) { - return result; - } + try + { + var ideAnalyzers = analyzers.WhereAsArray(a => a is ProjectDiagnosticAnalyzer or DocumentDiagnosticAnalyzer); - foreach (var (analyzer, results) in existing) - { - if (results.Version != version) + return await ComputeDiagnosticsForAnalyzersAsync(ideAnalyzers).ConfigureAwait(false); + } + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { - continue; + throw ExceptionUtilities.Unreachable(); } - - result = result.SetItem(analyzer, results); } - return result; - } - - private static bool TryReduceAnalyzersToRun( - CompilationWithAnalyzersPair compilationWithAnalyzers, VersionStamp version, - ImmutableDictionary existing, - out ImmutableArray projectAnalyzers, - out ImmutableArray hostAnalyzers) - { - projectAnalyzers = compilationWithAnalyzers.ProjectAnalyzers.WhereAsArray( - static (analyzer, arg) => + async Task> MergeProjectDiagnosticAnalyzerDiagnosticsAsync( + ImmutableArray ideAnalyzers, + ImmutableDictionary result) + { + try { - if (arg.existing.TryGetValue(analyzer, out var analysisResult) && - analysisResult.Version == arg.version) - { - // we already have up to date result. - return false; - } + var compilation = compilationWithAnalyzers?.HostCompilation; - // analyzer that is out of date. - // open file only analyzer is always out of date for project wide data - return true; - }, - (existing, version)); + (result, var failedDocuments) = await UpdateWithDocumentLoadAndGeneratorFailuresAsync(result).ConfigureAwait(false); - hostAnalyzers = compilationWithAnalyzers.HostAnalyzers.WhereAsArray( - static (analyzer, arg) => - { - if (arg.existing.TryGetValue(analyzer, out var analysisResult) && - analysisResult.Version == arg.version) + foreach (var analyzer in ideAnalyzers) { - // we already have up to date result. - return false; - } - - // analyzer that is out of date. - // open file only analyzer is always out of date for project wide data - return true; - }, - (existing, version)); - - if (projectAnalyzers.Length == compilationWithAnalyzers.ProjectAnalyzers.Length - && hostAnalyzers.Length == compilationWithAnalyzers.HostAnalyzers.Length) - { - // all of analyzers are out of date. - projectAnalyzers = default; - hostAnalyzers = default; - return false; - } + var builder = new DiagnosticAnalysisResultBuilder(project); - return true; - } - - private async Task> MergeProjectDiagnosticAnalyzerDiagnosticsAsync( - Project project, - ImmutableArray ideAnalyzers, - Compilation? compilation, - ImmutableDictionary result, - CancellationToken cancellationToken) - { - try - { - var version = await GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false); - - (result, var failedDocuments) = await UpdateWithDocumentLoadAndGeneratorFailuresAsync(result, project, version, cancellationToken).ConfigureAwait(false); - - foreach (var analyzer in ideAnalyzers) - { - var builder = new DiagnosticAnalysisResultBuilder(project, version); - - switch (analyzer) - { - case DocumentDiagnosticAnalyzer documentAnalyzer: - foreach (var document in project.Documents) - { - // don't analyze documents whose content failed to load - if (failedDocuments == null || !failedDocuments.Contains(document)) + switch (analyzer) + { + case DocumentDiagnosticAnalyzer documentAnalyzer: + foreach (var document in project.Documents) { - var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); - if (tree != null) - { - builder.AddSyntaxDiagnostics(tree, await DocumentAnalysisExecutor.ComputeDocumentDiagnosticAnalyzerDiagnosticsAsync(documentAnalyzer, document, AnalysisKind.Syntax, compilation, cancellationToken).ConfigureAwait(false)); - builder.AddSemanticDiagnostics(tree, await DocumentAnalysisExecutor.ComputeDocumentDiagnosticAnalyzerDiagnosticsAsync(documentAnalyzer, document, AnalysisKind.Semantic, compilation, cancellationToken).ConfigureAwait(false)); - } - else + // don't analyze documents whose content failed to load + if (failedDocuments == null || !failedDocuments.Contains(document)) { - builder.AddExternalSyntaxDiagnostics(document.Id, await DocumentAnalysisExecutor.ComputeDocumentDiagnosticAnalyzerDiagnosticsAsync(documentAnalyzer, document, AnalysisKind.Syntax, compilation, cancellationToken).ConfigureAwait(false)); - builder.AddExternalSemanticDiagnostics(document.Id, await DocumentAnalysisExecutor.ComputeDocumentDiagnosticAnalyzerDiagnosticsAsync(documentAnalyzer, document, AnalysisKind.Semantic, compilation, cancellationToken).ConfigureAwait(false)); + var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); + if (tree != null) + { + builder.AddSyntaxDiagnostics(tree, await DocumentAnalysisExecutor.ComputeDocumentDiagnosticAnalyzerDiagnosticsAsync(documentAnalyzer, document, AnalysisKind.Syntax, compilation, cancellationToken).ConfigureAwait(false)); + builder.AddSemanticDiagnostics(tree, await DocumentAnalysisExecutor.ComputeDocumentDiagnosticAnalyzerDiagnosticsAsync(documentAnalyzer, document, AnalysisKind.Semantic, compilation, cancellationToken).ConfigureAwait(false)); + } + else + { + builder.AddExternalSyntaxDiagnostics(document.Id, await DocumentAnalysisExecutor.ComputeDocumentDiagnosticAnalyzerDiagnosticsAsync(documentAnalyzer, document, AnalysisKind.Syntax, compilation, cancellationToken).ConfigureAwait(false)); + builder.AddExternalSemanticDiagnostics(document.Id, await DocumentAnalysisExecutor.ComputeDocumentDiagnosticAnalyzerDiagnosticsAsync(documentAnalyzer, document, AnalysisKind.Semantic, compilation, cancellationToken).ConfigureAwait(false)); + } } } - } - break; + break; - case ProjectDiagnosticAnalyzer projectAnalyzer: - builder.AddCompilationDiagnostics(await DocumentAnalysisExecutor.ComputeProjectDiagnosticAnalyzerDiagnosticsAsync(projectAnalyzer, project, compilation, cancellationToken).ConfigureAwait(false)); - break; + case ProjectDiagnosticAnalyzer projectAnalyzer: + builder.AddCompilationDiagnostics(await DocumentAnalysisExecutor.ComputeProjectDiagnosticAnalyzerDiagnosticsAsync(projectAnalyzer, project, compilation, cancellationToken).ConfigureAwait(false)); + break; + } + + // merge the result to existing one. + // there can be existing one from compiler driver with empty set. overwrite it with + // ide one. + result = result.SetItem(analyzer, DiagnosticAnalysisResult.CreateFromBuilder(builder)); } - // merge the result to existing one. - // there can be existing one from compiler driver with empty set. overwrite it with - // ide one. - result = result.SetItem(analyzer, DiagnosticAnalysisResult.CreateFromBuilder(builder)); + return result; + } + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) + { + throw ExceptionUtilities.Unreachable(); } - - return result; - } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) - { - throw ExceptionUtilities.Unreachable(); } - } - - private async Task<(ImmutableDictionary results, ImmutableHashSet? failedDocuments)> UpdateWithDocumentLoadAndGeneratorFailuresAsync( - ImmutableDictionary results, - Project project, - VersionStamp version, - CancellationToken cancellationToken) - { - ImmutableHashSet.Builder? failedDocuments = null; - ImmutableDictionary>.Builder? lazyLoadDiagnostics = null; - foreach (var document in project.Documents) + async Task<(ImmutableDictionary results, ImmutableHashSet? failedDocuments)> UpdateWithDocumentLoadAndGeneratorFailuresAsync( + ImmutableDictionary results) { - var loadDiagnostic = await document.State.GetLoadDiagnosticAsync(cancellationToken).ConfigureAwait(false); - if (loadDiagnostic != null) + ImmutableHashSet.Builder? failedDocuments = null; + ImmutableDictionary>.Builder? lazyLoadDiagnostics = null; + + foreach (var document in project.Documents) { - lazyLoadDiagnostics ??= ImmutableDictionary.CreateBuilder>(); - lazyLoadDiagnostics.Add(document.Id, [DiagnosticData.Create(loadDiagnostic, document)]); + var loadDiagnostic = await document.State.GetLoadDiagnosticAsync(cancellationToken).ConfigureAwait(false); + if (loadDiagnostic != null) + { + lazyLoadDiagnostics ??= ImmutableDictionary.CreateBuilder>(); + lazyLoadDiagnostics.Add(document.Id, [DiagnosticData.Create(loadDiagnostic, document)]); - failedDocuments ??= ImmutableHashSet.CreateBuilder(); - failedDocuments.Add(document); + failedDocuments ??= ImmutableHashSet.CreateBuilder(); + failedDocuments.Add(document); + } } - } - results = results.SetItem( - FileContentLoadAnalyzer.Instance, - DiagnosticAnalysisResult.Create( - project, - version, - syntaxLocalMap: lazyLoadDiagnostics?.ToImmutable() ?? ImmutableDictionary>.Empty, - semanticLocalMap: ImmutableDictionary>.Empty, - nonLocalMap: ImmutableDictionary>.Empty, - others: [], - documentIds: null)); - - var generatorDiagnostics = await _diagnosticAnalyzerRunner.GetSourceGeneratorDiagnosticsAsync(project, cancellationToken).ConfigureAwait(false); - var diagnosticResultBuilder = new DiagnosticAnalysisResultBuilder(project, version); - foreach (var generatorDiagnostic in generatorDiagnostics) - { - // We'll always treat generator diagnostics that are associated with a tree as a local diagnostic, because - // we want that to be refreshed and deduplicated with regular document analysis. - diagnosticResultBuilder.AddDiagnosticTreatedAsLocalSemantic(generatorDiagnostic); - } + results = results.SetItem( + FileContentLoadAnalyzer.Instance, + DiagnosticAnalysisResult.Create( + project, + syntaxLocalMap: lazyLoadDiagnostics?.ToImmutable() ?? ImmutableDictionary>.Empty, + semanticLocalMap: ImmutableDictionary>.Empty, + nonLocalMap: ImmutableDictionary>.Empty, + others: [], + documentIds: null)); + + var generatorDiagnostics = await _diagnosticAnalyzerRunner.GetSourceGeneratorDiagnosticsAsync(project, cancellationToken).ConfigureAwait(false); + var diagnosticResultBuilder = new DiagnosticAnalysisResultBuilder(project); + foreach (var generatorDiagnostic in generatorDiagnostics) + { + // We'll always treat generator diagnostics that are associated with a tree as a local diagnostic, because + // we want that to be refreshed and deduplicated with regular document analysis. + diagnosticResultBuilder.AddDiagnosticTreatedAsLocalSemantic(generatorDiagnostic); + } - results = results.SetItem( - GeneratorDiagnosticsPlaceholderAnalyzer.Instance, - DiagnosticAnalysisResult.CreateFromBuilder(diagnosticResultBuilder)); + results = results.SetItem( + GeneratorDiagnosticsPlaceholderAnalyzer.Instance, + DiagnosticAnalysisResult.CreateFromBuilder(diagnosticResultBuilder)); - return (results, failedDocuments?.ToImmutable()); - } + return (results, failedDocuments?.ToImmutable()); + } - private void UpdateAnalyzerTelemetryData(ImmutableDictionary telemetry) - { - foreach (var (analyzer, telemetryInfo) in telemetry) + void UpdateAnalyzerTelemetryData(ImmutableDictionary telemetry) { - var isTelemetryCollectionAllowed = DiagnosticAnalyzerInfoCache.IsTelemetryCollectionAllowed(analyzer); - _telemetry.UpdateAnalyzerActionsTelemetry(analyzer, telemetryInfo, isTelemetryCollectionAllowed); + foreach (var (analyzer, telemetryInfo) in telemetry) + { + var isTelemetryCollectionAllowed = DiagnosticAnalyzerInfoCache.IsTelemetryCollectionAllowed(analyzer); + _telemetry.UpdateAnalyzerActionsTelemetry(analyzer, telemetryInfo, isTelemetryCollectionAllowed); + } } } } diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.HostAnalyzerInfo.cs b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.HostAnalyzerInfo.cs new file mode 100644 index 0000000000000..9a917b7ff7ef5 --- /dev/null +++ b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.HostAnalyzerInfo.cs @@ -0,0 +1,156 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Diagnostics; + +internal partial class DiagnosticAnalyzerService +{ + private partial class DiagnosticIncrementalAnalyzer + { + private partial class StateManager + { + private HostAnalyzerInfo GetOrCreateHostAnalyzerInfo( + SolutionState solution, ProjectState project, ProjectAnalyzerInfo projectAnalyzerInfo) + { + var key = new HostAnalyzerInfoKey(project.Language, project.HasSdkCodeStyleAnalyzers, solution.Analyzers.HostAnalyzerReferences); + // Some Host Analyzers may need to be treated as Project Analyzers so that they do not have access to the + // Host fallback options. These ids will be used when building up the Host and Project analyzer collections. + var referenceIdsToRedirect = GetReferenceIdsToRedirectAsProjectAnalyzers(solution, project); + var hostAnalyzerInfo = ImmutableInterlocked.GetOrAdd(ref _hostAnalyzerStateMap, key, CreateLanguageSpecificAnalyzerMap, (solution.Analyzers, referenceIdsToRedirect)); + return hostAnalyzerInfo.WithExcludedAnalyzers(projectAnalyzerInfo.SkippedAnalyzersInfo.SkippedAnalyzers); + + static HostAnalyzerInfo CreateLanguageSpecificAnalyzerMap(HostAnalyzerInfoKey arg, (HostDiagnosticAnalyzers HostAnalyzers, ImmutableHashSet ReferenceIdsToRedirect) state) + { + var language = arg.Language; + var analyzersPerReference = state.HostAnalyzers.GetOrCreateHostDiagnosticAnalyzersPerReference(language); + + var (hostAnalyzerCollection, projectAnalyzerCollection) = GetAnalyzerCollections(analyzersPerReference, state.ReferenceIdsToRedirect); + var (hostAnalyzers, allAnalyzers) = PartitionAnalyzers(projectAnalyzerCollection, hostAnalyzerCollection, includeWorkspacePlaceholderAnalyzers: true); + + return new HostAnalyzerInfo(hostAnalyzers, allAnalyzers); + } + + static (IEnumerable> HostAnalyzerCollection, IEnumerable> ProjectAnalyzerCollection) GetAnalyzerCollections( + ImmutableDictionary> analyzersPerReference, + ImmutableHashSet referenceIdsToRedirectAsProjectAnalyzers) + { + if (referenceIdsToRedirectAsProjectAnalyzers.IsEmpty) + { + return (analyzersPerReference.Values, []); + } + + var hostAnalyzerCollection = ArrayBuilder>.GetInstance(); + var projectAnalyzerCollection = ArrayBuilder>.GetInstance(); + + foreach (var (referenceId, analyzers) in analyzersPerReference) + { + if (referenceIdsToRedirectAsProjectAnalyzers.Contains(referenceId)) + { + projectAnalyzerCollection.Add(analyzers); + } + else + { + hostAnalyzerCollection.Add(analyzers); + } + } + + return (hostAnalyzerCollection.ToImmutableAndFree(), projectAnalyzerCollection.ToImmutableAndFree()); + } + } + + private static ImmutableHashSet GetReferenceIdsToRedirectAsProjectAnalyzers( + SolutionState solution, ProjectState project) + { + if (project.HasSdkCodeStyleAnalyzers) + { + // When a project uses CodeStyle analyzers added by the SDK, we remove them in favor of the + // Features analyzers. We need to then treat the Features analyzers as Project analyzers so + // they do not get access to the Host fallback options. + return GetFeaturesAnalyzerReferenceIds(solution.Analyzers); + } + + return []; + + static ImmutableHashSet GetFeaturesAnalyzerReferenceIds(HostDiagnosticAnalyzers hostAnalyzers) + { + var builder = ImmutableHashSet.CreateBuilder(); + + foreach (var analyzerReference in hostAnalyzers.HostAnalyzerReferences) + { + if (analyzerReference.IsFeaturesAnalyzer()) + builder.Add(analyzerReference.Id); + } + + return builder.ToImmutable(); + } + } + } + } + + private sealed class HostAnalyzerInfo + { + private const int FileContentLoadAnalyzerPriority = -4; + private const int GeneratorDiagnosticsPlaceholderAnalyzerPriority = -3; + private const int BuiltInCompilerPriority = -2; + private const int RegularDiagnosticAnalyzerPriority = -1; + + private readonly ImmutableHashSet _hostAnalyzers; + private readonly ImmutableHashSet _allAnalyzers; + public readonly ImmutableArray OrderedAllAnalyzers; + + public HostAnalyzerInfo( + ImmutableHashSet hostAnalyzers, + ImmutableHashSet allAnalyzers) + { + _hostAnalyzers = hostAnalyzers; + _allAnalyzers = allAnalyzers; + + // order analyzers. + // order will be in this order + // BuiltIn Compiler Analyzer (C#/VB) < Regular DiagnosticAnalyzers < Document/ProjectDiagnosticAnalyzers + OrderedAllAnalyzers = [.. _allAnalyzers.OrderBy(PriorityComparison)]; + } + + public bool IsHostAnalyzer(DiagnosticAnalyzer analyzer) + => _hostAnalyzers.Contains(analyzer); + + public HostAnalyzerInfo WithExcludedAnalyzers(ImmutableHashSet excludedAnalyzers) + { + if (excludedAnalyzers.IsEmpty) + { + return this; + } + + return new(_hostAnalyzers, _allAnalyzers.Except(excludedAnalyzers)); + } + + private int PriorityComparison(DiagnosticAnalyzer state1, DiagnosticAnalyzer state2) + => GetPriority(state1) - GetPriority(state2); + + private static int GetPriority(DiagnosticAnalyzer state) + { + // compiler gets highest priority + if (state.IsCompilerAnalyzer()) + { + return BuiltInCompilerPriority; + } + + return state switch + { + FileContentLoadAnalyzer _ => FileContentLoadAnalyzerPriority, + GeneratorDiagnosticsPlaceholderAnalyzer _ => GeneratorDiagnosticsPlaceholderAnalyzerPriority, + DocumentDiagnosticAnalyzer analyzer => Math.Max(0, analyzer.Priority), + ProjectDiagnosticAnalyzer analyzer => Math.Max(0, analyzer.Priority), + _ => RegularDiagnosticAnalyzerPriority, + }; + } + } +} diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.InMemoryStorage.cs b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.InMemoryStorage.cs deleted file mode 100644 index ca96681acd08d..0000000000000 --- a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.InMemoryStorage.cs +++ /dev/null @@ -1,78 +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.Concurrent; -using System.Collections.Immutable; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Diagnostics.EngineV2 -{ - internal partial class DiagnosticIncrementalAnalyzer - { - private static class InMemoryStorage - { - // the reason using nested map rather than having tuple as key is so that I dont have a gigantic map - private static readonly ConcurrentDictionary> s_map = - new(concurrencyLevel: 2, capacity: 10); - - public static bool TryGetValue(DiagnosticAnalyzer analyzer, (object key, string stateKey) key, out CacheEntry entry) - { - AssertKey(key); - - entry = default; - return s_map.TryGetValue(analyzer, out var analyzerMap) && - analyzerMap.TryGetValue(key, out entry); - } - - public static void Cache(DiagnosticAnalyzer analyzer, (object key, string stateKey) key, CacheEntry entry) - { - AssertKey(key); - - // add new cache entry - var analyzerMap = s_map.GetOrAdd(analyzer, _ => new ConcurrentDictionary<(object key, string stateKey), CacheEntry>(concurrencyLevel: 2, capacity: 10)); - analyzerMap[key] = entry; - } - - public static void Remove(DiagnosticAnalyzer analyzer, (object key, string stateKey) key) - { - AssertKey(key); - // remove the entry - if (!s_map.TryGetValue(analyzer, out var analyzerMap)) - { - return; - } - - analyzerMap.TryRemove(key, out _); - - if (analyzerMap.IsEmpty) - { - s_map.TryRemove(analyzer, out _); - } - } - - public static void DropCache(DiagnosticAnalyzer analyzer) - { - // drop any cache related to given analyzer - s_map.TryRemove(analyzer, out _); - } - - // make sure key is either documentId or projectId - private static void AssertKey((object key, string stateKey) key) - => Contract.ThrowIfFalse(key.key is DocumentId or ProjectId); - } - - // in memory cache entry - private readonly struct CacheEntry - { - public readonly VersionStamp Version; - public readonly ImmutableArray Diagnostics; - - public CacheEntry(VersionStamp version, ImmutableArray diagnostics) - { - Version = version; - Diagnostics = diagnostics; - } - } - } -} diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.IncrementalMemberEditAnalyzer.cs b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.IncrementalMemberEditAnalyzer.cs index de59475e77e05..dd609587e37cc 100644 --- a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.IncrementalMemberEditAnalyzer.cs +++ b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.IncrementalMemberEditAnalyzer.cs @@ -16,9 +16,11 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Diagnostics.EngineV2 +namespace Microsoft.CodeAnalysis.Diagnostics; + +internal partial class DiagnosticAnalyzerService { - internal partial class DiagnosticIncrementalAnalyzer + private partial class DiagnosticIncrementalAnalyzer { /// /// This type performs incremental analysis in presence of edits to only a single member inside a document. @@ -45,10 +47,8 @@ public void UpdateDocumentWithCachedDiagnostics(Document document) public async Task>> ComputeDiagnosticsAsync( DocumentAnalysisExecutor executor, - ImmutableArray analyzersWithState, + ImmutableArray analyzers, VersionStamp version, - Func>> computeAnalyzerDiagnosticsAsync, - Func>>> computeDiagnosticsNonIncrementallyAsync, CancellationToken cancellationToken) { var analysisScope = executor.AnalysisScope; @@ -57,7 +57,7 @@ public async Task stateSet.Analyzer.SupportsSpanBasedSemanticDiagnosticAnalysis())); + Debug.Assert(analyzers.All(analyzer => analyzer.SupportsSpanBasedSemanticDiagnosticAnalysis())); var document = (Document)analysisScope.TextDocument; var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); @@ -66,7 +66,7 @@ public async Task.GetInstance(out var spanBasedAnalyzers); - using var _2 = ArrayBuilder.GetInstance(out var documentBasedAnalyzers); - (AnalyzerWithState analyzerWithState, bool spanBased)? compilerAnalyzerData = null; - foreach (var analyzerWithState in analyzersWithState) + using var _1 = ArrayBuilder.GetInstance(out var spanBasedAnalyzers); + using var _2 = ArrayBuilder.GetInstance(out var documentBasedAnalyzers); + (DiagnosticAnalyzer analyzer, bool spanBased)? compilerAnalyzerData = null; + foreach (var analyzer in analyzers) { // Check if we have existing cached diagnostics for this analyzer whose version matches the // old document version. If so, we can perform span based incremental analysis for the changed member. // Otherwise, we have to perform entire document analysis. - var state = analyzerWithState.State; - var existingData = analyzerWithState.ExistingData; - if (oldDocumentVersion == existingData.Version) + if (oldDocumentVersion == VersionStamp.Default) { - if (!compilerAnalyzerData.HasValue && analyzerWithState.Analyzer.IsCompilerAnalyzer()) - compilerAnalyzerData = (analyzerWithState, spanBased: true); + if (!compilerAnalyzerData.HasValue && analyzer.IsCompilerAnalyzer()) + compilerAnalyzerData = (analyzer, spanBased: true); else - spanBasedAnalyzers.Add(analyzerWithState); + spanBasedAnalyzers.Add(analyzer); } else { - var analyzerWithStateAndEmptyData = new AnalyzerWithState(analyzerWithState.Analyzer, analyzerWithState.IsHostAnalyzer, analyzerWithState.State, DocumentAnalysisData.Empty); - if (!compilerAnalyzerData.HasValue && analyzerWithState.Analyzer.IsCompilerAnalyzer()) - compilerAnalyzerData = (analyzerWithStateAndEmptyData, spanBased: false); + if (!compilerAnalyzerData.HasValue && analyzer.IsCompilerAnalyzer()) + compilerAnalyzerData = (analyzer, spanBased: false); else - documentBasedAnalyzers.Add(analyzerWithStateAndEmptyData); + documentBasedAnalyzers.Add(analyzer); } } if (spanBasedAnalyzers.Count == 0 && (!compilerAnalyzerData.HasValue || !compilerAnalyzerData.Value.spanBased)) { // No incremental span based-analysis to be performed. - return await computeDiagnosticsNonIncrementallyAsync(executor, cancellationToken).ConfigureAwait(false); + return await ComputeDocumentDiagnosticsCoreAsync(executor, cancellationToken).ConfigureAwait(false); } // Get or create the member spans for all member nodes in the old document. @@ -127,73 +124,59 @@ public async Task oldMemberSpans, - PooledDictionary> builder) + Dictionary> builder) { if (!compilerAnalyzerData.HasValue) return; - var (analyzerWithState, spanBased) = compilerAnalyzerData.Value; + var (analyzer, spanBased) = compilerAnalyzerData.Value; var span = spanBased ? changedMember.FullSpan : (TextSpan?)null; executor = executor.With(analysisScope.WithSpan(span)); - using var _ = ArrayBuilder.GetInstance(1, analyzerWithState, out var analyzersWithState); - await ExecuteAnalyzersAsync(executor, analyzersWithState, oldMemberSpans, builder).ConfigureAwait(false); + using var _ = ArrayBuilder.GetInstance(1, analyzer, out var analyzers); + await ExecuteAnalyzersAsync(executor, analyzers, oldMemberSpans, builder).ConfigureAwait(false); } async Task ExecuteSpanBasedAnalyzersAsync( - ArrayBuilder analyzersWithState, + ArrayBuilder analyzers, ImmutableArray oldMemberSpans, - PooledDictionary> builder) + Dictionary> builder) { - if (analyzersWithState.Count == 0) + if (analyzers.Count == 0) return; executor = executor.With(analysisScope.WithSpan(changedMember.FullSpan)); - await ExecuteAnalyzersAsync(executor, analyzersWithState, oldMemberSpans, builder).ConfigureAwait(false); + await ExecuteAnalyzersAsync(executor, analyzers, oldMemberSpans, builder).ConfigureAwait(false); } async Task ExecuteDocumentBasedAnalyzersAsync( - ArrayBuilder analyzersWithState, + ArrayBuilder analyzers, ImmutableArray oldMemberSpans, - PooledDictionary> builder) + Dictionary> builder) { - if (analyzersWithState.Count == 0) + if (analyzers.Count == 0) return; executor = executor.With(analysisScope.WithSpan(null)); - await ExecuteAnalyzersAsync(executor, analyzersWithState, oldMemberSpans, builder).ConfigureAwait(false); + await ExecuteAnalyzersAsync(executor, analyzers, oldMemberSpans, builder).ConfigureAwait(false); } async Task ExecuteAnalyzersAsync( DocumentAnalysisExecutor executor, - ArrayBuilder analyzersWithState, + ArrayBuilder analyzers, ImmutableArray oldMemberSpans, - PooledDictionary> builder) + Dictionary> builder) { var analysisScope = executor.AnalysisScope; Debug.Assert(changedMember != null); Debug.Assert(analysisScope.Kind == AnalysisKind.Semantic); - foreach (var analyzerWithState in analyzersWithState) + foreach (var analyzer in analyzers) { - var diagnostics = await computeAnalyzerDiagnosticsAsync(analyzerWithState.Analyzer, executor, cancellationToken).ConfigureAwait(false); - - // If we computed the diagnostics just for a span, then we are performing incremental analysis. - // We need to compute the full document diagnostics by re-using diagnostics outside the changed - // member and using the above computed latest diagnostics for the edited member span. - if (analysisScope.Span.HasValue) - { - Debug.Assert(analysisScope.Span.Value == changedMember.FullSpan); - - diagnostics = await GetUpdatedDiagnosticsForMemberEditAsync( - diagnostics, analyzerWithState.ExistingData, analyzerWithState.Analyzer, - executor, changedMember, changedMemberId, - oldMemberSpans, computeAnalyzerDiagnosticsAsync, cancellationToken).ConfigureAwait(false); - } - - builder.Add(analyzerWithState.Analyzer, diagnostics); + var diagnostics = await ComputeDocumentDiagnosticsForAnalyzerCoreAsync(analyzer, executor, cancellationToken).ConfigureAwait(false); + builder.Add(analyzer, diagnostics); } } } @@ -217,8 +200,10 @@ async Task ExecuteAnalyzersAsync( } var syntaxFacts = document.GetRequiredLanguageService(); - using var pooledMembers = syntaxFacts.GetMethodLevelMembers(root); - var members = pooledMembers.Object; + + // Specifies false for discardLargeInstances as these objects commonly exceed the default ArrayBuilder capacity threshold. + using var _ = ArrayBuilder.GetInstance(discardLargeInstances: false, out var members); + syntaxFacts.AddMethodLevelMembers(root, members); var memberSpans = members.SelectAsArray(member => member.FullSpan); var changedMemberId = members.IndexOf(changedMember); @@ -232,169 +217,6 @@ async Task ExecuteAnalyzersAsync( return (changedMember, changedMemberId, memberSpans, lastDocument); } - - private static async Task> GetUpdatedDiagnosticsForMemberEditAsync( - ImmutableArray diagnostics, - DocumentAnalysisData existingData, - DiagnosticAnalyzer analyzer, - DocumentAnalysisExecutor executor, - SyntaxNode changedMember, - int changedMemberId, - ImmutableArray oldMemberSpans, - Func>> computeAnalyzerDiagnosticsAsync, - CancellationToken cancellationToken) - { - // We are performing semantic span-based analysis for member-only edit scenario. - // Instead of computing the analyzer diagnostics for the entire document, - // we have computed the new diagnostics just for the edited member span. - Debug.Assert(executor.AnalysisScope.Span.HasValue); - Debug.Assert(executor.AnalysisScope.Span.Value == changedMember.FullSpan); - - // We now try to get the new document diagnostics by performing an incremental update: - // 1. Re-using all the old cached diagnostics outside the edited member node from a prior - // document snapshot, but with updated diagnostic spans. - // AND - // 2. Replacing old diagnostics for the edited member node in a prior document snapshot - // with the new diagnostics for this member node in the latest document snaphot. - // If we are unable to perform this incremental diagnostics update, - // we fallback to computing the diagnostics for the entire document. - var tree = changedMember.SyntaxTree; - var text = tree.GetText(cancellationToken); - if (TryGetUpdatedDocumentDiagnostics(existingData, oldMemberSpans, diagnostics, tree, text, changedMember, changedMemberId, out var updatedDiagnostics)) - { -#if DEBUG_INCREMENTAL_ANALYSIS - await ValidateMemberDiagnosticsAsync(executor, analyzer, updatedDiagnostics, cancellationToken).ConfigureAwait(false); -#endif - return updatedDiagnostics; - } - else - { - // Incremental diagnostics update failed. - // Fallback to computing the diagnostics for the entire document. - var documentExecutor = executor.With(executor.AnalysisScope.WithSpan(null)); - return await computeAnalyzerDiagnosticsAsync(analyzer, documentExecutor, cancellationToken).ConfigureAwait(false); - } - -#if DEBUG_INCREMENTAL_ANALYSIS - static async Task ValidateMemberDiagnosticsAsync(DocumentAnalysisExecutor executor, DiagnosticAnalyzer analyzer, ImmutableArray diagnostics, CancellationToken cancellationToken) - { - executor = executor.With(executor.AnalysisScope.WithSpan(null)); - var expected = await executor.ComputeDiagnosticsAsync(analyzer, cancellationToken).ConfigureAwait(false); - Debug.Assert(diagnostics.SetEquals(expected)); - } -#endif - } - - private static bool TryGetUpdatedDocumentDiagnostics( - DocumentAnalysisData existingData, - ImmutableArray oldMemberSpans, - ImmutableArray memberDiagnostics, - SyntaxTree tree, - SourceText text, - SyntaxNode member, - int memberId, - out ImmutableArray updatedDiagnostics) - { - // get old span - var oldSpan = oldMemberSpans[memberId]; - - // get old diagnostics - var diagnostics = existingData.Items; - - // check quick exit cases - if (diagnostics.Length == 0 && memberDiagnostics.Length == 0) - { - updatedDiagnostics = diagnostics; - return true; - } - - // simple case - if (diagnostics.Length == 0 && memberDiagnostics.Length > 0) - { - updatedDiagnostics = memberDiagnostics; - return true; - } - - // regular case - using var _ = ArrayBuilder.GetInstance(out var resultBuilder); - - // update member location - Contract.ThrowIfFalse(member.FullSpan.Start == oldSpan.Start); - var delta = member.FullSpan.End - oldSpan.End; - - var replaced = false; - foreach (var diagnostic in diagnostics) - { - if (diagnostic.DocumentId is null) - { - resultBuilder.Add(diagnostic); - continue; - } - - var diagnosticSpan = diagnostic.DataLocation.UnmappedFileSpan.GetClampedTextSpan(text); - if (diagnosticSpan.Start < oldSpan.Start) - { - // Bail out if the diagnostic has any additional locations that we don't know how to handle. - if (diagnostic.AdditionalLocations.Any(l => l.DocumentId != null && l.UnmappedFileSpan.GetClampedTextSpan(text).Start >= oldSpan.Start)) - { - updatedDiagnostics = default; - return false; - } - - resultBuilder.Add(diagnostic); - continue; - } - - if (!replaced) - { - resultBuilder.AddRange(memberDiagnostics); - replaced = true; - } - - if (oldSpan.End <= diagnosticSpan.Start) - { - // Bail out if the diagnostic has any additional locations that we don't know how to handle. - if (diagnostic.AdditionalLocations.Any(l => l.DocumentId != null && oldSpan.End > l.UnmappedFileSpan.GetClampedTextSpan(text).Start)) - { - updatedDiagnostics = default; - return false; - } - - resultBuilder.Add(UpdateLocations(diagnostic, tree, text, delta)); - continue; - } - } - - // if it haven't replaced, replace it now - if (!replaced) - { - resultBuilder.AddRange(memberDiagnostics); - } - - updatedDiagnostics = resultBuilder.ToImmutableArray(); - return true; - - static DiagnosticData UpdateLocations(DiagnosticData diagnostic, SyntaxTree tree, SourceText text, int delta) - { - Debug.Assert(diagnostic.DataLocation != null); - var location = UpdateLocation(diagnostic.DataLocation); - var additionalLocations = diagnostic.AdditionalLocations.SelectAsArray(UpdateLocation); - return diagnostic.WithLocations(location, additionalLocations); - - DiagnosticDataLocation UpdateLocation(DiagnosticDataLocation location) - { - var diagnosticSpan = location.UnmappedFileSpan.GetClampedTextSpan(text); - var start = Math.Max(diagnosticSpan.Start + delta, 0); - var end = start + diagnosticSpan.Length; - if (start >= tree.Length) - start = tree.Length - 1; - if (end >= tree.Length) - end = tree.Length - 1; - var newSpan = new TextSpan(start, end - start); - return location.WithSpan(newSpan, tree); - } - } - } } } } 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 c76750e900a4c..5dac600b131e8 100644 --- a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.IncrementalMemberEditAnalyzer_MemberSpans.cs +++ b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.IncrementalMemberEditAnalyzer_MemberSpans.cs @@ -2,18 +2,19 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Generic; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.LanguageService; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Diagnostics.EngineV2 +namespace Microsoft.CodeAnalysis.Diagnostics; + +internal partial class DiagnosticAnalyzerService { - internal partial class DiagnosticIncrementalAnalyzer + private partial class DiagnosticIncrementalAnalyzer { private sealed partial class IncrementalMemberEditAnalyzer { @@ -47,8 +48,9 @@ static async Task> CreateMemberSpansAsync(Document docu var service = document.GetRequiredLanguageService(); var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - using var pooledMembers = service.GetMethodLevelMembers(root); - var members = pooledMembers.Object; + // Specifies false for discardLargeInstances as these objects commonly exceed the default ArrayBuilder capacity threshold. + using var _ = ArrayBuilder.GetInstance(discardLargeInstances: false, out var members); + service.AddMethodLevelMembers(root, members); return members.SelectAsArray(m => m.FullSpan); } diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.ProjectAnalyzerReferenceChangedEventArgs.cs b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.ProjectAnalyzerReferenceChangedEventArgs.cs deleted file mode 100644 index f5b259f4e6372..0000000000000 --- a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.ProjectAnalyzerReferenceChangedEventArgs.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; -using System.Collections.Immutable; - -namespace Microsoft.CodeAnalysis.Diagnostics.EngineV2 -{ - internal partial class DiagnosticIncrementalAnalyzer - { - /// - /// EventArgs for - /// - /// this event args contains information such as the has changed - /// and what has changed. - /// - private class ProjectAnalyzerReferenceChangedEventArgs : EventArgs - { - public readonly Project Project; - public readonly ImmutableArray Added; - public readonly ImmutableArray Removed; - - public ProjectAnalyzerReferenceChangedEventArgs(Project project, ImmutableArray added, ImmutableArray removed) - { - Project = project; - Added = added; - Removed = removed; - } - } - } -} diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.ProjectState.cs b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.ProjectState.cs deleted file mode 100644 index d738aa7ec02de..0000000000000 --- a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.ProjectState.cs +++ /dev/null @@ -1,506 +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.Diagnostics; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Simplification; -using Microsoft.CodeAnalysis.SolutionCrawler; -using Microsoft.CodeAnalysis.Workspaces.Diagnostics; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Diagnostics.EngineV2 -{ - internal partial class DiagnosticIncrementalAnalyzer - { - /// - /// State for diagnostics that belong to a project at given time. - /// - private sealed class ProjectState - { - private const string SyntaxStateName = nameof(SyntaxStateName); - private const string SemanticStateName = nameof(SemanticStateName); - private const string NonLocalStateName = nameof(NonLocalStateName); - - // project id of this state - private readonly StateSet _owner; - - // last aggregated analysis result for this project saved - private DiagnosticAnalysisResult _lastResult; - - public ProjectState(StateSet owner, ProjectId projectId) - { - _owner = owner; - _lastResult = DiagnosticAnalysisResult.CreateInitialResult(projectId); - } - - public bool FromBuild => _lastResult.FromBuild; - - public ImmutableHashSet GetDocumentsWithDiagnostics() - => _lastResult.DocumentIdsOrEmpty; - - public bool IsEmpty() - => _lastResult.IsEmpty; - - public bool IsEmpty(DocumentId documentId) - => IsEmpty(_lastResult, documentId); - - /// - /// Return all diagnostics for the given project stored in this state - /// - public async Task GetAnalysisDataAsync(Project project, bool avoidLoadingData, CancellationToken cancellationToken) - { - // make a copy of last result. - var lastResult = _lastResult; - Contract.ThrowIfFalse(lastResult.ProjectId == project.Id); - - if (lastResult.IsDefault) - { - return await LoadInitialAnalysisDataAsync(project, cancellationToken).ConfigureAwait(false); - } - - RoslynDebug.Assert(lastResult.DocumentIds != null); - - // PERF: avoid loading data if version is not right one. - // avoid loading data flag is there as a strictly perf optimization. - var version = await GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false); - if (avoidLoadingData && lastResult.Version != version) - { - return lastResult; - } - - // if given project doesnt have any diagnostics, return empty. - if (lastResult.IsEmpty) - { - return DiagnosticAnalysisResult.CreateEmpty(lastResult.ProjectId, lastResult.Version); - } - - // loading data can be canceled any time. - var serializerVersion = lastResult.Version; - var builder = new Builder(project, lastResult.Version, lastResult.DocumentIds); - - foreach (var documentId in lastResult.DocumentIds) - { - cancellationToken.ThrowIfCancellationRequested(); - - var document = project.GetDocument(documentId); - if (document == null) - continue; - - if (!await TryGetDiagnosticsFromInMemoryStorageAsync(serializerVersion, document, builder, cancellationToken).ConfigureAwait(false)) - { - Debug.Assert(lastResult.Version == VersionStamp.Default); - - // this can happen if we merged back active file diagnostics back to project state but - // project state didn't have diagnostics for the file yet. (since project state was staled) - continue; - } - } - - if (!await TryGetProjectDiagnosticsFromInMemoryStorageAsync(serializerVersion, project, builder, cancellationToken).ConfigureAwait(false)) - { - // this can happen if SaveAsync is not yet called but active file merge happened. one of case is if user did build before the very first - // analysis happened. - } - - return builder.ToResult(); - } - - /// - /// Return all diagnostics for the given document stored in this state including non local diagnostics for this document - /// - public async Task GetAnalysisDataAsync(TextDocument document, bool avoidLoadingData, CancellationToken cancellationToken) - { - // make a copy of last result. - var lastResult = _lastResult; - Contract.ThrowIfFalse(lastResult.ProjectId == document.Project.Id); - - if (lastResult.IsDefault) - { - return await LoadInitialAnalysisDataAsync(document, cancellationToken).ConfigureAwait(false); - } - - var version = await GetDiagnosticVersionAsync(document.Project, cancellationToken).ConfigureAwait(false); - if (avoidLoadingData && lastResult.Version != version) - { - return lastResult; - } - - // if given document doesnt have any diagnostics, return empty. - if (IsEmpty(lastResult, document.Id)) - { - return DiagnosticAnalysisResult.CreateEmpty(lastResult.ProjectId, lastResult.Version); - } - - // loading data can be canceled any time. - var serializerVersion = lastResult.Version; - var builder = new Builder(document.Project, lastResult.Version); - - if (!await TryGetDiagnosticsFromInMemoryStorageAsync(serializerVersion, document, builder, cancellationToken).ConfigureAwait(false)) - { - Debug.Assert(lastResult.Version == VersionStamp.Default); - - // this can happen if we merged back active file diagnostics back to project state but - // project state didn't have diagnostics for the file yet. (since project state was staled) - } - - return builder.ToResult(); - } - - /// - /// Return all no location diagnostics for the given project stored in this state - /// - public async Task GetProjectAnalysisDataAsync(Project project, bool avoidLoadingData, CancellationToken cancellationToken) - { - // make a copy of last result. - var lastResult = _lastResult; - Contract.ThrowIfFalse(lastResult.ProjectId == project.Id); - - if (lastResult.IsDefault) - { - return await LoadInitialProjectAnalysisDataAsync(project, cancellationToken).ConfigureAwait(false); - } - - var version = await GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false); - if (avoidLoadingData && lastResult.Version != version) - { - return lastResult; - } - - // if given document doesn't have any diagnostics, return empty. - if (lastResult.IsEmpty) - { - return DiagnosticAnalysisResult.CreateEmpty(lastResult.ProjectId, lastResult.Version); - } - - // loading data can be canceled any time. - var serializerVersion = lastResult.Version; - var builder = new Builder(project, lastResult.Version); - - if (!await TryGetProjectDiagnosticsFromInMemoryStorageAsync(serializerVersion, project, builder, cancellationToken).ConfigureAwait(false)) - { - // this can happen if SaveAsync is not yet called but active file merge happened. one of case is if user did build before the very first - // analysis happened. - } - - return builder.ToResult(); - } - - public async ValueTask SaveToInMemoryStorageAsync(Project project, DiagnosticAnalysisResult result) - { - Contract.ThrowIfTrue(result.IsAggregatedForm); - Contract.ThrowIfNull(result.DocumentIds); - - RemoveInMemoryCache(_lastResult); - - using var _ = PooledHashSet.GetInstance(out var documentIdsToProcess); - documentIdsToProcess.AddRange(_lastResult.DocumentIdsOrEmpty); - documentIdsToProcess.AddRange(result.DocumentIdsOrEmpty); - - // save last aggregated form of analysis result - _lastResult = result.ToAggregatedForm(); - - // serialization can't be canceled. - var serializerVersion = result.Version; - - foreach (var documentId in documentIdsToProcess) - { - var document = project.GetTextDocument(documentId); - - // If we couldn't find a normal document, and all features are enabled for source generated - // documents, attempt to locate a matching source generated document in the project. - if (document is null - && project.Solution.Services.GetService()?.EnableDiagnosticsInSourceGeneratedFiles == true) - { - document = await project.GetSourceGeneratedDocumentAsync(documentId, CancellationToken.None).ConfigureAwait(false); - } - - if (document == null) - { - // it can happen with build synchronization since, in build case, - // we don't have actual snapshot (we have no idea what sources out of proc build has picked up) - // so we might be out of sync. - // example of such cases will be changing anything about solution while building is going on. - // it can be user explicit actions such as unloading project, deleting a file, but also it can be - // something project system or roslyn workspace does such as populating workspace right after - // solution is loaded. - continue; - } - - AddToInMemoryStorage(serializerVersion, project, document, document.Id, SyntaxStateName, result.GetDocumentDiagnostics(document.Id, AnalysisKind.Syntax)); - AddToInMemoryStorage(serializerVersion, project, document, document.Id, SemanticStateName, result.GetDocumentDiagnostics(document.Id, AnalysisKind.Semantic)); - AddToInMemoryStorage(serializerVersion, project, document, document.Id, NonLocalStateName, result.GetDocumentDiagnostics(document.Id, AnalysisKind.NonLocal)); - } - - AddToInMemoryStorage(serializerVersion, project, document: null, result.ProjectId, NonLocalStateName, result.GetOtherDiagnostics()); - } - - public void ResetVersion() - { - // reset version of cached data so that we can recalculate new data (ex, OnDocumentReset) - _lastResult = _lastResult.Reset(); - } - - public async ValueTask MergeAsync(ActiveFileState state, TextDocument document, IGlobalOptionService globalOptions) - { - Contract.ThrowIfFalse(state.DocumentId == document.Id); - - // merge active file state to project state - var lastResult = _lastResult; - - var syntax = state.GetAnalysisData(AnalysisKind.Syntax); - var semantic = state.GetAnalysisData(AnalysisKind.Semantic); - - var project = document.Project; - - // if project didn't successfully loaded, then it is same as FSA off - var fullAnalysis = _owner.Analyzer.IsFullSolutionAnalysisEnabled(globalOptions, project.Language) && - await project.HasSuccessfullyLoadedAsync(CancellationToken.None).ConfigureAwait(false); - - // keep from build flag if full analysis is off - var fromBuild = fullAnalysis ? false : lastResult.FromBuild; - - // if it is allowed to keep project state, check versions and if they are same, bail out. - // if full solution analysis is off or we are asked to reset document state, we always merge. - if (fullAnalysis && - syntax.Version != VersionStamp.Default && - syntax.Version == semantic.Version && - syntax.Version == lastResult.Version) - { - // all data is in sync already. - return; - } - - // we have mixed versions or full analysis is off, set it to default so that it can be re-calculated next time so data can be in sync. - var version = VersionStamp.Default; - - // serialization can't be canceled. - var serializerVersion = version; - - // save active file diagnostics back to project state - AddToInMemoryStorage(serializerVersion, project, document, document.Id, SyntaxStateName, syntax.Items); - AddToInMemoryStorage(serializerVersion, project, document, document.Id, SemanticStateName, semantic.Items); - - // save last aggregated form of analysis result - _lastResult = _lastResult.UpdateAggregatedResult(version, state.DocumentId, fromBuild); - } - - public bool OnDocumentRemoved(DocumentId id) - { - RemoveInMemoryCacheEntries(id); - return !IsEmpty(id); - } - - public bool OnProjectRemoved(ProjectId id) - { - RemoveInMemoryCacheEntry(id, NonLocalStateName); - return !IsEmpty(); - } - - private async Task LoadInitialAnalysisDataAsync(Project project, CancellationToken cancellationToken) - { - // loading data can be canceled any time. - var version = await GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false); - var serializerVersion = version; - var builder = new Builder(project, version); - - foreach (var document in project.Documents) - { - cancellationToken.ThrowIfCancellationRequested(); - - if (!await TryGetDiagnosticsFromInMemoryStorageAsync(serializerVersion, document, builder, cancellationToken).ConfigureAwait(false)) - continue; - } - - if (!await TryGetProjectDiagnosticsFromInMemoryStorageAsync(serializerVersion, project, builder, cancellationToken).ConfigureAwait(false)) - return DiagnosticAnalysisResult.CreateEmpty(project.Id, VersionStamp.Default); - - return builder.ToResult(); - } - - private async Task LoadInitialAnalysisDataAsync(TextDocument document, CancellationToken cancellationToken) - { - // loading data can be canceled any time. - var project = document.Project; - - var version = await GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false); - var serializerVersion = version; - var builder = new Builder(project, version); - - if (!await TryGetDiagnosticsFromInMemoryStorageAsync(serializerVersion, document, builder, cancellationToken).ConfigureAwait(false)) - { - return DiagnosticAnalysisResult.CreateEmpty(project.Id, VersionStamp.Default); - } - - return builder.ToResult(); - } - - private async Task LoadInitialProjectAnalysisDataAsync(Project project, CancellationToken cancellationToken) - { - // loading data can be canceled any time. - var version = await GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false); - var serializerVersion = version; - var builder = new Builder(project, version); - - if (!await TryGetProjectDiagnosticsFromInMemoryStorageAsync(serializerVersion, project, builder, cancellationToken).ConfigureAwait(false)) - return DiagnosticAnalysisResult.CreateEmpty(project.Id, VersionStamp.Default); - - return builder.ToResult(); - } - - private void AddToInMemoryStorage( - VersionStamp serializerVersion, Project project, TextDocument? document, object key, string stateKey, ImmutableArray diagnostics) - { - Contract.ThrowIfFalse(document == null || document.Project == project); - - // if serialization fail, hold it in the memory - InMemoryStorage.Cache(_owner.Analyzer, (key, stateKey), new CacheEntry(serializerVersion, diagnostics)); - } - - private async ValueTask TryGetDiagnosticsFromInMemoryStorageAsync(VersionStamp serializerVersion, TextDocument document, Builder builder, CancellationToken cancellationToken) - { - var success = true; - var project = document.Project; - var documentId = document.Id; - - var diagnostics = await GetDiagnosticsFromInMemoryStorageAsync(serializerVersion, project, document, documentId, SyntaxStateName, cancellationToken).ConfigureAwait(false); - if (!diagnostics.IsDefault) - { - builder.AddSyntaxLocals(documentId, diagnostics); - } - else - { - success = false; - } - - diagnostics = await GetDiagnosticsFromInMemoryStorageAsync(serializerVersion, project, document, documentId, SemanticStateName, cancellationToken).ConfigureAwait(false); - if (!diagnostics.IsDefault) - { - builder.AddSemanticLocals(documentId, diagnostics); - } - else - { - success = false; - } - - diagnostics = await GetDiagnosticsFromInMemoryStorageAsync(serializerVersion, project, document, documentId, NonLocalStateName, cancellationToken).ConfigureAwait(false); - if (!diagnostics.IsDefault) - { - builder.AddNonLocals(documentId, diagnostics); - } - else - { - success = false; - } - - return success; - } - - private async ValueTask TryGetProjectDiagnosticsFromInMemoryStorageAsync(VersionStamp serializerVersion, Project project, Builder builder, CancellationToken cancellationToken) - { - var diagnostics = await GetDiagnosticsFromInMemoryStorageAsync(serializerVersion, project, document: null, project.Id, NonLocalStateName, cancellationToken).ConfigureAwait(false); - if (!diagnostics.IsDefault) - { - builder.AddOthers(diagnostics); - return true; - } - - return false; - } - - private ValueTask> GetDiagnosticsFromInMemoryStorageAsync( - VersionStamp serializerVersion, Project project, TextDocument? document, object key, string stateKey, CancellationToken _) - { - Contract.ThrowIfFalse(document == null || document.Project == project); - - return InMemoryStorage.TryGetValue(_owner.Analyzer, (key, stateKey), out var entry) && serializerVersion == entry.Version - ? new(entry.Diagnostics) - : default; - } - - private void RemoveInMemoryCache(DiagnosticAnalysisResult lastResult) - { - // remove old cache - foreach (var documentId in lastResult.DocumentIdsOrEmpty) - { - RemoveInMemoryCacheEntries(documentId); - } - } - - private void RemoveInMemoryCacheEntries(DocumentId id) - { - RemoveInMemoryCacheEntry(id, SyntaxStateName); - RemoveInMemoryCacheEntry(id, SemanticStateName); - RemoveInMemoryCacheEntry(id, NonLocalStateName); - } - - private void RemoveInMemoryCacheEntry(object key, string stateKey) - { - // remove in memory cache if entry exist - InMemoryStorage.Remove(_owner.Analyzer, (key, stateKey)); - } - - private static bool IsEmpty(DiagnosticAnalysisResult result, DocumentId documentId) - => !result.DocumentIdsOrEmpty.Contains(documentId); - - // we have this builder to avoid allocating collections unnecessarily. - private sealed class Builder - { - private readonly Project _project; - private readonly VersionStamp _version; - private readonly ImmutableHashSet? _documentIds; - - private ImmutableDictionary>.Builder? _syntaxLocals; - private ImmutableDictionary>.Builder? _semanticLocals; - private ImmutableDictionary>.Builder? _nonLocals; - private ImmutableArray _others; - - public Builder(Project project, VersionStamp version, ImmutableHashSet? documentIds = null) - { - _project = project; - _version = version; - _documentIds = documentIds; - } - - public void AddSyntaxLocals(DocumentId documentId, ImmutableArray diagnostics) - => Add(ref _syntaxLocals, documentId, diagnostics); - - public void AddSemanticLocals(DocumentId documentId, ImmutableArray diagnostics) - => Add(ref _semanticLocals, documentId, diagnostics); - - public void AddNonLocals(DocumentId documentId, ImmutableArray diagnostics) - => Add(ref _nonLocals, documentId, diagnostics); - - public void AddOthers(ImmutableArray diagnostics) - => _others = diagnostics; - - private void Add(ref ImmutableDictionary>.Builder? locals, DocumentId documentId, ImmutableArray diagnostics) - { - if (_project.GetDocument(documentId)?.SupportsDiagnostics() == false) - { - return; - } - - locals ??= ImmutableDictionary.CreateBuilder>(); - locals.Add(documentId, diagnostics); - } - - public DiagnosticAnalysisResult ToResult() - { - return DiagnosticAnalysisResult.Create(_project, _version, - _syntaxLocals?.ToImmutable() ?? ImmutableDictionary>.Empty, - _semanticLocals?.ToImmutable() ?? ImmutableDictionary>.Empty, - _nonLocals?.ToImmutable() ?? ImmutableDictionary>.Empty, - _others.NullToEmpty(), - _documentIds); - } - } - } - } -} diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.StateManager.HostStates.cs b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.StateManager.HostStates.cs deleted file mode 100644 index 0cb12b892ce0c..0000000000000 --- a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.StateManager.HostStates.cs +++ /dev/null @@ -1,170 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using Microsoft.CodeAnalysis.PooledObjects; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Diagnostics.EngineV2 -{ - internal partial class DiagnosticIncrementalAnalyzer - { - private partial class StateManager - { - public IEnumerable GetAllHostStateSets() - { - var analyzerReferences = _workspace.CurrentSolution.SolutionState.Analyzers.HostAnalyzerReferences; - foreach (var (key, value) in _hostAnalyzerStateMap) - { - if (key.AnalyzerReferences == analyzerReferences) - { - foreach (var stateSet in value.OrderedStateSets) - { - yield return stateSet; - } - } - } - } - - private HostAnalyzerStateSets GetOrCreateHostStateSets(Project project, ProjectAnalyzerStateSets projectStateSets) - { - var key = new HostAnalyzerStateSetKey(project.Language, project.State.HasSdkCodeStyleAnalyzers, project.Solution.SolutionState.Analyzers.HostAnalyzerReferences); - // Some Host Analyzers may need to be treated as Project Analyzers so that they do not have access to the - // Host fallback options. These ids will be used when building up the Host and Project analyzer collections. - var referenceIdsToRedirect = GetReferenceIdsToRedirectAsProjectAnalyzers(project); - var hostStateSets = ImmutableInterlocked.GetOrAdd(ref _hostAnalyzerStateMap, key, CreateLanguageSpecificAnalyzerMap, (project.Solution.SolutionState.Analyzers, referenceIdsToRedirect)); - return hostStateSets.WithExcludedAnalyzers(projectStateSets.SkippedAnalyzersInfo.SkippedAnalyzers); - - static HostAnalyzerStateSets CreateLanguageSpecificAnalyzerMap(HostAnalyzerStateSetKey arg, (HostDiagnosticAnalyzers HostAnalyzers, ImmutableHashSet ReferenceIdsToRedirect) state) - { - var language = arg.Language; - var analyzersPerReference = state.HostAnalyzers.GetOrCreateHostDiagnosticAnalyzersPerReference(language); - - var (hostAnalyzerCollection, projectAnalyzerCollection) = GetAnalyzerCollections(analyzersPerReference, state.ReferenceIdsToRedirect); - var analyzerMap = CreateStateSetMap(language, projectAnalyzerCollection, hostAnalyzerCollection, includeWorkspacePlaceholderAnalyzers: true); - - return new HostAnalyzerStateSets(analyzerMap); - } - - static (IEnumerable> HostAnalyzerCollection, IEnumerable> ProjectAnalyzerCollection) GetAnalyzerCollections( - ImmutableDictionary> analyzersPerReference, - ImmutableHashSet referenceIdsToRedirectAsProjectAnalyzers) - { - if (referenceIdsToRedirectAsProjectAnalyzers.IsEmpty) - { - return (analyzersPerReference.Values, []); - } - - var hostAnalyzerCollection = ArrayBuilder>.GetInstance(); - var projectAnalyzerCollection = ArrayBuilder>.GetInstance(); - - foreach (var (referenceId, analyzers) in analyzersPerReference) - { - if (referenceIdsToRedirectAsProjectAnalyzers.Contains(referenceId)) - { - projectAnalyzerCollection.Add(analyzers); - } - else - { - hostAnalyzerCollection.Add(analyzers); - } - } - - return (hostAnalyzerCollection.ToImmutableAndFree(), projectAnalyzerCollection.ToImmutableAndFree()); - } - } - - private static ImmutableHashSet GetReferenceIdsToRedirectAsProjectAnalyzers(Project project) - { - if (project.State.HasSdkCodeStyleAnalyzers) - { - // When a project uses CodeStyle analyzers added by the SDK, we remove them in favor of the - // Features analyzers. We need to then treat the Features analyzers as Project analyzers so - // they do not get access to the Host fallback options. - return GetFeaturesAnalyzerReferenceIds(project.Solution.SolutionState.Analyzers); - } - - return []; - - static ImmutableHashSet GetFeaturesAnalyzerReferenceIds(HostDiagnosticAnalyzers hostAnalyzers) - { - var builder = ImmutableHashSet.CreateBuilder(); - - foreach (var analyzerReference in hostAnalyzers.HostAnalyzerReferences) - { - if (analyzerReference.IsFeaturesAnalyzer()) - builder.Add(analyzerReference.Id); - } - - return builder.ToImmutable(); - } - } - - private sealed class HostAnalyzerStateSets - { - private const int FileContentLoadAnalyzerPriority = -4; - private const int GeneratorDiagnosticsPlaceholderAnalyzerPriority = -3; - private const int BuiltInCompilerPriority = -2; - private const int RegularDiagnosticAnalyzerPriority = -1; - - // ordered by priority - public readonly ImmutableArray OrderedStateSets; - - public readonly ImmutableDictionary StateSetMap; - - private HostAnalyzerStateSets(ImmutableDictionary stateSetMap, ImmutableArray orderedStateSets) - { - StateSetMap = stateSetMap; - OrderedStateSets = orderedStateSets; - } - - public HostAnalyzerStateSets(ImmutableDictionary analyzerMap) - { - StateSetMap = analyzerMap; - - // order statesets - // order will be in this order - // BuiltIn Compiler Analyzer (C#/VB) < Regular DiagnosticAnalyzers < Document/ProjectDiagnosticAnalyzers - OrderedStateSets = [.. StateSetMap.Values.OrderBy(PriorityComparison)]; - } - - public HostAnalyzerStateSets WithExcludedAnalyzers(ImmutableHashSet excludedAnalyzers) - { - if (excludedAnalyzers.IsEmpty) - { - return this; - } - - var stateSetMap = StateSetMap.Where(kvp => !excludedAnalyzers.Contains(kvp.Key)).ToImmutableDictionary(); - var orderedStateSets = OrderedStateSets.WhereAsArray(stateSet => !excludedAnalyzers.Contains(stateSet.Analyzer)); - return new HostAnalyzerStateSets(stateSetMap, orderedStateSets); - } - - private int PriorityComparison(StateSet state1, StateSet state2) - => GetPriority(state1) - GetPriority(state2); - - private static int GetPriority(StateSet state) - { - // compiler gets highest priority - if (state.Analyzer.IsCompilerAnalyzer()) - { - return BuiltInCompilerPriority; - } - - return state.Analyzer switch - { - FileContentLoadAnalyzer _ => FileContentLoadAnalyzerPriority, - GeneratorDiagnosticsPlaceholderAnalyzer _ => GeneratorDiagnosticsPlaceholderAnalyzerPriority, - DocumentDiagnosticAnalyzer analyzer => Math.Max(0, analyzer.Priority), - ProjectDiagnosticAnalyzer analyzer => Math.Max(0, analyzer.Priority), - _ => RegularDiagnosticAnalyzerPriority, - }; - } - } - } - } -} diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.StateManager.ProjectStates.cs b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.StateManager.ProjectStates.cs index 38990e7851c12..3c52425994a08 100644 --- a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.StateManager.ProjectStates.cs +++ b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.StateManager.ProjectStates.cs @@ -4,56 +4,44 @@ using System.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Diagnostics.EngineV2 +namespace Microsoft.CodeAnalysis.Diagnostics; + +internal partial class DiagnosticAnalyzerService { - internal partial class DiagnosticIncrementalAnalyzer + private partial class DiagnosticIncrementalAnalyzer { private partial class StateManager { - private readonly struct ProjectAnalyzerStateSets + private readonly struct ProjectAnalyzerInfo { - public static readonly ProjectAnalyzerStateSets Default = new( - [], - ImmutableDictionary>.Empty, - ImmutableDictionary.Empty, + public static readonly ProjectAnalyzerInfo Default = new( + analyzerReferences: [], + analyzers: [], SkippedHostAnalyzersInfo.Empty); public readonly IReadOnlyList AnalyzerReferences; - // maps analyzer reference id to list of analyzers loaded from the reference - public readonly ImmutableDictionary> MapPerReferences; - - public readonly ImmutableDictionary StateSetMap; + public readonly ImmutableHashSet Analyzers; public readonly SkippedHostAnalyzersInfo SkippedAnalyzersInfo; - internal ProjectAnalyzerStateSets( + internal ProjectAnalyzerInfo( IReadOnlyList analyzerReferences, - ImmutableDictionary> mapPerReferences, - ImmutableDictionary stateSetMap, + ImmutableHashSet analyzers, SkippedHostAnalyzersInfo skippedAnalyzersInfo) { AnalyzerReferences = analyzerReferences; - MapPerReferences = mapPerReferences; - StateSetMap = stateSetMap; + Analyzers = analyzers; SkippedAnalyzersInfo = skippedAnalyzersInfo; } } - public IEnumerable GetAllProjectStateSets() - { - // return existing state sets - // No need to use _projectAnalyzerStateMapGuard during reads of _projectAnalyzerStateMap - return _projectAnalyzerStateMap.Values.SelectManyAsArray(e => e.StateSetMap.Values); - } - - private ProjectAnalyzerStateSets? TryGetProjectStateSets(Project project) + private ProjectAnalyzerInfo? TryGetProjectAnalyzerInfo(ProjectState project) { // check if the analyzer references have changed since the last time we updated the map: // No need to use _projectAnalyzerStateMapGuard during reads of _projectAnalyzerStateMap @@ -66,127 +54,55 @@ public IEnumerable GetAllProjectStateSets() return null; } - private async Task GetOrCreateProjectStateSetsAsync(Project project, CancellationToken cancellationToken) - => TryGetProjectStateSets(project) ?? await UpdateProjectStateSetsAsync(project, cancellationToken).ConfigureAwait(false); + private async Task GetOrCreateProjectAnalyzerInfoAsync(SolutionState solution, ProjectState project, CancellationToken cancellationToken) + => TryGetProjectAnalyzerInfo(project) ?? await UpdateProjectAnalyzerInfoAsync(solution, project, cancellationToken).ConfigureAwait(false); - /// - /// Creates a new project state sets. - /// - private ProjectAnalyzerStateSets CreateProjectStateSets(Project project) + private ProjectAnalyzerInfo CreateProjectAnalyzerInfo(SolutionState solution, ProjectState project) { if (project.AnalyzerReferences.Count == 0) { - return ProjectAnalyzerStateSets.Default; + return ProjectAnalyzerInfo.Default; } - var hostAnalyzers = project.Solution.SolutionState.Analyzers; - var analyzersPerReference = hostAnalyzers.CreateProjectDiagnosticAnalyzersPerReference(project); + var solutionAnalyzers = solution.Analyzers; + var analyzersPerReference = solutionAnalyzers.CreateProjectDiagnosticAnalyzersPerReference(project); if (analyzersPerReference.Count == 0) { - return ProjectAnalyzerStateSets.Default; + return ProjectAnalyzerInfo.Default; } - var newMap = CreateStateSetMap(project.Language, analyzersPerReference.Values, [], includeWorkspacePlaceholderAnalyzers: false); - var skippedAnalyzersInfo = project.GetSkippedAnalyzersInfo(_analyzerInfoCache); - return new ProjectAnalyzerStateSets(project.AnalyzerReferences, analyzersPerReference, newMap, skippedAnalyzersInfo); + var (newHostAnalyzers, newAllAnalyzers) = PartitionAnalyzers( + analyzersPerReference.Values, hostAnalyzerCollection: [], includeWorkspacePlaceholderAnalyzers: false); + + // We passed an empty array for 'hostAnalyzeCollection' above, and we specifically asked to not include + // workspace placeholder analyzers. So we should never get host analyzers back here. + Contract.ThrowIfTrue(newHostAnalyzers.Count > 0); + + var skippedAnalyzersInfo = solutionAnalyzers.GetSkippedAnalyzersInfo(project, _analyzerInfoCache); + return new ProjectAnalyzerInfo(project.AnalyzerReferences, newAllAnalyzers, skippedAnalyzersInfo); } /// /// Updates the map to the given project snapshot. /// - private async Task UpdateProjectStateSetsAsync(Project project, CancellationToken cancellationToken) + private async Task UpdateProjectAnalyzerInfoAsync( + SolutionState solution, ProjectState project, CancellationToken cancellationToken) { - ProjectAnalyzerReferenceChangedEventArgs? analyzerReferenceChangedEventArgs = null; - ProjectAnalyzerStateSets? projectStateSets; - // This code is called concurrently for a project, so the guard prevents duplicated effort calculating StateSets. using (await _projectAnalyzerStateMapGuard.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) { - projectStateSets = TryGetProjectStateSets(project); + var projectAnalyzerInfo = TryGetProjectAnalyzerInfo(project); - if (projectStateSets == null) + if (projectAnalyzerInfo == null) { - projectStateSets = CreateProjectStateSets(project); - - analyzerReferenceChangedEventArgs = GetProjectAnalyzerReferenceChangedEventArgs(project, projectStateSets.Value.MapPerReferences, projectStateSets.Value.StateSetMap); + projectAnalyzerInfo = CreateProjectAnalyzerInfo(solution, project); // update cache. - _projectAnalyzerStateMap = _projectAnalyzerStateMap.SetItem(project.Id, projectStateSets.Value); - } - } - - if (analyzerReferenceChangedEventArgs != null) - RaiseProjectAnalyzerReferenceChanged(analyzerReferenceChangedEventArgs); - - return projectStateSets.Value; - } - - private ProjectAnalyzerReferenceChangedEventArgs? GetProjectAnalyzerReferenceChangedEventArgs( - Project project, - ImmutableDictionary> newMapPerReference, - ImmutableDictionary newMap) - { - // No need to use _projectAnalyzerStateMapGuard during reads of _projectAnalyzerStateMap - if (!_projectAnalyzerStateMap.TryGetValue(project.Id, out var entry)) - { - // no previous references and we still don't have any references - if (newMap.Count == 0) - { - return null; + _projectAnalyzerStateMap = _projectAnalyzerStateMap.SetItem(project.Id, projectAnalyzerInfo.Value); } - // new reference added - return new ProjectAnalyzerReferenceChangedEventArgs(project, newMap.Values.ToImmutableArrayOrEmpty(), []); + return projectAnalyzerInfo.Value; } - - Debug.Assert(!entry.AnalyzerReferences.Equals(project.AnalyzerReferences)); - - // there has been change. find out what has changed - var addedStates = DiffStateSets(project.AnalyzerReferences.Except(entry.AnalyzerReferences), newMapPerReference, newMap); - var removedStates = DiffStateSets(entry.AnalyzerReferences.Except(project.AnalyzerReferences), entry.MapPerReferences, entry.StateSetMap); - - // nothing has changed - if (addedStates.Length == 0 && removedStates.Length == 0) - { - return null; - } - - return new ProjectAnalyzerReferenceChangedEventArgs(project, addedStates, removedStates); - } - - private static ImmutableArray DiffStateSets( - IEnumerable references, - ImmutableDictionary> mapPerReference, - ImmutableDictionary map) - { - if (mapPerReference.Count == 0 || map.Count == 0) - { - // nothing to diff - return []; - } - - var builder = ImmutableArray.CreateBuilder(); - foreach (var reference in references) - { - // check duplication - if (!mapPerReference.TryGetValue(reference.Id, out var analyzers)) - { - continue; - } - - // okay, this is real reference. get stateset - foreach (var analyzer in analyzers) - { - if (!map.TryGetValue(analyzer, out var set)) - { - continue; - } - - builder.Add(set); - } - } - - return builder.ToImmutableAndClear(); } } } diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.StateManager.cs b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.StateManager.cs index 78e1d431cdbe2..2a46388f88f88 100644 --- a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.StateManager.cs +++ b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.StateManager.cs @@ -2,146 +2,76 @@ // The .NET Foundation 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 Roslyn.Utilities; +using Microsoft.CodeAnalysis.PooledObjects; -namespace Microsoft.CodeAnalysis.Diagnostics.EngineV2 +namespace Microsoft.CodeAnalysis.Diagnostics; + +internal partial class DiagnosticAnalyzerService { - internal partial class DiagnosticIncrementalAnalyzer + private partial class DiagnosticIncrementalAnalyzer { /// - /// This is in charge of anything related to + /// This is in charge of anything related to /// - private partial class StateManager + private partial class StateManager(DiagnosticAnalyzerInfoCache analyzerInfoCache) { - private readonly Workspace _workspace; - private readonly DiagnosticAnalyzerInfoCache _analyzerInfoCache; + private readonly DiagnosticAnalyzerInfoCache _analyzerInfoCache = analyzerInfoCache; /// /// Analyzers supplied by the host (IDE). These are built-in to the IDE, the compiler, or from an installed IDE extension (VSIX). /// Maps language name to the analyzers and their state. /// - private ImmutableDictionary _hostAnalyzerStateMap; + private ImmutableDictionary _hostAnalyzerStateMap = ImmutableDictionary.Empty; /// /// Analyzers referenced by the project via a PackageReference. Updates are protected by _projectAnalyzerStateMapGuard. /// ImmutableDictionary used to present a safe, non-immutable view to users. /// - private ImmutableDictionary _projectAnalyzerStateMap; + private ImmutableDictionary _projectAnalyzerStateMap = ImmutableDictionary.Empty; /// /// Guard around updating _projectAnalyzerStateMap. This is used in UpdateProjectStateSets to avoid /// duplicated calculations for a project during contentious calls. /// - private readonly SemaphoreSlim _projectAnalyzerStateMapGuard = new(1); - - /// - /// This will be raised whenever finds change - /// - public event EventHandler? ProjectAnalyzerReferenceChanged; - - public StateManager(Workspace workspace, DiagnosticAnalyzerInfoCache analyzerInfoCache) - { - _workspace = workspace; - _analyzerInfoCache = analyzerInfoCache; - - _hostAnalyzerStateMap = ImmutableDictionary.Empty; - _projectAnalyzerStateMap = ImmutableDictionary.Empty; - } + private readonly SemaphoreSlim _projectAnalyzerStateMapGuard = new(initialCount: 1); /// - /// Return s for the given . - /// This will never create new but will return ones already created. + /// Return s for the given . /// - public IEnumerable GetStateSets(ProjectId projectId) + public async Task> GetOrCreateAnalyzersAsync( + SolutionState solution, ProjectState project, CancellationToken cancellationToken) { - var hostStateSets = GetAllHostStateSets(); - - // No need to use _projectAnalyzerStateMapGuard during reads of _projectAnalyzerStateMap - return _projectAnalyzerStateMap.TryGetValue(projectId, out var entry) - ? hostStateSets.Concat(entry.StateSetMap.Values) - : hostStateSets; + var hostAnalyzerInfo = await GetOrCreateHostAnalyzerInfoAsync(solution, project, cancellationToken).ConfigureAwait(false); + var projectAnalyzerInfo = await GetOrCreateProjectAnalyzerInfoAsync(solution, project, cancellationToken).ConfigureAwait(false); + return hostAnalyzerInfo.OrderedAllAnalyzers.AddRange(projectAnalyzerInfo.Analyzers); } - /// - /// Return s for the given . - /// This will never create new but will return ones already created. - /// Difference with is that - /// this will only return s that have same language as . - /// - public IEnumerable GetStateSets(Project project) - => GetStateSets(project.Id).Where(s => s.Language == project.Language); - - /// - /// Return s for the given . - /// This will either return already created s for the specific snapshot of or - /// it will create new s for the and update internal state. - /// - public async Task> GetOrCreateStateSetsAsync(Project project, CancellationToken cancellationToken) + public async Task GetOrCreateHostAnalyzerInfoAsync( + SolutionState solution, ProjectState project, CancellationToken cancellationToken) { - var projectStateSets = await GetOrCreateProjectStateSetsAsync(project, cancellationToken).ConfigureAwait(false); - return GetOrCreateHostStateSets(project, projectStateSets).OrderedStateSets.AddRange(projectStateSets.StateSetMap.Values); + var projectAnalyzerInfo = await GetOrCreateProjectAnalyzerInfoAsync(solution, project, cancellationToken).ConfigureAwait(false); + return GetOrCreateHostAnalyzerInfo(solution, project, projectAnalyzerInfo); } - /// - /// Return for the given in the context of . - /// This will either return already created for the specific snapshot of or - /// it will create new for the . and update internal state. - /// - public async Task GetOrCreateStateSetAsync(Project project, DiagnosticAnalyzer analyzer, CancellationToken cancellationToken) - { - var projectStateSets = await GetOrCreateProjectStateSetsAsync(project, cancellationToken).ConfigureAwait(false); - if (projectStateSets.StateSetMap.TryGetValue(analyzer, out var stateSet)) - { - return stateSet; - } - - var hostStateSetMap = GetOrCreateHostStateSets(project, projectStateSets).StateSetMap; - if (hostStateSetMap.TryGetValue(analyzer, out stateSet)) - { - return stateSet; - } - - return null; - } - - public bool OnProjectRemoved(IEnumerable stateSets, ProjectId projectId) - { - var removed = false; - foreach (var stateSet in stateSets) - { - removed |= stateSet.OnProjectRemoved(projectId); - } - - lock (_projectAnalyzerStateMap) - { - _projectAnalyzerStateMap = _projectAnalyzerStateMap.Remove(projectId); - } - - return removed; - } - - private void RaiseProjectAnalyzerReferenceChanged(ProjectAnalyzerReferenceChangedEventArgs args) - => ProjectAnalyzerReferenceChanged?.Invoke(this, args); - - private static ImmutableDictionary CreateStateSetMap( - string language, + private static (ImmutableHashSet hostAnalyzers, ImmutableHashSet allAnalyzers) PartitionAnalyzers( IEnumerable> projectAnalyzerCollection, IEnumerable> hostAnalyzerCollection, bool includeWorkspacePlaceholderAnalyzers) { - var builder = ImmutableDictionary.CreateBuilder(); + using var _1 = PooledHashSet.GetInstance(out var hostAnalyzers); + using var _2 = PooledHashSet.GetInstance(out var allAnalyzers); if (includeWorkspacePlaceholderAnalyzers) { - builder.Add(FileContentLoadAnalyzer.Instance, new StateSet(language, FileContentLoadAnalyzer.Instance, isHostAnalyzer: true)); - builder.Add(GeneratorDiagnosticsPlaceholderAnalyzer.Instance, new StateSet(language, GeneratorDiagnosticsPlaceholderAnalyzer.Instance, isHostAnalyzer: true)); + hostAnalyzers.Add(FileContentLoadAnalyzer.Instance); + hostAnalyzers.Add(GeneratorDiagnosticsPlaceholderAnalyzer.Instance); + allAnalyzers.Add(FileContentLoadAnalyzer.Instance); + allAnalyzers.Add(GeneratorDiagnosticsPlaceholderAnalyzer.Instance); } foreach (var analyzers in projectAnalyzerCollection) @@ -149,17 +79,7 @@ private static ImmutableDictionary CreateStateSetM foreach (var analyzer in analyzers) { Debug.Assert(analyzer != FileContentLoadAnalyzer.Instance && analyzer != GeneratorDiagnosticsPlaceholderAnalyzer.Instance); - - // TODO: - // #1, all de-duplication should move to DiagnosticAnalyzerInfoCache - // #2, not sure whether de-duplication of analyzer itself makes sense. this can only happen - // if user deliberately put same analyzer twice. - if (builder.ContainsKey(analyzer)) - { - continue; - } - - builder.Add(analyzer, new StateSet(language, analyzer, isHostAnalyzer: false)); + allAnalyzers.Add(analyzer); } } @@ -168,48 +88,16 @@ private static ImmutableDictionary CreateStateSetM foreach (var analyzer in analyzers) { Debug.Assert(analyzer != FileContentLoadAnalyzer.Instance && analyzer != GeneratorDiagnosticsPlaceholderAnalyzer.Instance); - - // TODO: - // #1, all de-duplication should move to DiagnosticAnalyzerInfoCache - // #2, not sure whether de-duplication of analyzer itself makes sense. this can only happen - // if user deliberately put same analyzer twice. - if (builder.ContainsKey(analyzer)) - { - continue; - } - - builder.Add(analyzer, new StateSet(language, analyzer, isHostAnalyzer: true)); + allAnalyzers.Add(analyzer); + hostAnalyzers.Add(analyzer); } } - return builder.ToImmutable(); + return (hostAnalyzers.ToImmutableHashSet(), allAnalyzers.ToImmutableHashSet()); } - private readonly struct HostAnalyzerStateSetKey : IEquatable - { - public HostAnalyzerStateSetKey(string language, bool hasSdkCodeStyleAnalyzers, IReadOnlyList analyzerReferences) - { - Language = language; - HasSdkCodeStyleAnalyzers = hasSdkCodeStyleAnalyzers; - AnalyzerReferences = analyzerReferences; - } - - public string Language { get; } - public bool HasSdkCodeStyleAnalyzers { get; } - public IReadOnlyList AnalyzerReferences { get; } - - public bool Equals(HostAnalyzerStateSetKey other) - => Language == other.Language && - HasSdkCodeStyleAnalyzers == other.HasSdkCodeStyleAnalyzers && - AnalyzerReferences == other.AnalyzerReferences; - - public override bool Equals(object? obj) - => obj is HostAnalyzerStateSetKey key && Equals(key); - - public override int GetHashCode() - => Hash.Combine(Language.GetHashCode(), - Hash.Combine(HasSdkCodeStyleAnalyzers.GetHashCode(), AnalyzerReferences.GetHashCode())); - } + private readonly record struct HostAnalyzerInfoKey( + string Language, bool HasSdkCodeStyleAnalyzers, IReadOnlyList AnalyzerReferences); } } } diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.StateSet.cs b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.StateSet.cs deleted file mode 100644 index 3a6afd3e5633a..0000000000000 --- a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.StateSet.cs +++ /dev/null @@ -1,198 +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.Concurrent; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Options; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Diagnostics.EngineV2 -{ - internal partial class DiagnosticIncrementalAnalyzer - { - /// - /// this contains all states regarding a - /// - private sealed class StateSet - { - public readonly string Language; - public readonly DiagnosticAnalyzer Analyzer; - public readonly bool IsHostAnalyzer; - - private readonly ConcurrentDictionary _activeFileStates; - private readonly ConcurrentDictionary _projectStates; - - public StateSet(string language, DiagnosticAnalyzer analyzer, bool isHostAnalyzer) - { - Language = language; - Analyzer = analyzer; - IsHostAnalyzer = isHostAnalyzer; - - _activeFileStates = new ConcurrentDictionary(concurrencyLevel: 2, capacity: 10); - _projectStates = new ConcurrentDictionary(concurrencyLevel: 2, capacity: 1); - } - - public IEnumerable GetProjectsWithDiagnostics() - { - // quick bail out - if (_activeFileStates.IsEmpty && _projectStates.IsEmpty) - return []; - - if (_activeFileStates.Count == 1 && _projectStates.IsEmpty) - { - // see whether we actually have diagnostics - var (documentId, state) = _activeFileStates.First(); - if (state.IsEmpty) - return []; - - // we do have diagnostics - return [documentId.ProjectId]; - } - - return new HashSet( - _activeFileStates.Where(kv => !kv.Value.IsEmpty) - .Select(kv => kv.Key.ProjectId) - .Concat(_projectStates.Where(kv => !kv.Value.IsEmpty()) - .Select(kv => kv.Key))); - } - - [PerformanceSensitive("https://github.com/dotnet/roslyn/issues/34761", AllowCaptures = false, AllowGenericEnumeration = false)] - public void CollectDocumentsWithDiagnostics(ProjectId projectId, HashSet set) - { - RoslynDebug.Assert(set != null); - - // Collect active documents with diagnostics - - foreach (var (documentId, state) in _activeFileStates) - { - if (documentId.ProjectId == projectId && !state.IsEmpty) - { - set.Add(documentId); - } - } - - if (_projectStates.TryGetValue(projectId, out var projectState) && !projectState.IsEmpty()) - { - set.UnionWith(projectState.GetDocumentsWithDiagnostics()); - } - } - - public bool IsActiveFile(DocumentId documentId) - => _activeFileStates.ContainsKey(documentId); - - public bool FromBuild(ProjectId projectId) - => _projectStates.TryGetValue(projectId, out var projectState) && projectState.FromBuild; - - public bool TryGetActiveFileState(DocumentId documentId, [NotNullWhen(true)] out ActiveFileState? state) - => _activeFileStates.TryGetValue(documentId, out state); - - public bool TryGetProjectState(ProjectId projectId, [NotNullWhen(true)] out ProjectState? state) - => _projectStates.TryGetValue(projectId, out state); - - public ActiveFileState GetOrCreateActiveFileState(DocumentId documentId) - => _activeFileStates.GetOrAdd(documentId, id => new ActiveFileState(id)); - - public ProjectState GetOrCreateProjectState(ProjectId projectId) - => _projectStates.GetOrAdd(projectId, static (id, self) => new ProjectState(self, id), this); - - public async Task OnDocumentOpenedAsync(TextDocument document) - { - // can not be cancelled - if (!TryGetProjectState(document.Project.Id, out var projectState) || - projectState.IsEmpty(document.Id)) - { - // nothing to do - return false; - } - - var result = await projectState.GetAnalysisDataAsync(document, avoidLoadingData: false, CancellationToken.None).ConfigureAwait(false); - var text = await document.GetValueTextAsync(CancellationToken.None).ConfigureAwait(false); - - // store analysis result to active file state: - var activeFileState = GetOrCreateActiveFileState(document.Id); - - activeFileState.Save(AnalysisKind.Syntax, new DocumentAnalysisData(result.Version, text.Lines.Count, result.GetDocumentDiagnostics(document.Id, AnalysisKind.Syntax))); - activeFileState.Save(AnalysisKind.Semantic, new DocumentAnalysisData(result.Version, text.Lines.Count, result.GetDocumentDiagnostics(document.Id, AnalysisKind.Semantic))); - - return true; - } - - public async Task OnDocumentClosedAsync(TextDocument document, IGlobalOptionService globalOptions) - { - // can not be cancelled - // remove active file state and put it in project state - if (!_activeFileStates.TryRemove(document.Id, out var activeFileState)) - { - return false; - } - - // active file exist, put it in the project state - var projectState = GetOrCreateProjectState(document.Project.Id); - await projectState.MergeAsync(activeFileState, document, globalOptions).ConfigureAwait(false); - return true; - } - - public bool OnDocumentReset(TextDocument document) - { - var changed = false; - // can not be cancelled - // remove active file state and put it in project state - if (TryGetActiveFileState(document.Id, out var activeFileState)) - { - activeFileState.ResetVersion(); - changed |= true; - } - - if (TryGetProjectState(document.Project.Id, out var projectState)) - { - projectState.ResetVersion(); - changed |= true; - } - - return changed; - } - - public bool OnDocumentRemoved(DocumentId id) - { - // remove active file state for removed document - var removed = false; - if (_activeFileStates.TryRemove(id, out _)) - { - removed = true; - } - // remove state for the file that got removed. - if (_projectStates.TryGetValue(id.ProjectId, out var state)) - { - removed |= state.OnDocumentRemoved(id); - } - - return removed; - } - - public bool OnProjectRemoved(ProjectId id) - { - // remove state for project that got removed. - if (_projectStates.TryRemove(id, out var state)) - { - return state.OnProjectRemoved(id); - } - - return false; - } - - public void OnRemoved() - { - // ths stateset is being removed. - // TODO: we do this since InMemoryCache is static type. we might consider making it instance object - // of something. - InMemoryStorage.DropCache(Analyzer); - } - } - } -} diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.cs b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.cs index 50c31315f85ca..a08e0d811d5db 100644 --- a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.cs +++ b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.cs @@ -3,25 +3,23 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.SolutionCrawler; -using Microsoft.CodeAnalysis.Workspaces.Diagnostics; -using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Diagnostics.EngineV2 +namespace Microsoft.CodeAnalysis.Diagnostics; + +internal partial class DiagnosticAnalyzerService { /// /// Diagnostic Analyzer Engine V2 /// /// This one follows pattern compiler has set for diagnostic analyzer. /// - internal partial class DiagnosticIncrementalAnalyzer + private partial class DiagnosticIncrementalAnalyzer { private readonly DiagnosticAnalyzerTelemetry _telemetry = new(); private readonly StateManager _stateManager; @@ -29,67 +27,31 @@ internal partial class DiagnosticIncrementalAnalyzer private readonly IncrementalMemberEditAnalyzer _incrementalMemberEditAnalyzer = new(); internal DiagnosticAnalyzerService AnalyzerService { get; } - internal Workspace Workspace { get; } - [Obsolete(MefConstruction.FactoryMethodMessage, error: true)] public DiagnosticIncrementalAnalyzer( DiagnosticAnalyzerService analyzerService, - Workspace workspace, - DiagnosticAnalyzerInfoCache analyzerInfoCache) + DiagnosticAnalyzerInfoCache analyzerInfoCache, + IGlobalOptionService globalOptionService) { Contract.ThrowIfNull(analyzerService); AnalyzerService = analyzerService; - Workspace = workspace; + GlobalOptions = globalOptionService; - _stateManager = new StateManager(workspace, analyzerInfoCache); - _stateManager.ProjectAnalyzerReferenceChanged += OnProjectAnalyzerReferenceChanged; + _stateManager = new StateManager(analyzerInfoCache); - var enabled = this.AnalyzerService.GlobalOptions.GetOption(SolutionCrawlerRegistrationService.EnableSolutionCrawler); + var enabled = globalOptionService.GetOption(SolutionCrawlerRegistrationService.EnableSolutionCrawler); _diagnosticAnalyzerRunner = new InProcOrRemoteHostAnalyzerRunner( enabled, analyzerInfoCache, analyzerService.Listener); } - internal IGlobalOptionService GlobalOptions => AnalyzerService.GlobalOptions; + internal IGlobalOptionService GlobalOptions { get; } internal DiagnosticAnalyzerInfoCache DiagnosticAnalyzerInfoCache => _diagnosticAnalyzerRunner.AnalyzerInfoCache; - private void OnProjectAnalyzerReferenceChanged(object? sender, ProjectAnalyzerReferenceChangedEventArgs e) - { - if (e.Removed.Length == 0) - { - // nothing to refresh - return; - } - - // make sure we drop cache related to the analyzers - foreach (var stateSet in e.Removed) - stateSet.OnRemoved(); - } - - public static Task GetDiagnosticVersionAsync(Project project, CancellationToken cancellationToken) - => project.GetDependentVersionAsync(cancellationToken); - - private static DiagnosticAnalysisResult GetResultOrEmpty(ImmutableDictionary map, DiagnosticAnalyzer analyzer, ProjectId projectId, VersionStamp version) - { - if (map.TryGetValue(analyzer, out var result)) - { - return result; - } - - return DiagnosticAnalysisResult.CreateEmpty(projectId, version); - } - - internal async Task> GetAnalyzersTestOnlyAsync(Project project, CancellationToken cancellationToken) - { - var analyzers = await _stateManager.GetOrCreateStateSetsAsync(project, cancellationToken).ConfigureAwait(false); - - return analyzers.Select(s => s.Analyzer); - } - - private static string GetProjectLogMessage(Project project, ImmutableArray stateSets) - => $"project: ({project.Id}), ({string.Join(Environment.NewLine, stateSets.Select(s => s.Analyzer.ToString()))})"; + public Task> GetAnalyzersForTestingPurposesOnlyAsync(Project project, CancellationToken cancellationToken) + => _stateManager.GetOrCreateAnalyzersAsync(project.Solution.SolutionState, project.State, cancellationToken); - private static string GetOpenLogMessage(TextDocument document) - => $"document open: ({document.FilePath ?? document.Name})"; + private static string GetProjectLogMessage(Project project, ImmutableArray analyzers) + => $"project: ({project.Id}), ({string.Join(Environment.NewLine, analyzers.Select(a => a.ToString()))})"; } } diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnostics.cs b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnostics.cs index 0aaa78c089dd6..88489fcb8b566 100644 --- a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnostics.cs +++ b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnostics.cs @@ -8,277 +8,142 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Shared.Utilities; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Workspaces.Diagnostics; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Diagnostics.EngineV2 +namespace Microsoft.CodeAnalysis.Diagnostics; + +internal partial class DiagnosticAnalyzerService { - internal partial class DiagnosticIncrementalAnalyzer + private partial class DiagnosticIncrementalAnalyzer { - public Task> GetCachedDiagnosticsAsync(Solution solution, ProjectId? projectId, DocumentId? documentId, bool includeLocalDocumentDiagnostics, bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken) - => new IdeCachedDiagnosticGetter(this, solution, projectId, documentId, includeLocalDocumentDiagnostics, includeNonLocalDocumentDiagnostics).GetDiagnosticsAsync(cancellationToken); - - public Task> GetDiagnosticsForIdsAsync(Solution solution, ProjectId? projectId, DocumentId? documentId, ImmutableHashSet? diagnosticIds, Func? shouldIncludeAnalyzer, Func>? getDocuments, bool includeLocalDocumentDiagnostics, bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken) - => new IdeLatestDiagnosticGetter(this, solution, projectId, documentId, diagnosticIds, shouldIncludeAnalyzer, getDocuments, includeLocalDocumentDiagnostics, includeNonLocalDocumentDiagnostics).GetDiagnosticsAsync(cancellationToken); - - public Task> GetProjectDiagnosticsForIdsAsync(Solution solution, ProjectId? projectId, ImmutableHashSet? diagnosticIds, Func? shouldIncludeAnalyzer, bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken) - => new IdeLatestDiagnosticGetter(this, solution, projectId, documentId: null, diagnosticIds, shouldIncludeAnalyzer, getDocuments: null, includeLocalDocumentDiagnostics: false, includeNonLocalDocumentDiagnostics).GetProjectDiagnosticsAsync(cancellationToken); - - private abstract class DiagnosticGetter( - DiagnosticIncrementalAnalyzer owner, - Solution solution, - ProjectId? projectId, - DocumentId? documentId, - Func>? getDocuments, - bool includeLocalDocumentDiagnostics, - bool includeNonLocalDocumentDiagnostics) + public Task> GetDiagnosticsForIdsAsync(Project project, DocumentId? documentId, ImmutableHashSet? diagnosticIds, Func? shouldIncludeAnalyzer, bool includeLocalDocumentDiagnostics, bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken) { - protected readonly DiagnosticIncrementalAnalyzer Owner = owner; - - protected readonly Solution Solution = solution; - protected readonly ProjectId? ProjectId = projectId ?? documentId?.ProjectId; - protected readonly DocumentId? DocumentId = documentId; - protected readonly bool IncludeLocalDocumentDiagnostics = includeLocalDocumentDiagnostics; - protected readonly bool IncludeNonLocalDocumentDiagnostics = includeNonLocalDocumentDiagnostics; - - private readonly Func> _getDocuments = getDocuments ?? (static (project, documentId) => documentId != null ? [documentId] : project.DocumentIds); - - protected StateManager StateManager => Owner._stateManager; - - protected virtual bool ShouldIncludeDiagnostic(DiagnosticData diagnostic) => true; - - protected abstract Task ProduceDiagnosticsAsync( - Project project, IReadOnlyList documentIds, bool includeProjectNonLocalResult, Action callback, CancellationToken cancellationToken); - - public async Task> GetDiagnosticsAsync(CancellationToken cancellationToken) - { - if (ProjectId != null) - { - var project = Solution.GetProject(ProjectId); - if (project == null) - return []; - - // return diagnostics specific to one project or document - var includeProjectNonLocalResult = DocumentId == null; - return await ProduceProjectDiagnosticsAsync( - [project], project => _getDocuments(project, DocumentId), includeProjectNonLocalResult, cancellationToken).ConfigureAwait(false); - } - - return await ProduceSolutionDiagnosticsAsync(Solution, cancellationToken).ConfigureAwait(false); - } - - protected Task> ProduceSolutionDiagnosticsAsync(Solution solution, CancellationToken cancellationToken) - => ProduceProjectDiagnosticsAsync(solution.Projects, static project => project.DocumentIds, includeProjectNonLocalResult: true, cancellationToken); - - protected async Task> ProduceProjectDiagnosticsAsync( - IEnumerable projects, Func> getDocumentIds, - bool includeProjectNonLocalResult, CancellationToken cancellationToken) - { - // PERF: run projects in parallel rather than running CompilationWithAnalyzer with concurrency == true. - // We do this to not get into thread starvation causing hundreds of threads to be spawned. - return await ProducerConsumer.RunParallelAsync( - source: projects, - produceItems: static (project, callback, args, cancellationToken) => args.@this.ProduceDiagnosticsAsync( - project, args.getDocumentIds(project), args.includeProjectNonLocalResult, callback, cancellationToken), - args: (@this: this, getDocumentIds, includeProjectNonLocalResult), - cancellationToken).ConfigureAwait(false); - } + return ProduceProjectDiagnosticsAsync( + project, diagnosticIds, shouldIncludeAnalyzer, + // Ensure we compute and return diagnostics for both the normal docs and the additional docs in this + // project if no specific document id was requested. + documentId != null ? [documentId] : [.. project.DocumentIds, .. project.AdditionalDocumentIds], + includeLocalDocumentDiagnostics, + includeNonLocalDocumentDiagnostics, + // return diagnostics specific to one project or document + includeProjectNonLocalResult: documentId == null, + cancellationToken); + } - protected void InvokeCallback(Action callback, ImmutableArray diagnostics) - { - foreach (var diagnostic in diagnostics) - { - if (ShouldIncludeDiagnostic(diagnostic)) - callback(diagnostic); - } - } + public Task> GetProjectDiagnosticsForIdsAsync( + Project project, + ImmutableHashSet? diagnosticIds, + Func? shouldIncludeAnalyzer, + bool includeNonLocalDocumentDiagnostics, + CancellationToken cancellationToken) + { + return ProduceProjectDiagnosticsAsync( + project, diagnosticIds, shouldIncludeAnalyzer, + documentIds: [], + includeLocalDocumentDiagnostics: false, + includeNonLocalDocumentDiagnostics: includeNonLocalDocumentDiagnostics, + includeProjectNonLocalResult: true, + cancellationToken); } - private sealed class IdeCachedDiagnosticGetter( - DiagnosticIncrementalAnalyzer owner, - Solution solution, - ProjectId? projectId, - DocumentId? documentId, + private async Task> ProduceProjectDiagnosticsAsync( + Project project, + ImmutableHashSet? diagnosticIds, + Func? shouldIncludeAnalyzer, + IReadOnlyList documentIds, bool includeLocalDocumentDiagnostics, - bool includeNonLocalDocumentDiagnostics) : DiagnosticGetter( - owner, solution, projectId, documentId, getDocuments: null, includeLocalDocumentDiagnostics, includeNonLocalDocumentDiagnostics) + bool includeNonLocalDocumentDiagnostics, + bool includeProjectNonLocalResult, + CancellationToken cancellationToken) { - protected override async Task ProduceDiagnosticsAsync( - Project project, IReadOnlyList documentIds, bool includeProjectNonLocalResult, - Action callback, CancellationToken cancellationToken) - { - foreach (var stateSet in StateManager.GetStateSets(project.Id)) - { - foreach (var documentId in documentIds) - { - if (IncludeLocalDocumentDiagnostics) - { - InvokeCallback(callback, await GetDiagnosticsAsync(stateSet, project, documentId, AnalysisKind.Syntax, cancellationToken).ConfigureAwait(false)); - InvokeCallback(callback, await GetDiagnosticsAsync(stateSet, project, documentId, AnalysisKind.Semantic, cancellationToken).ConfigureAwait(false)); - } - - if (IncludeNonLocalDocumentDiagnostics) - InvokeCallback(callback, await GetDiagnosticsAsync(stateSet, project, documentId, AnalysisKind.NonLocal, cancellationToken).ConfigureAwait(false)); - } - - if (includeProjectNonLocalResult) - { - // include project diagnostics if there is no target document - InvokeCallback(callback, await GetProjectStateDiagnosticsAsync(stateSet, project, documentId: null, AnalysisKind.NonLocal, cancellationToken).ConfigureAwait(false)); - } - } - } - - public async Task> GetSpecificDiagnosticsAsync(DiagnosticAnalyzer analyzer, AnalysisKind analysisKind, CancellationToken cancellationToken) - { - var project = Solution.GetProject(ProjectId); - if (project == null) - { - // when we return cached result, make sure we at least return something that exist in current solution - return []; - } - - var stateSet = await StateManager.GetOrCreateStateSetAsync(project, analyzer, cancellationToken).ConfigureAwait(false); - if (stateSet == null) - { - return []; - } - - var diagnostics = await GetDiagnosticsAsync(stateSet, project, DocumentId, analysisKind, cancellationToken).ConfigureAwait(false); - - return diagnostics; - } - - private static async Task> GetDiagnosticsAsync(StateSet stateSet, Project project, DocumentId? documentId, AnalysisKind kind, CancellationToken cancellationToken) - { - cancellationToken.ThrowIfCancellationRequested(); + using var _ = ArrayBuilder.GetInstance(out var builder); - // active file diagnostics: - if (documentId != null && kind != AnalysisKind.NonLocal && stateSet.TryGetActiveFileState(documentId, out var state)) - { - return state.GetAnalysisData(kind).Items; - } + var solution = project.Solution; + var analyzersForProject = await _stateManager.GetOrCreateAnalyzersAsync( + solution.SolutionState, project.State, cancellationToken).ConfigureAwait(false); + var hostAnalyzerInfo = await _stateManager.GetOrCreateHostAnalyzerInfoAsync( + solution.SolutionState, project.State, cancellationToken).ConfigureAwait(false); + var analyzers = analyzersForProject.WhereAsArray(a => ShouldIncludeAnalyzer(project, a)); - // project diagnostics: - return await GetProjectStateDiagnosticsAsync(stateSet, project, documentId, kind, cancellationToken).ConfigureAwait(false); - } + var result = await GetOrComputeDiagnosticAnalysisResultsAsync(analyzers).ConfigureAwait(false); - private static async Task> GetProjectStateDiagnosticsAsync(StateSet stateSet, Project project, DocumentId? documentId, AnalysisKind kind, CancellationToken cancellationToken) + foreach (var analyzer in analyzers) { - if (!stateSet.TryGetProjectState(project.Id, out var state)) - { - // never analyzed this project yet. - return []; - } + if (!result.TryGetValue(analyzer, out var analysisResult)) + continue; - if (documentId != null) + foreach (var documentId in documentIds) { - // file doesn't exist in current solution - var document = await project.Solution.GetTextDocumentAsync( - documentId, - cancellationToken).ConfigureAwait(false); - - if (document == null) + if (includeLocalDocumentDiagnostics) { - return []; + AddIncludedDiagnostics(builder, analysisResult.GetDocumentDiagnostics(documentId, AnalysisKind.Syntax)); + AddIncludedDiagnostics(builder, analysisResult.GetDocumentDiagnostics(documentId, AnalysisKind.Semantic)); } - var result = await state.GetAnalysisDataAsync(document, avoidLoadingData: false, cancellationToken).ConfigureAwait(false); - return result.GetDocumentDiagnostics(documentId, kind); + if (includeNonLocalDocumentDiagnostics) + AddIncludedDiagnostics(builder, analysisResult.GetDocumentDiagnostics(documentId, AnalysisKind.NonLocal)); } - Contract.ThrowIfFalse(kind == AnalysisKind.NonLocal); - var nonLocalResult = await state.GetProjectAnalysisDataAsync(project, avoidLoadingData: false, cancellationToken: cancellationToken).ConfigureAwait(false); - return nonLocalResult.GetOtherDiagnostics(); + // include project diagnostics if there is no target document + if (includeProjectNonLocalResult) + AddIncludedDiagnostics(builder, analysisResult.GetOtherDiagnostics()); } - } - private sealed class IdeLatestDiagnosticGetter( - DiagnosticIncrementalAnalyzer owner, - Solution solution, - ProjectId? projectId, - DocumentId? documentId, - ImmutableHashSet? diagnosticIds, - Func? shouldIncludeAnalyzer, - Func>? getDocuments, - bool includeLocalDocumentDiagnostics, - bool includeNonLocalDocumentDiagnostics) : DiagnosticGetter( - owner, solution, projectId, documentId, getDocuments, includeLocalDocumentDiagnostics, includeNonLocalDocumentDiagnostics) - { - private readonly ImmutableHashSet? _diagnosticIds = diagnosticIds; - private readonly Func? _shouldIncludeAnalyzer = shouldIncludeAnalyzer; + return builder.ToImmutableAndClear(); - public async Task> GetProjectDiagnosticsAsync(CancellationToken cancellationToken) + bool ShouldIncludeDiagnostic(DiagnosticData diagnostic) + => diagnosticIds == null || diagnosticIds.Contains(diagnostic.Id); + + void AddIncludedDiagnostics(ArrayBuilder builder, ImmutableArray diagnostics) { - if (ProjectId != null) + foreach (var diagnostic in diagnostics) { - var project = Solution.GetProject(ProjectId); - if (project is null) - return []; - - return await ProduceProjectDiagnosticsAsync( - [project], static _ => [], includeProjectNonLocalResult: true, cancellationToken).ConfigureAwait(false); + if (ShouldIncludeDiagnostic(diagnostic)) + builder.Add(diagnostic); } - - return await ProduceSolutionDiagnosticsAsync(Solution, cancellationToken).ConfigureAwait(false); } - protected override bool ShouldIncludeDiagnostic(DiagnosticData diagnostic) - => _diagnosticIds == null || _diagnosticIds.Contains(diagnostic.Id); - - protected override async Task ProduceDiagnosticsAsync( - Project project, IReadOnlyList documentIds, bool includeProjectNonLocalResult, - Action callback, CancellationToken cancellationToken) + async Task> GetOrComputeDiagnosticAnalysisResultsAsync( + ImmutableArray analyzers) { - // get analyzers that are not suppressed. - var stateSetsForProject = await StateManager.GetOrCreateStateSetsAsync(project, cancellationToken).ConfigureAwait(false); - var stateSets = stateSetsForProject.Where(s => ShouldIncludeStateSet(project, s)).ToImmutableArrayOrEmpty(); - - // unlike the suppressed (disabled) analyzer, we will include hidden diagnostic only analyzers here. - var compilation = await CreateCompilationWithAnalyzersAsync(project, stateSets, Owner.AnalyzerService.CrashOnAnalyzerException, cancellationToken).ConfigureAwait(false); - - var result = await Owner.GetProjectAnalysisDataAsync(compilation, project, stateSets, cancellationToken).ConfigureAwait(false); - - foreach (var stateSet in stateSets) + // If there was a 'ForceAnalyzeProjectAsync' run for this project, we can piggy back off of the + // prior computed/cached results as they will be a superset of the results we want. + // + // Note: the caller will loop over *its* analyzers, grabbing from the full set of data we've cached for + // this project, and filtering down further. So it's ok to return this potentially larger set. + // + // Note: While ForceAnalyzeProjectAsync should always run with a larger set of analyzers than us + // (since it runs all analyzers), we still run a paranoia check that the analyzers we care about are + // a subset of that call so that we don't accidentally reuse results that would not correspond to + // what we are computing ourselves. + if (s_projectToForceAnalysisData.TryGetValue(project.State, out var box) && + analyzers.IsSubsetOf(box.Value.analyzers)) { - var analysisResult = result.GetResult(stateSet.Analyzer); - - foreach (var documentId in documentIds) - { - if (IncludeLocalDocumentDiagnostics) - { - InvokeCallback(callback, analysisResult.GetDocumentDiagnostics(documentId, AnalysisKind.Syntax)); - InvokeCallback(callback, analysisResult.GetDocumentDiagnostics(documentId, AnalysisKind.Semantic)); - } + var checksum = await project.GetDiagnosticChecksumAsync(cancellationToken).ConfigureAwait(false); + if (box.Value.checksum == checksum) + return box.Value.diagnosticAnalysisResults; + } - if (IncludeNonLocalDocumentDiagnostics) - InvokeCallback(callback, analysisResult.GetDocumentDiagnostics(documentId, AnalysisKind.NonLocal)); - } + // Otherwise, just compute for the analyzers we care about. + var compilation = await GetOrCreateCompilationWithAnalyzersAsync( + project, analyzers, hostAnalyzerInfo, AnalyzerService.CrashOnAnalyzerException, cancellationToken).ConfigureAwait(false); - if (includeProjectNonLocalResult) - { - // include project diagnostics if there is no target document - InvokeCallback(callback, analysisResult.GetOtherDiagnostics()); - } - } + var result = await ComputeDiagnosticAnalysisResultsAsync(compilation, project, analyzers, cancellationToken).ConfigureAwait(false); + return result; } - private bool ShouldIncludeStateSet(Project project, StateSet stateSet) + bool ShouldIncludeAnalyzer(Project project, DiagnosticAnalyzer analyzer) { - if (!DocumentAnalysisExecutor.IsAnalyzerEnabledForProject(stateSet.Analyzer, project, Owner.GlobalOptions)) - { + if (!DocumentAnalysisExecutor.IsAnalyzerEnabledForProject(analyzer, project, this.GlobalOptions)) return false; - } - if (_shouldIncludeAnalyzer != null && !_shouldIncludeAnalyzer(stateSet.Analyzer)) - { + if (shouldIncludeAnalyzer != null && !shouldIncludeAnalyzer(analyzer)) return false; - } - if (_diagnosticIds != null && Owner.DiagnosticAnalyzerInfoCache.GetDiagnosticDescriptors(stateSet.Analyzer).All(d => !_diagnosticIds.Contains(d.Id))) - { + if (diagnosticIds != null && this.DiagnosticAnalyzerInfoCache.GetDiagnosticDescriptors(analyzer).All(d => !diagnosticIds.Contains(d.Id))) return false; - } return true; } diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.ProjectAndCompilationWithAnalyzers.cs b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.ProjectAndCompilationWithAnalyzers.cs deleted file mode 100644 index df33398ea07c7..0000000000000 --- a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.ProjectAndCompilationWithAnalyzers.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. - -namespace Microsoft.CodeAnalysis.Diagnostics.EngineV2 -{ - internal partial class DiagnosticIncrementalAnalyzer - { - private sealed class ProjectAndCompilationWithAnalyzers - { - public Project Project { get; } - public CompilationWithAnalyzersPair? CompilationWithAnalyzers { get; } - - public ProjectAndCompilationWithAnalyzers(Project project, CompilationWithAnalyzersPair? compilationWithAnalyzers) - { - Project = project; - CompilationWithAnalyzers = compilationWithAnalyzers; - } - } - } -} diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs index 2f48d82960e42..48da4ffee222a 100644 --- a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs +++ b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Linq; @@ -18,231 +17,144 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Diagnostics.EngineV2 +namespace Microsoft.CodeAnalysis.Diagnostics; + +internal partial class DiagnosticAnalyzerService { - internal partial class DiagnosticIncrementalAnalyzer + private partial class DiagnosticIncrementalAnalyzer { + private static async Task>> ComputeDocumentDiagnosticsCoreAsync( + DocumentAnalysisExecutor executor, + CancellationToken cancellationToken) + { + using var _ = PooledDictionary>.GetInstance(out var builder); + foreach (var analyzer in executor.AnalysisScope.ProjectAnalyzers.ConcatFast(executor.AnalysisScope.HostAnalyzers)) + { + var diagnostics = await ComputeDocumentDiagnosticsForAnalyzerCoreAsync(analyzer, executor, cancellationToken).ConfigureAwait(false); + builder.Add(analyzer, diagnostics); + } + + return builder.ToImmutableDictionary(); + } + + private static async Task> ComputeDocumentDiagnosticsForAnalyzerCoreAsync( + DiagnosticAnalyzer analyzer, + DocumentAnalysisExecutor executor, + CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + + var diagnostics = await executor.ComputeDiagnosticsAsync(analyzer, cancellationToken).ConfigureAwait(false); + return diagnostics?.ToImmutableArrayOrEmpty() ?? []; + } + public async Task> GetDiagnosticsForSpanAsync( TextDocument document, TextSpan? range, Func? shouldIncludeDiagnostic, - bool includeCompilerDiagnostics, ICodeActionRequestPriorityProvider priorityProvider, - DiagnosticKind diagnosticKinds, + DiagnosticKind diagnosticKind, bool isExplicit, CancellationToken cancellationToken) { - using var _ = ArrayBuilder.GetInstance(out var list); + var text = await document.GetValueTextAsync(cancellationToken).ConfigureAwait(false); + + var project = document.Project; + var solutionState = project.Solution.SolutionState; + var unfilteredAnalyzers = await _stateManager + .GetOrCreateAnalyzersAsync(solutionState, project.State, cancellationToken) + .ConfigureAwait(false); + var analyzers = unfilteredAnalyzers + .WhereAsArray(a => DocumentAnalysisExecutor.IsAnalyzerEnabledForProject(a, document.Project, GlobalOptions)); + var hostAnalyzerInfo = await _stateManager.GetOrCreateHostAnalyzerInfoAsync(solutionState, project.State, cancellationToken).ConfigureAwait(false); + + // Note that some callers, such as diagnostic tagger, might pass in a range equal to the entire document span. + // We clear out range for such cases as we are computing full document diagnostics. + if (range == new TextSpan(0, text.Length)) + range = null; + + // We log performance info when we are computing diagnostics for a span + var logPerformanceInfo = range.HasValue; + var compilationWithAnalyzers = await GetOrCreateCompilationWithAnalyzersAsync( + document.Project, analyzers, hostAnalyzerInfo, AnalyzerService.CrashOnAnalyzerException, cancellationToken).ConfigureAwait(false); + + // If we are computing full document diagnostics, we will attempt to perform incremental + // member edit analysis. This analysis is currently only enabled with LSP pull diagnostics. + var incrementalAnalysis = !range.HasValue + && document is Document { SupportsSyntaxTree: true }; - var getter = await LatestDiagnosticsForSpanGetter.CreateAsync( - this, document, range, includeCompilerDiagnostics, - priorityProvider, shouldIncludeDiagnostic, diagnosticKinds, isExplicit, cancellationToken).ConfigureAwait(false); - await getter.GetAsync(list, cancellationToken).ConfigureAwait(false); + using var _ = ArrayBuilder.GetInstance(out var list); + await GetAsync(list).ConfigureAwait(false); return list.ToImmutableAndClear(); - } - - /// - /// Get diagnostics for given span either by using cache or calculating it on the spot. - /// - private sealed class LatestDiagnosticsForSpanGetter - { - // PERF: Cache the last Project and corresponding CompilationWithAnalyzers used to compute analyzer diagnostics for span. - // This is now required as async lightbulb will query and execute different priority buckets of analyzers with multiple - // calls, and we want to reuse CompilationWithAnalyzers instance if possible. - private static readonly WeakReference s_lastProjectAndCompilationWithAnalyzers = new(null); - - private readonly DiagnosticIncrementalAnalyzer _owner; - private readonly TextDocument _document; - private readonly SourceText _text; - - private readonly ImmutableArray _stateSets; - private readonly CompilationWithAnalyzersPair? _compilationWithAnalyzers; - - private readonly TextSpan? _range; - private readonly ICodeActionRequestPriorityProvider _priorityProvider; - private readonly Func? _shouldIncludeDiagnostic; - private readonly bool _includeCompilerDiagnostics; - private readonly bool _isExplicit; - private readonly bool _logPerformanceInfo; - private readonly bool _incrementalAnalysis; - private readonly DiagnosticKind _diagnosticKind; - - private delegate Task> DiagnosticsGetterAsync(DiagnosticAnalyzer analyzer, DocumentAnalysisExecutor executor, CancellationToken cancellationToken); - - public static async Task CreateAsync( - DiagnosticIncrementalAnalyzer owner, - TextDocument document, - TextSpan? range, - bool includeCompilerDiagnostics, - ICodeActionRequestPriorityProvider priorityProvider, - Func? shouldIncludeDiagnostic, - DiagnosticKind diagnosticKinds, - bool isExplicit, - CancellationToken cancellationToken) - { - var text = await document.GetValueTextAsync(cancellationToken).ConfigureAwait(false); - var unfilteredStateSets = await owner._stateManager - .GetOrCreateStateSetsAsync(document.Project, cancellationToken) - .ConfigureAwait(false); - var stateSets = unfilteredStateSets - .Where(s => DocumentAnalysisExecutor.IsAnalyzerEnabledForProject(s.Analyzer, document.Project, owner.GlobalOptions)) - .ToImmutableArray(); - - // Note that some callers, such as diagnostic tagger, might pass in a range equal to the entire document span. - // We clear out range for such cases as we are computing full document diagnostics. - if (range == new TextSpan(0, text.Length)) - range = null; - - // We log performance info when we are computing diagnostics for a span - var logPerformanceInfo = range.HasValue; - var compilationWithAnalyzers = await GetOrCreateCompilationWithAnalyzersAsync(document.Project, stateSets, owner.AnalyzerService.CrashOnAnalyzerException, cancellationToken).ConfigureAwait(false); - - // If we are computing full document diagnostics, we will attempt to perform incremental - // member edit analysis. This analysis is currently only enabled with LSP pull diagnostics. - var incrementalAnalysis = !range.HasValue - && document is Document { SupportsSyntaxTree: true }; - - return new LatestDiagnosticsForSpanGetter( - owner, compilationWithAnalyzers, document, text, stateSets, shouldIncludeDiagnostic, includeCompilerDiagnostics, - range, priorityProvider, isExplicit, logPerformanceInfo, incrementalAnalysis, diagnosticKinds); - } - - private static async Task GetOrCreateCompilationWithAnalyzersAsync( - Project project, - ImmutableArray stateSets, - bool crashOnAnalyzerException, - CancellationToken cancellationToken) - { - if (s_lastProjectAndCompilationWithAnalyzers.TryGetTarget(out var projectAndCompilationWithAnalyzers) && - projectAndCompilationWithAnalyzers?.Project == project) - { - if (projectAndCompilationWithAnalyzers.CompilationWithAnalyzers == null) - { - return null; - } - - if (HasAllAnalyzers(stateSets, projectAndCompilationWithAnalyzers.CompilationWithAnalyzers)) - { - return projectAndCompilationWithAnalyzers.CompilationWithAnalyzers; - } - } - - var compilationWithAnalyzers = await CreateCompilationWithAnalyzersAsync(project, stateSets, crashOnAnalyzerException, cancellationToken).ConfigureAwait(false); - s_lastProjectAndCompilationWithAnalyzers.SetTarget(new ProjectAndCompilationWithAnalyzers(project, compilationWithAnalyzers)); - return compilationWithAnalyzers; - - static bool HasAllAnalyzers(IEnumerable stateSets, CompilationWithAnalyzersPair compilationWithAnalyzers) - { - foreach (var stateSet in stateSets) - { - if (stateSet.IsHostAnalyzer && !compilationWithAnalyzers.HostAnalyzers.Contains(stateSet.Analyzer)) - return false; - else if (!stateSet.IsHostAnalyzer && !compilationWithAnalyzers.ProjectAnalyzers.Contains(stateSet.Analyzer)) - return false; - } - return true; - } - } - - private LatestDiagnosticsForSpanGetter( - DiagnosticIncrementalAnalyzer owner, - CompilationWithAnalyzersPair? compilationWithAnalyzers, - TextDocument document, - SourceText text, - ImmutableArray stateSets, - Func? shouldIncludeDiagnostic, - bool includeCompilerDiagnostics, - TextSpan? range, - ICodeActionRequestPriorityProvider priorityProvider, - bool isExplicit, - bool logPerformanceInfo, - bool incrementalAnalysis, - DiagnosticKind diagnosticKind) - { - _owner = owner; - _compilationWithAnalyzers = compilationWithAnalyzers; - _document = document; - _text = text; - _stateSets = stateSets; - _shouldIncludeDiagnostic = shouldIncludeDiagnostic; - _includeCompilerDiagnostics = includeCompilerDiagnostics; - _range = range; - _priorityProvider = priorityProvider; - _isExplicit = isExplicit; - _logPerformanceInfo = logPerformanceInfo; - _incrementalAnalysis = incrementalAnalysis; - _diagnosticKind = diagnosticKind; - } - - public async Task GetAsync(ArrayBuilder list, CancellationToken cancellationToken) + async Task GetAsync(ArrayBuilder list) { try { - // Try to get cached diagnostics, and also compute non-cached state sets that need diagnostic computation. - using var _1 = ArrayBuilder.GetInstance(out var syntaxAnalyzers); + using var _1 = ArrayBuilder.GetInstance(out var syntaxAnalyzers); // If we are performing incremental member edit analysis to compute diagnostics incrementally, // we divide the analyzers into those that support span-based incremental analysis and // those that do not support incremental analysis and must be executed for the entire document. // Otherwise, if we are not performing incremental analysis, all semantic analyzers are added // to the span-based analyzer set as we want to compute diagnostics only for the given span. - using var _2 = ArrayBuilder.GetInstance(out var semanticSpanBasedAnalyzers); - using var _3 = ArrayBuilder.GetInstance(out var semanticDocumentBasedAnalyzers); + using var _2 = ArrayBuilder.GetInstance(out var semanticSpanBasedAnalyzers); + using var _3 = ArrayBuilder.GetInstance(out var semanticDocumentBasedAnalyzers); - using var _4 = TelemetryLogging.LogBlockTimeAggregatedHistogram(FunctionId.RequestDiagnostics_Summary, $"Pri{_priorityProvider.Priority.GetPriorityInt()}"); + using var _4 = TelemetryLogging.LogBlockTimeAggregatedHistogram(FunctionId.RequestDiagnostics_Summary, $"Pri{priorityProvider.Priority.GetPriorityInt()}"); - foreach (var stateSet in _stateSets) + foreach (var analyzer in analyzers) { - var analyzer = stateSet.Analyzer; - if (!ShouldIncludeAnalyzer(analyzer, _shouldIncludeDiagnostic, _priorityProvider, _owner)) + if (!ShouldIncludeAnalyzer(analyzer, shouldIncludeDiagnostic, priorityProvider, this)) continue; bool includeSyntax = true, includeSemantic = true; - if (_diagnosticKind != DiagnosticKind.All) + if (diagnosticKind != DiagnosticKind.All) { var isCompilerAnalyzer = analyzer.IsCompilerAnalyzer(); includeSyntax = isCompilerAnalyzer - ? _diagnosticKind == DiagnosticKind.CompilerSyntax - : _diagnosticKind == DiagnosticKind.AnalyzerSyntax; + ? diagnosticKind == DiagnosticKind.CompilerSyntax + : diagnosticKind == DiagnosticKind.AnalyzerSyntax; includeSemantic = isCompilerAnalyzer - ? _diagnosticKind == DiagnosticKind.CompilerSemantic - : _diagnosticKind == DiagnosticKind.AnalyzerSemantic; + ? diagnosticKind == DiagnosticKind.CompilerSemantic + : diagnosticKind == DiagnosticKind.AnalyzerSemantic; } includeSyntax = includeSyntax && analyzer.SupportAnalysisKind(AnalysisKind.Syntax); - includeSemantic = includeSemantic && analyzer.SupportAnalysisKind(AnalysisKind.Semantic) && _document is Document; + includeSemantic = includeSemantic && analyzer.SupportAnalysisKind(AnalysisKind.Semantic) && document is Document; if (includeSyntax || includeSemantic) { - var state = stateSet.GetOrCreateActiveFileState(_document.Id); - if (includeSyntax) { - var existingData = state.GetAnalysisData(AnalysisKind.Syntax); - if (!await TryAddCachedDocumentDiagnosticsAsync(stateSet.Analyzer, AnalysisKind.Syntax, existingData, list, cancellationToken).ConfigureAwait(false)) - syntaxAnalyzers.Add(new AnalyzerWithState(stateSet.Analyzer, stateSet.IsHostAnalyzer, state, existingData)); + syntaxAnalyzers.Add(analyzer); } if (includeSemantic) { - var existingData = state.GetAnalysisData(AnalysisKind.Semantic); - if (!await TryAddCachedDocumentDiagnosticsAsync(stateSet.Analyzer, AnalysisKind.Semantic, existingData, list, cancellationToken).ConfigureAwait(false)) + if (!incrementalAnalysis) { - var stateSets = GetSemanticAnalysisSelectedStates( - stateSet.Analyzer, _incrementalAnalysis, - semanticSpanBasedAnalyzers, semanticDocumentBasedAnalyzers); - - stateSets.Add(new AnalyzerWithState(stateSet.Analyzer, stateSet.IsHostAnalyzer, state, existingData)); + // For non-incremental analysis, we always attempt to compute all + // analyzer diagnostics for the requested span. + semanticSpanBasedAnalyzers.Add(analyzer); + } + else if (analyzer.SupportsSpanBasedSemanticDiagnosticAnalysis()) + { + // We can perform incremental analysis only for analyzers that support + // span-based semantic diagnostic analysis. + semanticSpanBasedAnalyzers.Add(analyzer); + } + else + { + semanticDocumentBasedAnalyzers.Add(analyzer); } } } } - // Compute diagnostics for non-cached state sets. - await ComputeDocumentDiagnosticsAsync(syntaxAnalyzers.ToImmutable(), AnalysisKind.Syntax, _range, list, incrementalAnalysis: false, cancellationToken).ConfigureAwait(false); - await ComputeDocumentDiagnosticsAsync(semanticSpanBasedAnalyzers.ToImmutable(), AnalysisKind.Semantic, _range, list, _incrementalAnalysis, cancellationToken).ConfigureAwait(false); + await ComputeDocumentDiagnosticsAsync(syntaxAnalyzers.ToImmutable(), AnalysisKind.Syntax, range, list, incrementalAnalysis: false, cancellationToken).ConfigureAwait(false); + await ComputeDocumentDiagnosticsAsync(semanticSpanBasedAnalyzers.ToImmutable(), AnalysisKind.Semantic, range, list, incrementalAnalysis, cancellationToken).ConfigureAwait(false); await ComputeDocumentDiagnosticsAsync(semanticDocumentBasedAnalyzers.ToImmutable(), AnalysisKind.Semantic, span: null, list, incrementalAnalysis: false, cancellationToken).ConfigureAwait(false); return; @@ -251,95 +163,44 @@ public async Task GetAsync(ArrayBuilder list, CancellationToken { throw ExceptionUtilities.Unreachable(); } - - // Local functions - static bool ShouldIncludeAnalyzer( - DiagnosticAnalyzer analyzer, - Func? shouldIncludeDiagnostic, - ICodeActionRequestPriorityProvider priorityProvider, - DiagnosticIncrementalAnalyzer owner) - { - // Skip executing analyzer if its priority does not match the request priority. - if (!priorityProvider.MatchesPriority(analyzer)) - return false; - - // Special case DocumentDiagnosticAnalyzer to never skip these document analyzers - // based on 'shouldIncludeDiagnostic' predicate. More specifically, TS has special document - // analyzer which report 0 supported diagnostics, but we always want to execute it. - if (analyzer is DocumentDiagnosticAnalyzer) - return true; - - // Special case GeneratorDiagnosticsPlaceholderAnalyzer to never skip it based on - // 'shouldIncludeDiagnostic' predicate. More specifically, this is a placeholder analyzer - // for threading through all source generator reported diagnostics, but this special analyzer - // reports 0 supported diagnostics, and we always want to execute it. - if (analyzer is GeneratorDiagnosticsPlaceholderAnalyzer) - return true; - - // Skip analyzer if none of its reported diagnostics should be included. - if (shouldIncludeDiagnostic != null && - !owner.DiagnosticAnalyzerInfoCache.GetDiagnosticDescriptors(analyzer).Any(static (a, shouldIncludeDiagnostic) => shouldIncludeDiagnostic(a.Id), shouldIncludeDiagnostic)) - { - return false; - } - - return true; - } - - static ArrayBuilder GetSemanticAnalysisSelectedStates( - DiagnosticAnalyzer analyzer, - bool incrementalAnalysis, - ArrayBuilder semanticSpanBasedAnalyzers, - ArrayBuilder semanticDocumentBasedAnalyzers) - { - if (!incrementalAnalysis) - { - // For non-incremental analysis, we always attempt to compute all - // analyzer diagnostics for the requested span. - return semanticSpanBasedAnalyzers; - } - else - { - // We can perform incremental analysis only for analyzers that support - // span-based semantic diagnostic analysis. - return analyzer.SupportsSpanBasedSemanticDiagnosticAnalysis() - ? semanticSpanBasedAnalyzers - : semanticDocumentBasedAnalyzers; - } - } } - /// - /// Returns if we were able to add the cached diagnostics and we do not need to compute them fresh. - /// - private async Task TryAddCachedDocumentDiagnosticsAsync( + // Local functions + static bool ShouldIncludeAnalyzer( DiagnosticAnalyzer analyzer, - AnalysisKind kind, - DocumentAnalysisData existingData, - ArrayBuilder list, - CancellationToken cancellationToken) + Func? shouldIncludeDiagnostic, + ICodeActionRequestPriorityProvider priorityProvider, + DiagnosticIncrementalAnalyzer owner) { - Debug.Assert(analyzer.SupportAnalysisKind(kind)); - Debug.Assert(_priorityProvider.MatchesPriority(analyzer)); - - // see whether we can use existing info - var version = await GetDiagnosticVersionAsync(_document.Project, cancellationToken).ConfigureAwait(false); - if (existingData.Version == version) - { - foreach (var item in existingData.Items) - { - if (ShouldInclude(item)) - list.Add(item); - } + // Skip executing analyzer if its priority does not match the request priority. + if (!priorityProvider.MatchesPriority(analyzer)) + return false; + + // Special case DocumentDiagnosticAnalyzer to never skip these document analyzers + // based on 'shouldIncludeDiagnostic' predicate. More specifically, TS has special document + // analyzer which report 0 supported diagnostics, but we always want to execute it. + if (analyzer is DocumentDiagnosticAnalyzer) + return true; + // Special case GeneratorDiagnosticsPlaceholderAnalyzer to never skip it based on + // 'shouldIncludeDiagnostic' predicate. More specifically, this is a placeholder analyzer + // for threading through all source generator reported diagnostics, but this special analyzer + // reports 0 supported diagnostics, and we always want to execute it. + if (analyzer is GeneratorDiagnosticsPlaceholderAnalyzer) return true; + + // Skip analyzer if none of its reported diagnostics should be included. + if (shouldIncludeDiagnostic != null && + !owner.DiagnosticAnalyzerInfoCache.GetDiagnosticDescriptors(analyzer).Any(static (a, shouldIncludeDiagnostic) => shouldIncludeDiagnostic(a.Id), shouldIncludeDiagnostic)) + { + return false; } - return false; + return true; } - private async Task ComputeDocumentDiagnosticsAsync( - ImmutableArray analyzersWithState, + async Task ComputeDocumentDiagnosticsAsync( + ImmutableArray analyzers, AnalysisKind kind, TextSpan? span, ArrayBuilder builder, @@ -347,188 +208,137 @@ private async Task ComputeDocumentDiagnosticsAsync( CancellationToken cancellationToken) { Debug.Assert(!incrementalAnalysis || kind == AnalysisKind.Semantic); - Debug.Assert(!incrementalAnalysis || analyzersWithState.All(analyzerWithState => analyzerWithState.Analyzer.SupportsSpanBasedSemanticDiagnosticAnalysis())); + Debug.Assert(!incrementalAnalysis || analyzers.All(analyzer => analyzer.SupportsSpanBasedSemanticDiagnosticAnalysis())); - using var _ = ArrayBuilder.GetInstance(analyzersWithState.Length, out var filteredAnalyzersWithStateBuilder); - foreach (var analyzerWithState in analyzersWithState) + using var _ = ArrayBuilder.GetInstance(analyzers.Length, out var filteredAnalyzers); + foreach (var analyzer in analyzers) { - Debug.Assert(_priorityProvider.MatchesPriority(analyzerWithState.Analyzer)); + Debug.Assert(priorityProvider.MatchesPriority(analyzer)); // Check if this is an expensive analyzer that needs to be de-prioritized to a lower priority bucket. // If so, we skip this analyzer from execution in the current priority bucket. // We will subsequently execute this analyzer in the lower priority bucket. - if (await TryDeprioritizeAnalyzerAsync(analyzerWithState.Analyzer, analyzerWithState.ExistingData).ConfigureAwait(false)) + if (await TryDeprioritizeAnalyzerAsync(analyzer, kind, span).ConfigureAwait(false)) { continue; } - filteredAnalyzersWithStateBuilder.Add(analyzerWithState); + filteredAnalyzers.Add(analyzer); } - if (filteredAnalyzersWithStateBuilder.Count == 0) + if (filteredAnalyzers.Count == 0) return; - analyzersWithState = filteredAnalyzersWithStateBuilder.ToImmutable(); + analyzers = filteredAnalyzers.ToImmutable(); + + var hostAnalyzerInfo = await _stateManager.GetOrCreateHostAnalyzerInfoAsync(solutionState, project.State, cancellationToken).ConfigureAwait(false); - var projectAnalyzers = analyzersWithState.SelectAsArray(stateSet => !stateSet.IsHostAnalyzer, stateSet => stateSet.Analyzer); - var hostAnalyzers = analyzersWithState.SelectAsArray(stateSet => stateSet.IsHostAnalyzer, stateSet => stateSet.Analyzer); - var analysisScope = new DocumentAnalysisScope(_document, span, projectAnalyzers, hostAnalyzers, kind); - var executor = new DocumentAnalysisExecutor(analysisScope, _compilationWithAnalyzers, _owner._diagnosticAnalyzerRunner, _isExplicit, _logPerformanceInfo); - var version = await GetDiagnosticVersionAsync(_document.Project, cancellationToken).ConfigureAwait(false); + var projectAnalyzers = analyzers.WhereAsArray(static (a, info) => !info.IsHostAnalyzer(a), hostAnalyzerInfo); + var hostAnalyzers = analyzers.WhereAsArray(static (a, info) => info.IsHostAnalyzer(a), hostAnalyzerInfo); + var analysisScope = new DocumentAnalysisScope(document, span, projectAnalyzers, hostAnalyzers, kind); + var executor = new DocumentAnalysisExecutor(analysisScope, compilationWithAnalyzers, _diagnosticAnalyzerRunner, isExplicit, logPerformanceInfo); + var version = await GetDiagnosticVersionAsync(document.Project, cancellationToken).ConfigureAwait(false); ImmutableDictionary> diagnosticsMap; if (incrementalAnalysis) { - using var _2 = TelemetryLogging.LogBlockTimeAggregatedHistogram(FunctionId.RequestDiagnostics_Summary, $"Pri{_priorityProvider.Priority.GetPriorityInt()}.Incremental"); + using var _2 = TelemetryLogging.LogBlockTimeAggregatedHistogram(FunctionId.RequestDiagnostics_Summary, $"Pri{priorityProvider.Priority.GetPriorityInt()}.Incremental"); - diagnosticsMap = await _owner._incrementalMemberEditAnalyzer.ComputeDiagnosticsAsync( + diagnosticsMap = await _incrementalMemberEditAnalyzer.ComputeDiagnosticsAsync( executor, - analyzersWithState, + analyzers, version, - ComputeDocumentDiagnosticsForAnalyzerCoreAsync, - ComputeDocumentDiagnosticsCoreAsync, cancellationToken).ConfigureAwait(false); } else { - using var _2 = TelemetryLogging.LogBlockTimeAggregatedHistogram(FunctionId.RequestDiagnostics_Summary, $"Pri{_priorityProvider.Priority.GetPriorityInt()}.Document"); + using var _2 = TelemetryLogging.LogBlockTimeAggregatedHistogram(FunctionId.RequestDiagnostics_Summary, $"Pri{priorityProvider.Priority.GetPriorityInt()}.Document"); diagnosticsMap = await ComputeDocumentDiagnosticsCoreAsync(executor, cancellationToken).ConfigureAwait(false); } - foreach (var analyzerWithState in analyzersWithState) + foreach (var analyzer in analyzers) { - var diagnostics = diagnosticsMap[analyzerWithState.Analyzer]; + var diagnostics = diagnosticsMap[analyzer]; builder.AddRange(diagnostics.Where(ShouldInclude)); } if (incrementalAnalysis) - _owner._incrementalMemberEditAnalyzer.UpdateDocumentWithCachedDiagnostics((Document)_document); + _incrementalMemberEditAnalyzer.UpdateDocumentWithCachedDiagnostics((Document)document); + } - async Task TryDeprioritizeAnalyzerAsync(DiagnosticAnalyzer analyzer, DocumentAnalysisData existingData) + async Task TryDeprioritizeAnalyzerAsync( + DiagnosticAnalyzer analyzer, AnalysisKind kind, TextSpan? span) + { + // PERF: In order to improve lightbulb performance, we perform de-prioritization optimization for certain analyzers + // that moves the analyzer to a lower priority bucket. However, to ensure that de-prioritization happens for very rare cases, + // we only perform this optimizations when following conditions are met: + // 1. We are performing semantic span-based analysis. + // 2. We are processing 'CodeActionRequestPriority.Normal' priority request. + // 3. Analyzer registers certain actions that are known to lead to high performance impact due to its broad analysis scope, + // such as SymbolStart/End actions and SemanticModel actions. + // 4. Analyzer did not report a diagnostic on the same line in prior document snapshot. + + // Conditions 1. and 2. + if (kind != AnalysisKind.Semantic || + !span.HasValue || + priorityProvider.Priority != CodeActionRequestPriority.Default) { - // PERF: In order to improve lightbulb performance, we perform de-prioritization optimization for certain analyzers - // that moves the analyzer to a lower priority bucket. However, to ensure that de-prioritization happens for very rare cases, - // we only perform this optimizations when following conditions are met: - // 1. We are performing semantic span-based analysis. - // 2. We are processing 'CodeActionRequestPriority.Normal' priority request. - // 3. Analyzer registers certain actions that are known to lead to high performance impact due to its broad analysis scope, - // such as SymbolStart/End actions and SemanticModel actions. - // 4. Analyzer did not report a diagnostic on the same line in prior document snapshot. - - // Conditions 1. and 2. - if (kind != AnalysisKind.Semantic || - !span.HasValue || - _priorityProvider.Priority != CodeActionRequestPriority.Default) - { - return false; - } - - Debug.Assert(span.Value.Length < _text.Length); - - // Condition 3. - // Check if this is a candidate analyzer that can be de-prioritized into a lower priority bucket based on registered actions. - if (!await IsCandidateForDeprioritizationBasedOnRegisteredActionsAsync(analyzer).ConfigureAwait(false)) - { - return false; - } - - // Condition 4. - // We do not want to de-prioritize this analyzer if it reported a diagnostic on a prior document snapshot, - // such that diagnostic's start/end lines intersect the current analysis span's start/end lines. - // If an analyzer reported such a diagnostic, it is highly likely that the user intends to invoke the code fix - // for this diagnostic. Additionally, it is also highly likely that this analyzer will report a diagnostic - // on the current snapshot. So, we deem this as an important analyzer that should not be de-prioritized here. - // Note that we only perform this analysis if the prior document, whose existingData is cached, had same number - // of source lines as the current document snapshot. Otherwise, the start/end lines comparison across - // snapshots is not meaningful. - if (existingData.LineCount == _text.Lines.Count && - !existingData.Items.IsEmpty) - { - _text.GetLinesAndOffsets(span.Value, out var startLineNumber, out var _, out var endLineNumber, out var _); - - foreach (var diagnostic in existingData.Items) - { - if (diagnostic.DataLocation.UnmappedFileSpan.StartLinePosition.Line <= endLineNumber && - diagnostic.DataLocation.UnmappedFileSpan.EndLinePosition.Line >= startLineNumber) - { - return false; - } - } - } - - // 'LightbulbSkipExecutingDeprioritizedAnalyzers' option determines if we want to execute this analyzer - // in low priority bucket or skip it completely. If the option is not set, track the de-prioritized - // analyzer to be executed in low priority bucket. - // Note that 'AddDeprioritizedAnalyzerWithLowPriority' call below mutates the state in the provider to - // track this analyzer. This ensures that when the owner of this provider calls us back to execute - // the low priority bucket, we can still get back to this analyzer and execute it that time. - if (!_owner.GlobalOptions.GetOption(DiagnosticOptionsStorage.LightbulbSkipExecutingDeprioritizedAnalyzers)) - _priorityProvider.AddDeprioritizedAnalyzerWithLowPriority(analyzer); - - return true; + return false; } - // Returns true if this is an analyzer that is a candidate to be de-prioritized to - // 'CodeActionRequestPriority.Low' priority for improvement in analyzer - // execution performance for priority buckets above 'Low' priority. - // Based on performance measurements, currently only analyzers which register SymbolStart/End actions - // or SemanticModel actions are considered candidates to be de-prioritized. However, these semantics - // could be changed in future based on performance measurements. - async Task IsCandidateForDeprioritizationBasedOnRegisteredActionsAsync(DiagnosticAnalyzer analyzer) + Debug.Assert(span.Value.Length < text.Length); + + // Condition 3. + // Check if this is a candidate analyzer that can be de-prioritized into a lower priority bucket based on registered actions. + if (!await IsCandidateForDeprioritizationBasedOnRegisteredActionsAsync(analyzer).ConfigureAwait(false)) { - // We deprioritize SymbolStart/End and SemanticModel analyzers from 'Normal' to 'Low' priority bucket, - // as these are computationally more expensive. - // Note that we never de-prioritize compiler analyzer, even though it registers a SemanticModel action. - if (_compilationWithAnalyzers == null || - analyzer.IsWorkspaceDiagnosticAnalyzer() || - analyzer.IsCompilerAnalyzer()) - { - return false; - } + return false; + } - var telemetryInfo = await _compilationWithAnalyzers.GetAnalyzerTelemetryInfoAsync(analyzer, cancellationToken).ConfigureAwait(false); - if (telemetryInfo == null) - return false; + // 'LightbulbSkipExecutingDeprioritizedAnalyzers' option determines if we want to execute this analyzer + // in low priority bucket or skip it completely. If the option is not set, track the de-prioritized + // analyzer to be executed in low priority bucket. + // Note that 'AddDeprioritizedAnalyzerWithLowPriority' call below mutates the state in the provider to + // track this analyzer. This ensures that when the owner of this provider calls us back to execute + // the low priority bucket, we can still get back to this analyzer and execute it that time. + if (!this.GlobalOptions.GetOption(DiagnosticOptionsStorage.LightbulbSkipExecutingDeprioritizedAnalyzers)) + priorityProvider.AddDeprioritizedAnalyzerWithLowPriority(analyzer); - return telemetryInfo.SymbolStartActionsCount > 0 || telemetryInfo.SemanticModelActionsCount > 0; - } + return true; } - private async Task>> ComputeDocumentDiagnosticsCoreAsync( - DocumentAnalysisExecutor executor, - CancellationToken cancellationToken) + // Returns true if this is an analyzer that is a candidate to be de-prioritized to + // 'CodeActionRequestPriority.Low' priority for improvement in analyzer + // execution performance for priority buckets above 'Low' priority. + // Based on performance measurements, currently only analyzers which register SymbolStart/End actions + // or SemanticModel actions are considered candidates to be de-prioritized. However, these semantics + // could be changed in future based on performance measurements. + async Task IsCandidateForDeprioritizationBasedOnRegisteredActionsAsync(DiagnosticAnalyzer analyzer) { - using var _ = PooledDictionary>.GetInstance(out var builder); - foreach (var analyzer in executor.AnalysisScope.ProjectAnalyzers.ConcatFast(executor.AnalysisScope.HostAnalyzers)) + // We deprioritize SymbolStart/End and SemanticModel analyzers from 'Normal' to 'Low' priority bucket, + // as these are computationally more expensive. + // Note that we never de-prioritize compiler analyzer, even though it registers a SemanticModel action. + if (compilationWithAnalyzers == null || + analyzer.IsWorkspaceDiagnosticAnalyzer() || + analyzer.IsCompilerAnalyzer()) { - var diagnostics = await ComputeDocumentDiagnosticsForAnalyzerCoreAsync(analyzer, executor, cancellationToken).ConfigureAwait(false); - builder.Add(analyzer, diagnostics); + return false; } - return builder.ToImmutableDictionary(); - } - - private async Task> ComputeDocumentDiagnosticsForAnalyzerCoreAsync( - DiagnosticAnalyzer analyzer, - DocumentAnalysisExecutor executor, - CancellationToken cancellationToken) - { - cancellationToken.ThrowIfCancellationRequested(); + var telemetryInfo = await compilationWithAnalyzers.GetAnalyzerTelemetryInfoAsync(analyzer, cancellationToken).ConfigureAwait(false); + if (telemetryInfo == null) + return false; - var diagnostics = await executor.ComputeDiagnosticsAsync(analyzer, cancellationToken).ConfigureAwait(false); - return diagnostics?.ToImmutableArrayOrEmpty() ?? []; + return telemetryInfo.SymbolStartActionsCount > 0 || telemetryInfo.SemanticModelActionsCount > 0; } - private bool ShouldInclude(DiagnosticData diagnostic) + bool ShouldInclude(DiagnosticData diagnostic) { - return diagnostic.DocumentId == _document.Id && - (_range == null || _range.Value.IntersectsWith(diagnostic.DataLocation.UnmappedFileSpan.GetClampedTextSpan(_text))) - && (_includeCompilerDiagnostics || !diagnostic.CustomTags.Any(static t => t is WellKnownDiagnosticTags.Compiler)) - && (_shouldIncludeDiagnostic == null || _shouldIncludeDiagnostic(diagnostic.Id)); + return diagnostic.DocumentId == document.Id && + (range == null || range.Value.IntersectsWith(diagnostic.DataLocation.UnmappedFileSpan.GetClampedTextSpan(text))) + && (shouldIncludeDiagnostic == null || shouldIncludeDiagnostic(diagnostic.Id)); } } - - private sealed record class AnalyzerWithState(DiagnosticAnalyzer Analyzer, bool IsHostAnalyzer, ActiveFileState State, DocumentAnalysisData ExistingData); } } diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs index 93ba079476f40..dca653cd27e24 100644 --- a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs +++ b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs @@ -4,50 +4,65 @@ using System; using System.Collections.Immutable; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.ErrorReporting; -using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.SolutionCrawler; -using Roslyn.Utilities; +using Microsoft.CodeAnalysis.Workspaces.Diagnostics; -namespace Microsoft.CodeAnalysis.Diagnostics.EngineV2 +namespace Microsoft.CodeAnalysis.Diagnostics; + +internal partial class DiagnosticAnalyzerService { - internal partial class DiagnosticIncrementalAnalyzer + private partial class DiagnosticIncrementalAnalyzer { + /// + /// Cached data from a real instance to the cached diagnostic data produced by + /// all the analyzers for the project. This data can then be used by to speed up subsequent calls through the normal entry points as long as the project hasn't changed at all. + /// + /// + /// This table is keyed off of but stores data from on + /// it. Specifically . Normally keying off a ProjectState would not be ok + /// as the ProjectState might stay the same while the SolutionState changed. However, that can't happen as + /// SolutionState has the data for Analyzers computed prior to Projects being added, and then never changes. + /// Practically, solution analyzers are the core Roslyn analyzers themselves we distribute, or analyzers shipped + /// by vsix (not nuget). These analyzers do not get loaded after changing *until* VS restarts. + /// + private static readonly ConditionalWeakTable analyzers, ImmutableDictionary diagnosticAnalysisResults)>> s_projectToForceAnalysisData = new(); + public async Task> ForceAnalyzeProjectAsync(Project project, CancellationToken cancellationToken) { + var projectState = project.State; + var checksum = await project.GetDiagnosticChecksumAsync(cancellationToken).ConfigureAwait(false); + try { - var stateSetsForProject = await _stateManager.GetOrCreateStateSetsAsync(project, cancellationToken).ConfigureAwait(false); - var stateSets = GetStateSetsForFullSolutionAnalysis(stateSetsForProject, project); - - // PERF: get analyzers that are not suppressed and marked as open file only - // this is perf optimization. we cache these result since we know the result. (no diagnostics) - var activeProjectAnalyzers = stateSets.SelectAsArray(s => !s.IsHostAnalyzer, s => s.Analyzer); - var activeHostAnalyzers = stateSets.SelectAsArray(s => s.IsHostAnalyzer, s => s.Analyzer); - - CompilationWithAnalyzersPair? compilationWithAnalyzers = null; - - compilationWithAnalyzers = await DocumentAnalysisExecutor.CreateCompilationWithAnalyzersAsync( - project, activeProjectAnalyzers, activeHostAnalyzers, AnalyzerService.CrashOnAnalyzerException, cancellationToken).ConfigureAwait(false); - - var result = await GetProjectAnalysisDataAsync(compilationWithAnalyzers, project, stateSets, cancellationToken).ConfigureAwait(false); + if (!s_projectToForceAnalysisData.TryGetValue(projectState, out var box) || + box.Value.checksum != checksum) + { + box = new(await ComputeForceAnalyzeProjectAsync().ConfigureAwait(false)); + + // Try to add the new computed data to the CWT. But use any existing value that another thread + // might have beaten us to storing in it. +#if NET + if (!s_projectToForceAnalysisData.TryAdd(projectState, box)) + Contract.ThrowIfFalse(s_projectToForceAnalysisData.TryGetValue(projectState, out box)); +#else + box = s_projectToForceAnalysisData.GetValue(projectState, _ => box); +#endif + } using var _ = ArrayBuilder.GetInstance(out var diagnostics); - // no cancellation after this point. - foreach (var stateSet in stateSets) + var (_, analyzers, projectAnalysisData) = box.Value; + foreach (var analyzer in analyzers) { - var state = stateSet.GetOrCreateProjectState(project.Id); - - if (result.TryGetResult(stateSet.Analyzer, out var analyzerResult)) - { + if (projectAnalysisData.TryGetValue(analyzer, out var analyzerResult)) diagnostics.AddRange(analyzerResult.GetAllDiagnostics()); - await state.SaveToInMemoryStorageAsync(project, analyzerResult).ConfigureAwait(false); - } } return diagnostics.ToImmutableAndClear(); @@ -56,104 +71,68 @@ public async Task> ForceAnalyzeProjectAsync(Proje { throw ExceptionUtilities.Unreachable(); } - } - private async Task TextDocumentOpenAsync(TextDocument document, CancellationToken cancellationToken) - { - using (Logger.LogBlock(FunctionId.Diagnostics_DocumentOpen, GetOpenLogMessage, document, cancellationToken)) + async Task<(Checksum checksum, ImmutableArray analyzers, ImmutableDictionary diagnosticAnalysisResults)> ComputeForceAnalyzeProjectAsync() { - var stateSets = _stateManager.GetStateSets(document.Project); + var solutionState = project.Solution.SolutionState; + var allAnalyzers = await _stateManager.GetOrCreateAnalyzersAsync(solutionState, projectState, cancellationToken).ConfigureAwait(false); + var hostAnalyzerInfo = await _stateManager.GetOrCreateHostAnalyzerInfoAsync(solutionState, projectState, cancellationToken).ConfigureAwait(false); - // can not be canceled - foreach (var stateSet in stateSets) - await stateSet.OnDocumentOpenedAsync(document).ConfigureAwait(false); - } - } + var fullSolutionAnalysisAnalyzers = allAnalyzers.WhereAsArray( + static (analyzer, arg) => IsCandidateForFullSolutionAnalysis( + arg.self.DiagnosticAnalyzerInfoCache, analyzer, arg.hostAnalyzerInfo.IsHostAnalyzer(analyzer), arg.project), + (self: this, project, hostAnalyzerInfo)); - /// - /// Return list of to be used for full solution analysis. - /// - private ImmutableArray GetStateSetsForFullSolutionAnalysis(ImmutableArray stateSets, Project project) - { - // If full analysis is off, remove state that is created from build. - // this will make sure diagnostics from build (converted from build to live) will never be cleared - // until next build. - _ = GlobalOptions.IsFullSolutionAnalysisEnabled(project.Language, out var compilerFullSolutionAnalysisEnabled, out var analyzersFullSolutionAnalysisEnabled); - if (!compilerFullSolutionAnalysisEnabled) - { - // Full solution analysis is not enabled for compiler diagnostics, - // so we remove the compiler analyzer state sets that are from build. - // We do so by retaining only those state sets that are - // either not for compiler analyzer or those which are for compiler - // analyzer, but not from build. - stateSets = stateSets.WhereAsArray(s => !s.Analyzer.IsCompilerAnalyzer() || !s.FromBuild(project.Id)); - } + var compilationWithAnalyzers = await GetOrCreateCompilationWithAnalyzersAsync( + project, fullSolutionAnalysisAnalyzers, hostAnalyzerInfo, AnalyzerService.CrashOnAnalyzerException, cancellationToken).ConfigureAwait(false); - if (!analyzersFullSolutionAnalysisEnabled) - { - // Full solution analysis is not enabled for analyzer diagnostics, - // so we remove the analyzer state sets that are from build. - // We do so by retaining only those state sets that are - // either for the special compiler/workspace analyzers or those which are for - // other analyzers, but not from build. - stateSets = stateSets.WhereAsArray(s => s.Analyzer.IsCompilerAnalyzer() || s.Analyzer.IsWorkspaceDiagnosticAnalyzer() || !s.FromBuild(project.Id)); + var projectAnalysisData = await ComputeDiagnosticAnalysisResultsAsync(compilationWithAnalyzers, project, fullSolutionAnalysisAnalyzers, cancellationToken).ConfigureAwait(false); + return (checksum, fullSolutionAnalysisAnalyzers, projectAnalysisData); } - // Include only analyzers we want to run for full solution analysis. - // Analyzers not included here will never be saved because result is unknown. - return stateSets.WhereAsArray(static (s, arg) => arg.self.IsCandidateForFullSolutionAnalysis(s.Analyzer, s.IsHostAnalyzer, arg.project), (self: this, project)); - } - - private bool IsCandidateForFullSolutionAnalysis(DiagnosticAnalyzer analyzer, bool isHostAnalyzer, Project project) - { - // PERF: Don't query descriptors for compiler analyzer or workspace load analyzer, always execute them. - if (analyzer == FileContentLoadAnalyzer.Instance || - analyzer == GeneratorDiagnosticsPlaceholderAnalyzer.Instance || - analyzer.IsCompilerAnalyzer()) - { - return true; - } - - if (analyzer.IsBuiltInAnalyzer()) + static bool IsCandidateForFullSolutionAnalysis( + DiagnosticAnalyzerInfoCache infoCache, DiagnosticAnalyzer analyzer, bool isHostAnalyzer, Project project) { - // always return true for builtin analyzer. we can't use - // descriptor check since many builtin analyzer always return - // hidden descriptor regardless what descriptor it actually - // return on runtime. they do this so that they can control - // severity through option page rather than rule set editor. - // this is special behavior only ide analyzer can do. we hope - // once we support editorconfig fully, third party can use this - // ability as well and we can remove this kind special treatment on builtin - // analyzer. - return true; - } - - if (analyzer is DiagnosticSuppressor) - { - // Always execute diagnostic suppressors. - return true; - } + // PERF: Don't query descriptors for compiler analyzer or workspace load analyzer, always execute them. + if (analyzer == FileContentLoadAnalyzer.Instance || + analyzer == GeneratorDiagnosticsPlaceholderAnalyzer.Instance || + analyzer.IsCompilerAnalyzer()) + { + return true; + } - if (project.CompilationOptions is null) - { - // Skip compilation options based checks for non-C#/VB projects. - return true; - } + if (analyzer.IsBuiltInAnalyzer()) + { + // always return true for builtin analyzer. we can't use + // descriptor check since many builtin analyzer always return + // hidden descriptor regardless what descriptor it actually + // return on runtime. they do this so that they can control + // severity through option page rather than rule set editor. + // this is special behavior only ide analyzer can do. we hope + // once we support editorconfig fully, third party can use this + // ability as well and we can remove this kind special treatment on builtin + // analyzer. + return true; + } - // For most of analyzers, the number of diagnostic descriptors is small, so this should be cheap. - var descriptors = DiagnosticAnalyzerInfoCache.GetDiagnosticDescriptors(analyzer); - var analyzerConfigOptions = project.GetAnalyzerConfigOptions(); + if (analyzer is DiagnosticSuppressor) + { + // Always execute diagnostic suppressors. + return true; + } - return descriptors.Any(static (d, arg) => d.GetEffectiveSeverity(arg.CompilationOptions, arg.isHostAnalyzer ? arg.analyzerConfigOptions?.ConfigOptionsWithFallback : arg.analyzerConfigOptions?.ConfigOptionsWithoutFallback, arg.analyzerConfigOptions?.TreeOptions) != ReportDiagnostic.Hidden, (project.CompilationOptions, isHostAnalyzer, analyzerConfigOptions)); - } + if (project.CompilationOptions is null) + { + // Skip compilation options based checks for non-C#/VB projects. + return true; + } - public TestAccessor GetTestAccessor() - => new(this); + // For most of analyzers, the number of diagnostic descriptors is small, so this should be cheap. + var descriptors = infoCache.GetDiagnosticDescriptors(analyzer); + var analyzerConfigOptions = project.GetAnalyzerConfigOptions(); - public readonly struct TestAccessor(DiagnosticIncrementalAnalyzer diagnosticIncrementalAnalyzer) - { - public Task TextDocumentOpenAsync(TextDocument document) - => diagnosticIncrementalAnalyzer.TextDocumentOpenAsync(document, CancellationToken.None); + return descriptors.Any(static (d, arg) => d.GetEffectiveSeverity(arg.CompilationOptions, arg.isHostAnalyzer ? arg.analyzerConfigOptions?.ConfigOptionsWithFallback : arg.analyzerConfigOptions?.ConfigOptionsWithoutFallback, arg.analyzerConfigOptions?.TreeOptions) != ReportDiagnostic.Hidden, (project.CompilationOptions, isHostAnalyzer, analyzerConfigOptions)); + } } } } diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.InProcOrRemoteHostAnalyzerRunner.cs b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/InProcOrRemoteHostAnalyzerRunner.cs similarity index 96% rename from src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.InProcOrRemoteHostAnalyzerRunner.cs rename to src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/InProcOrRemoteHostAnalyzerRunner.cs index 3fced9e7cdeff..d43c3016d6487 100644 --- a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.InProcOrRemoteHostAnalyzerRunner.cs +++ b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/InProcOrRemoteHostAnalyzerRunner.cs @@ -9,7 +9,6 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Diagnostics.EngineV2; using Microsoft.CodeAnalysis.Diagnostics.Telemetry; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host; @@ -120,8 +119,6 @@ private async Task.Empty; if (analysisResult is not null) { var map = await analysisResult.ToResultBuilderMapAsync( - additionalPragmaSuppressionDiagnostics, documentAnalysisScope, project, version, + additionalPragmaSuppressionDiagnostics, documentAnalysisScope, project, projectAnalyzers, hostAnalyzers, skippedAnalyzersInfo, cancellationToken).ConfigureAwait(false); builderMap = builderMap.AddRange(map); } @@ -237,9 +234,6 @@ private static async Task.Empty; } - // handling of cancellation and exception - var version = await DiagnosticIncrementalAnalyzer.GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false); - var documentIds = (documentAnalysisScope != null) ? ImmutableHashSet.Create(documentAnalysisScope.TextDocument.Id) : null; return new DiagnosticAnalysisResultMap( @@ -247,7 +241,6 @@ private static async Task IReadOnlyDictionaryExtensions.GetValueOrDefault(projectAnalyzerMap, entry.analyzerId) ?? hostAnalyzerMap[entry.analyzerId], entry => DiagnosticAnalysisResult.Create( project, - version, syntaxLocalMap: Hydrate(entry.diagnosticMap.Syntax, project), semanticLocalMap: Hydrate(entry.diagnosticMap.Semantic, project), nonLocalMap: Hydrate(entry.diagnosticMap.NonLocal, project), diff --git a/src/LanguageServer/Protocol/Features/Options/CompletionOptionsStorage.cs b/src/LanguageServer/Protocol/Features/Options/CompletionOptionsStorage.cs index 2b237f5da50c6..f13c52f605e52 100644 --- a/src/LanguageServer/Protocol/Features/Options/CompletionOptionsStorage.cs +++ b/src/LanguageServer/Protocol/Features/Options/CompletionOptionsStorage.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 Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Completion; diff --git a/src/LanguageServer/Protocol/Features/Options/MetadataAsSourceOptionsStorage.cs b/src/LanguageServer/Protocol/Features/Options/MetadataAsSourceOptionsStorage.cs index 082f776c6cd01..328d5b4c4a9bd 100644 --- a/src/LanguageServer/Protocol/Features/Options/MetadataAsSourceOptionsStorage.cs +++ b/src/LanguageServer/Protocol/Features/Options/MetadataAsSourceOptionsStorage.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.MetadataAsSource; diff --git a/src/LanguageServer/Protocol/Features/Options/SolutionAnalyzerConfigOptionsUpdater.cs b/src/LanguageServer/Protocol/Features/Options/SolutionAnalyzerConfigOptionsUpdater.cs index 1dc7cc10b0682..035ab2a6a70a7 100644 --- a/src/LanguageServer/Protocol/Features/Options/SolutionAnalyzerConfigOptionsUpdater.cs +++ b/src/LanguageServer/Protocol/Features/Options/SolutionAnalyzerConfigOptionsUpdater.cs @@ -10,7 +10,6 @@ using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; @@ -27,9 +26,9 @@ namespace Microsoft.CodeAnalysis.Options; [WorkspaceKind.Host, WorkspaceKind.Interactive, WorkspaceKind.SemanticSearch, WorkspaceKind.MetadataAsSource, WorkspaceKind.MiscellaneousFiles, WorkspaceKind.Debugger, WorkspaceKind.Preview]), Shared] [method: ImportingConstructor] [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] -internal sealed class SolutionAnalyzerConfigOptionsUpdater(IGlobalOptionService globalOptions) : IEventListener, IEventListenerStoppable +internal sealed class SolutionAnalyzerConfigOptionsUpdater(IGlobalOptionService globalOptions) : IEventListener { - public void StartListening(Workspace workspace, object serviceOpt) + public void StartListening(Workspace workspace) => globalOptions.AddOptionChangedHandler(workspace, GlobalOptionsChanged); public void StopListening(Workspace workspace) diff --git a/src/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs b/src/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs index 7aefa3a7e94b5..57a1713b4640f 100644 --- a/src/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs +++ b/src/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs @@ -208,7 +208,7 @@ static CodeFixGroupKey GetGroupKey(CodeFix fix) private static async Task GetUnifiedFixAllSuggestedActionSetAsync( CodeAction action, int actionCount, - IFixAllState fixAllState, + IFixAllState? fixAllState, ImmutableArray supportedScopes, Diagnostic firstDiagnostic, Workspace workspace, diff --git a/src/LanguageServer/Protocol/Handler/AbstractRefreshQueue.cs b/src/LanguageServer/Protocol/Handler/AbstractRefreshQueue.cs index 5eec735c049bd..f4b0498caabc9 100644 --- a/src/LanguageServer/Protocol/Handler/AbstractRefreshQueue.cs +++ b/src/LanguageServer/Protocol/Handler/AbstractRefreshQueue.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Threading; using Roslyn.LanguageServer.Protocol; using Roslyn.Utilities; using StreamJsonRpc; diff --git a/src/LanguageServer/Protocol/Handler/BufferedProgress.cs b/src/LanguageServer/Protocol/Handler/BufferedProgress.cs index 2b13dfbae3c75..f2f79c51c04ca 100644 --- a/src/LanguageServer/Protocol/Handler/BufferedProgress.cs +++ b/src/LanguageServer/Protocol/Handler/BufferedProgress.cs @@ -5,7 +5,6 @@ using System; using System.Linq; using Microsoft.CodeAnalysis.PooledObjects; -using Roslyn.LanguageServer.Protocol; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.Handler diff --git a/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionFixAllResolveHandler.cs b/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionFixAllResolveHandler.cs index 2677137bf9096..d6adf6f910466 100644 --- a/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionFixAllResolveHandler.cs +++ b/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionFixAllResolveHandler.cs @@ -7,13 +7,11 @@ using System.Text.Json; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Roslyn.LanguageServer.Protocol; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.Handler.CodeActions; diff --git a/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs b/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs index 06a2c81bc987d..139e4fac2aeb9 100644 --- a/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs +++ b/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs @@ -13,7 +13,6 @@ using Microsoft.CodeAnalysis.LanguageServer.Handler.CodeActions; using Microsoft.CodeAnalysis.Options; using Roslyn.LanguageServer.Protocol; -using Roslyn.Utilities; using LSP = Roslyn.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.LanguageServer.Handler; diff --git a/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionsHandler.cs b/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionsHandler.cs index 87ef08b73bbcb..9f50e473f0af2 100644 --- a/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionsHandler.cs +++ b/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionsHandler.cs @@ -6,7 +6,6 @@ using System.Composition; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Host.Mef; diff --git a/src/LanguageServer/Protocol/Handler/CodeLens/CodeLensRefreshQueue.cs b/src/LanguageServer/Protocol/Handler/CodeLens/CodeLensRefreshQueue.cs index 9bb330e69a890..da7c9b800f48c 100644 --- a/src/LanguageServer/Protocol/Handler/CodeLens/CodeLensRefreshQueue.cs +++ b/src/LanguageServer/Protocol/Handler/CodeLens/CodeLensRefreshQueue.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.Linq; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; using Roslyn.LanguageServer.Protocol; diff --git a/src/LanguageServer/Protocol/Handler/CodeLens/CodeLensResolveHandler.cs b/src/LanguageServer/Protocol/Handler/CodeLens/CodeLensResolveHandler.cs index 0064c37cc88ba..e1d2a15d95d8d 100644 --- a/src/LanguageServer/Protocol/Handler/CodeLens/CodeLensResolveHandler.cs +++ b/src/LanguageServer/Protocol/Handler/CodeLens/CodeLensResolveHandler.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.CodeLens; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; using StreamJsonRpc; using LSP = Roslyn.LanguageServer.Protocol; diff --git a/src/LanguageServer/Protocol/Handler/Completion/CompletionCapabilityHelper.cs b/src/LanguageServer/Protocol/Handler/Completion/CompletionCapabilityHelper.cs index 6ed2dfe1ef6f1..aefec686e77a4 100644 --- a/src/LanguageServer/Protocol/Handler/Completion/CompletionCapabilityHelper.cs +++ b/src/LanguageServer/Protocol/Handler/Completion/CompletionCapabilityHelper.cs @@ -28,6 +28,7 @@ internal sealed class CompletionCapabilityHelper public bool SupportsMarkdownDocumentation { get; } public ISet SupportedItemKinds { get; } public ISet SupportedItemTags { get; } + public ISet SupportedInsertTextModes { get; } public CompletionCapabilityHelper(ClientCapabilities clientCapabilities) : this(supportsVSExtensions: clientCapabilities.HasVisualStudioLspCapability(), @@ -45,6 +46,7 @@ public CompletionCapabilityHelper(bool supportsVSExtensions, CompletionSetting? SupportDefaultCommitCharacters = completionSetting?.CompletionListSetting?.ItemDefaults?.Contains(CommitCharactersPropertyName) == true; SupportedItemKinds = completionSetting?.CompletionItemKind?.ValueSet?.ToSet() ?? SpecializedCollections.EmptySet(); SupportedItemTags = completionSetting?.CompletionItem?.TagSupport?.ValueSet?.ToSet() ?? SpecializedCollections.EmptySet(); + SupportedInsertTextModes = completionSetting?.CompletionItem?.InsertTextModeSupport?.ValueSet?.ToSet() ?? SpecializedCollections.EmptySet(); // internal VS LSP if (supportsVSExtensions) diff --git a/src/LanguageServer/Protocol/Handler/Completion/CompletionHandler.cs b/src/LanguageServer/Protocol/Handler/Completion/CompletionHandler.cs index 050bfd25f152e..de282a9c35fb2 100644 --- a/src/LanguageServer/Protocol/Handler/Completion/CompletionHandler.cs +++ b/src/LanguageServer/Protocol/Handler/Completion/CompletionHandler.cs @@ -3,10 +3,8 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Composition; -using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -68,7 +66,7 @@ public CompletionHandler( cancellationToken).ConfigureAwait(false); } - public static async Task GetCompletionListAsync( + public static async Task GetCompletionListAsync( Document document, int position, LSP.CompletionContext? completionContext, diff --git a/src/LanguageServer/Protocol/Handler/Completion/CompletionResultFactory.cs b/src/LanguageServer/Protocol/Handler/Completion/CompletionResultFactory.cs index ae0bf6c7d66df..2f7c4dd2c1b9b 100644 --- a/src/LanguageServer/Protocol/Handler/Completion/CompletionResultFactory.cs +++ b/src/LanguageServer/Protocol/Handler/Completion/CompletionResultFactory.cs @@ -33,7 +33,7 @@ internal static class CompletionResultFactory public static string[] DefaultCommitCharactersArray { get; } = CreateCommitCharacterArrayFromRules(CompletionItemRules.Default); - public static async Task ConvertToLspCompletionListAsync( + public static async Task ConvertToLspCompletionListAsync( Document document, CompletionCapabilityHelper capabilityHelper, CompletionList list, @@ -86,7 +86,7 @@ internal static class CompletionResultFactory ItemDefaults = new LSP.CompletionListItemDefaults { EditRange = capabilityHelper.SupportDefaultEditRange ? ProtocolConversions.TextSpanToRange(defaultSpan, documentText) : null, - Data = capabilityHelper.SupportCompletionListData ? resolveData : null + Data = capabilityHelper.SupportCompletionListData ? resolveData : null, }, // VS internal @@ -97,6 +97,12 @@ internal static class CompletionResultFactory Data = capabilityHelper.SupportVSInternalCompletionListData ? resolveData : null, }; + if (capabilityHelper.SupportedInsertTextModes.Contains(LSP.InsertTextMode.AsIs)) + { + // By default, all text edits we create include the appropriate whitespace, so tell the client to leave it as-is (if it supports the option). + completionList.ItemDefaults.InsertTextMode = LSP.InsertTextMode.AsIs; + } + PromoteCommonCommitCharactersOntoList(); if (completionList.ItemDefaults is { EditRange: null, CommitCharacters: null, Data: null }) diff --git a/src/LanguageServer/Protocol/Handler/Completion/Extensions.cs b/src/LanguageServer/Protocol/Handler/Completion/Extensions.cs index c0763139f9b96..4740af6efa02f 100644 --- a/src/LanguageServer/Protocol/Handler/Completion/Extensions.cs +++ b/src/LanguageServer/Protocol/Handler/Completion/Extensions.cs @@ -7,7 +7,6 @@ using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Options; -using Roslyn.Utilities; using LSP = Roslyn.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.LanguageServer.Handler.Completion; diff --git a/src/LanguageServer/Protocol/Handler/Configuration/DidChangeConfigurationNotificationHandler.cs b/src/LanguageServer/Protocol/Handler/Configuration/DidChangeConfigurationNotificationHandler.cs index ba4ed447b8d6a..43da49be70aa6 100644 --- a/src/LanguageServer/Protocol/Handler/Configuration/DidChangeConfigurationNotificationHandler.cs +++ b/src/LanguageServer/Protocol/Handler/Configuration/DidChangeConfigurationNotificationHandler.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics; using System.Text.Json.Nodes; using System.Threading; using System.Threading.Tasks; diff --git a/src/LanguageServer/Protocol/Handler/Definitions/AbstractGoToDefinitionHandler.cs b/src/LanguageServer/Protocol/Handler/Definitions/AbstractGoToDefinitionHandler.cs index a0c753ff3ff9d..1909c7298cc9a 100644 --- a/src/LanguageServer/Protocol/Handler/Definitions/AbstractGoToDefinitionHandler.cs +++ b/src/LanguageServer/Protocol/Handler/Definitions/AbstractGoToDefinitionHandler.cs @@ -88,7 +88,7 @@ await definition.Document.GetRequiredDocumentAsync(document.Project.Solution, ca var linePosSpan = declarationFile.IdentifierLocation.GetLineSpan().Span; locations.Add(new LSP.Location { - Uri = ProtocolConversions.CreateAbsoluteUri(declarationFile.FilePath), + Uri = ProtocolConversions.CreateAbsoluteUri(declarationFile.FilePath!), Range = ProtocolConversions.LinePositionToRange(linePosSpan), }); } diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs index 768adc82f6111..d1f6ead2e0d06 100644 --- a/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs +++ b/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs @@ -6,12 +6,9 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; @@ -123,7 +120,8 @@ protected virtual Task WaitForChangesAsync(string? category, RequestContext cont var handlerName = $"{this.GetType().Name}(category: {category})"; context.TraceInformation($"{handlerName} started getting diagnostics"); - var versionedCache = _categoryToVersionedCache.GetOrAdd(handlerName, static handlerName => new(handlerName)); + var versionedCache = _categoryToVersionedCache.GetOrAdd( + handlerName, static (handlerName, globalOptions) => new(globalOptions, handlerName), GlobalOptions); // Get the set of results the request said were previously reported. We can use this to determine both // what to skip, and what files we have to tell the client have been removed. diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractWorkspacePullDiagnosticsHandler.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractWorkspacePullDiagnosticsHandler.cs index dd00913897084..df726f111c6c4 100644 --- a/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractWorkspacePullDiagnosticsHandler.cs +++ b/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractWorkspacePullDiagnosticsHandler.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Diagnostics; @@ -21,6 +20,7 @@ internal abstract class AbstractWorkspacePullDiagnosticsHandler @@ -45,13 +45,16 @@ protected AbstractWorkspacePullDiagnosticsHandler( DiagnosticSourceManager = diagnosticSourceManager; _workspaceManager = workspaceManager; _workspaceRegistrationService = registrationService; + _diagnosticsRefresher = diagnosticRefresher; _workspaceRegistrationService.LspSolutionChanged += OnLspSolutionChanged; _workspaceManager.LspTextChanged += OnLspTextChanged; + _diagnosticsRefresher.WorkspaceRefreshRequested += OnWorkspaceRefreshRequested; } public void Dispose() { + _diagnosticsRefresher.WorkspaceRefreshRequested -= OnWorkspaceRefreshRequested; _workspaceManager.LspTextChanged -= OnLspTextChanged; _workspaceRegistrationService.LspSolutionChanged -= OnLspSolutionChanged; } @@ -79,6 +82,11 @@ private void OnLspTextChanged(object? sender, EventArgs e) UpdateLspChanged(); } + private void OnWorkspaceRefreshRequested() + { + UpdateLspChanged(); + } + private void UpdateLspChanged() { lock (_gate) diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSourceProviders/WorkspaceDocumentsAndProjectDiagnosticSourceProvider.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSourceProviders/WorkspaceDocumentsAndProjectDiagnosticSourceProvider.cs index 58cca636c91f5..e18ca39e8f871 100644 --- a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSourceProviders/WorkspaceDocumentsAndProjectDiagnosticSourceProvider.cs +++ b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSourceProviders/WorkspaceDocumentsAndProjectDiagnosticSourceProvider.cs @@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.SolutionCrawler; using Roslyn.LanguageServer.Protocol; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics; diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractProjectDiagnosticSource.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractProjectDiagnosticSource.cs index 0c122523e9b86..18fc22f98ca51 100644 --- a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractProjectDiagnosticSource.cs +++ b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractProjectDiagnosticSource.cs @@ -50,8 +50,8 @@ public override async Task> GetDiagnosticsAsync( // we're passing in. If information is already cached for that snapshot, it will be returned. Otherwise, // it will be computed on demand. Because it is always accurate as per this snapshot, all spans are correct // and do not need to be adjusted. - var diagnostics = await diagnosticAnalyzerService.GetProjectDiagnosticsForIdsAsync(Project.Solution, Project.Id, - diagnosticIds: null, shouldIncludeAnalyzer, includeNonLocalDocumentDiagnostics: false, cancellationToken).ConfigureAwait(false); + var diagnostics = await diagnosticAnalyzerService.GetProjectDiagnosticsForIdsAsync( + Project, diagnosticIds: null, shouldIncludeAnalyzer, includeNonLocalDocumentDiagnostics: false, cancellationToken).ConfigureAwait(false); // TODO(cyrusn): In the future we could consider reporting these, but with a flag on the diagnostic mentioning // that it is suppressed and should be hidden from the task list by default. @@ -74,7 +74,7 @@ public override Task> GetDiagnosticsAsync( RequestContext context, CancellationToken cancellationToken) { - return codeAnalysisService.GetLastComputedProjectDiagnosticsAsync(Project.Id, cancellationToken); + return Task.FromResult(codeAnalysisService.GetLastComputedProjectDiagnostics(Project.Id)); } } } diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractWorkspaceDocumentDiagnosticSource.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractWorkspaceDocumentDiagnosticSource.cs index 9becd49893ea4..7777dba417737 100644 --- a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractWorkspaceDocumentDiagnosticSource.cs +++ b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractWorkspaceDocumentDiagnosticSource.cs @@ -76,10 +76,7 @@ AsyncLazy> GetLazyDiagnostics() async cancellationToken => { var allDiagnostics = await diagnosticAnalyzerService.GetDiagnosticsForIdsAsync( - Document.Project.Solution, Document.Project.Id, documentId: null, - diagnosticIds: null, shouldIncludeAnalyzer, - // Ensure we compute and return diagnostics for both the normal docs and the additional docs in this project. - static (project, _) => [.. project.DocumentIds.Concat(project.AdditionalDocumentIds)], + Document.Project, documentId: null, diagnosticIds: null, shouldIncludeAnalyzer, includeLocalDocumentDiagnostics: true, includeNonLocalDocumentDiagnostics: true, cancellationToken).ConfigureAwait(false); // TODO(cyrusn): Should we be filtering out suppressed diagnostics here? This is how the @@ -105,7 +102,7 @@ public override Task> GetDiagnosticsAsync( RequestContext context, CancellationToken cancellationToken) { - return codeAnalysisService.GetLastComputedDocumentDiagnosticsAsync(Document.Id, cancellationToken); + return Task.FromResult(codeAnalysisService.GetLastComputedDocumentDiagnostics(Document.Id)); } } } diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/NonLocalDocumentDiagnosticSource.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/NonLocalDocumentDiagnosticSource.cs index b2a168f48a928..b089870386125 100644 --- a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/NonLocalDocumentDiagnosticSource.cs +++ b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/NonLocalDocumentDiagnosticSource.cs @@ -26,8 +26,7 @@ public override async Task> GetDiagnosticsAsync( // document including those reported as a compilation end diagnostic. These are not included in document pull // (uses GetDiagnosticsForSpan) due to cost. var diagnostics = await diagnosticAnalyzerService.GetDiagnosticsForIdsAsync( - Document.Project.Solution, Document.Project.Id, Document.Id, - diagnosticIds: null, _shouldIncludeAnalyzer, + Document.Project, Document.Id, diagnosticIds: null, _shouldIncludeAnalyzer, includeLocalDocumentDiagnostics: false, includeNonLocalDocumentDiagnostics: true, cancellationToken).ConfigureAwait(false); // TODO(cyrusn): In the future we could consider reporting these, but with a flag on the diagnostic mentioning diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticsPullCache.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticsPullCache.cs index 2d1b001f6f095..b4b702c4fa5de 100644 --- a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticsPullCache.cs +++ b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticsPullCache.cs @@ -5,7 +5,10 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; using Roslyn.LanguageServer.Protocol; using Roslyn.Utilities; @@ -15,17 +18,21 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics; internal abstract partial class AbstractPullDiagnosticHandler where TDiagnosticsParams : IPartialResultParams { - internal record struct DiagnosticsRequestState(Project Project, int GlobalStateVersion, RequestContext Context, IDiagnosticSource DiagnosticSource); + internal readonly record struct DiagnosticsRequestState(Project Project, int GlobalStateVersion, RequestContext Context, IDiagnosticSource DiagnosticSource); /// - /// Cache where we store the data produced by prior requests so that they can be returned if nothing of significance - /// changed. The is produced by while the - /// is produced by . The former is faster - /// and works well for us in the normal case. The latter still allows us to reuse diagnostics when changes happen that - /// update the version stamp but not the content (for example, forking LSP text). + /// Cache where we store the data produced by prior requests so that they can be returned if nothing of significance + /// changed. The is produced by while the is produced by + /// . The former is faster and works + /// well for us in the normal case. The latter still allows us to reuse diagnostics when changes happen that update + /// the version stamp but not the content (for example, forking LSP text). /// - private sealed class DiagnosticsPullCache(string uniqueKey) : VersionedPullCache<(int globalStateVersion, VersionStamp? dependentVersion), (int globalStateVersion, Checksum dependentChecksum), DiagnosticsRequestState, ImmutableArray>(uniqueKey) + private sealed class DiagnosticsPullCache(IGlobalOptionService globalOptions, string uniqueKey) + : VersionedPullCache<(int globalStateVersion, VersionStamp? dependentVersion), (int globalStateVersion, Checksum dependentChecksum), DiagnosticsRequestState, ImmutableArray>(uniqueKey) { + private readonly IGlobalOptionService _globalOptions = globalOptions; + public override async Task<(int globalStateVersion, VersionStamp? dependentVersion)> ComputeCheapVersionAsync(DiagnosticsRequestState state, CancellationToken cancellationToken) { return (state.GlobalStateVersion, await state.Project.GetDependentVersionAsync(cancellationToken).ConfigureAwait(false)); @@ -33,7 +40,7 @@ private sealed class DiagnosticsPullCache(string uniqueKey) : VersionedPullCache public override async Task<(int globalStateVersion, Checksum dependentChecksum)> ComputeExpensiveVersionAsync(DiagnosticsRequestState state, CancellationToken cancellationToken) { - return (state.GlobalStateVersion, await state.Project.GetDependentChecksumAsync(cancellationToken).ConfigureAwait(false)); + return (state.GlobalStateVersion, await state.Project.GetDiagnosticChecksumAsync(cancellationToken).ConfigureAwait(false)); } /// @@ -44,14 +51,28 @@ public override async Task> ComputeDataAsync(Diag return diagnostics; } - public override Checksum ComputeChecksum(ImmutableArray data) + public override Checksum ComputeChecksum(ImmutableArray data, string language) { // Create checksums of diagnostic data and sort to ensure stable ordering for comparison. - var diagnosticDataChecksums = data - .SelectAsArray(d => Checksum.Create(d, SerializeDiagnosticData)) - .Sort(); + using var _ = ArrayBuilder.GetInstance(out var builder); + foreach (var datum in data) + builder.Add(Checksum.Create(datum, SerializeDiagnosticData)); + + // Ensure that if fading options change that we recompute the checksum as it will produce different data + // that we would report to the client. + var option1 = _globalOptions.GetOption(FadingOptions.FadeOutUnreachableCode, language); + var option2 = _globalOptions.GetOption(FadingOptions.FadeOutUnusedImports, language); + var option3 = _globalOptions.GetOption(FadingOptions.FadeOutUnusedMembers, language); + + var value = + (option1 ? (1 << 2) : 0) | + (option2 ? (1 << 1) : 0) | + (option3 ? (1 << 0) : 0); + + builder.Add(new Checksum(0, value)); + builder.Sort(); - return Checksum.Create(diagnosticDataChecksums); + return Checksum.Create(builder); } private static void SerializeDiagnosticData(DiagnosticData diagnosticData, ObjectWriter writer) diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/ProjectOrDocumentId.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/ProjectOrDocumentId.cs index ac1f4f63653a6..a6a3dbf5d3ab9 100644 --- a/src/LanguageServer/Protocol/Handler/Diagnostics/ProjectOrDocumentId.cs +++ b/src/LanguageServer/Protocol/Handler/Diagnostics/ProjectOrDocumentId.cs @@ -2,26 +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.Diagnostics.CodeAnalysis; - namespace Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics; /// /// Wrapper around project and document ids for convenience in caching diagnostic results and /// use in the /// -internal readonly struct ProjectOrDocumentId +internal readonly record struct ProjectOrDocumentId { /// /// Non-null if this represents a documentId. Used for equality comparisons. /// - [SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used for equality comparison.")] private readonly DocumentId? _documentId; /// /// Non-null if this represents a projectId. Used for equality comparisons. /// - [SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used for equality comparison.")] private readonly ProjectId? _projectId; public ProjectOrDocumentId(ProjectId projectId) diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/PullDiagnosticCategories.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/PullDiagnosticCategories.cs index ca79789913f81..39ec24da85143 100644 --- a/src/LanguageServer/Protocol/Handler/Diagnostics/PullDiagnosticCategories.cs +++ b/src/LanguageServer/Protocol/Handler/Diagnostics/PullDiagnosticCategories.cs @@ -16,7 +16,7 @@ internal static class PullDiagnosticCategories /// /// Edit and Continue diagnostics. Can be for Document or Workspace pull requests. /// - public static readonly string EditAndContinue = VSInternalDiagnosticKind.EditAndContiue.Value; + public static readonly string EditAndContinue = VSInternalDiagnosticKind.EditAndContinue.Value; // Workspace categories diff --git a/src/LanguageServer/Protocol/Handler/EditAndContinue/RegisterSolutionSnapshotHandler.cs b/src/LanguageServer/Protocol/Handler/EditAndContinue/RegisterSolutionSnapshotHandler.cs index 22c82c93e3ff0..1c34bd1f636f5 100644 --- a/src/LanguageServer/Protocol/Handler/EditAndContinue/RegisterSolutionSnapshotHandler.cs +++ b/src/LanguageServer/Protocol/Handler/EditAndContinue/RegisterSolutionSnapshotHandler.cs @@ -9,7 +9,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.EditAndContinue; using Microsoft.CodeAnalysis.Host.Mef; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.Handler.EditAndContinue; diff --git a/src/LanguageServer/Protocol/Handler/EditAndContinue/WorkspaceEditAndContinueDiagnosticSourceProvider.cs b/src/LanguageServer/Protocol/Handler/EditAndContinue/WorkspaceEditAndContinueDiagnosticSourceProvider.cs index af92108b86cae..f3e63d42a98f0 100644 --- a/src/LanguageServer/Protocol/Handler/EditAndContinue/WorkspaceEditAndContinueDiagnosticSourceProvider.cs +++ b/src/LanguageServer/Protocol/Handler/EditAndContinue/WorkspaceEditAndContinueDiagnosticSourceProvider.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.EditAndContinue; using Microsoft.CodeAnalysis.Host.Mef; using Roslyn.LanguageServer.Protocol; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics; diff --git a/src/LanguageServer/Protocol/Handler/Formatting/AbstractFormatDocumentHandlerBase.cs b/src/LanguageServer/Protocol/Handler/Formatting/AbstractFormatDocumentHandlerBase.cs index 3b3e8623bf679..ba60956bd4b7e 100644 --- a/src/LanguageServer/Protocol/Handler/Formatting/AbstractFormatDocumentHandlerBase.cs +++ b/src/LanguageServer/Protocol/Handler/Formatting/AbstractFormatDocumentHandlerBase.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.Linq; using System.Threading; using System.Threading.Tasks; diff --git a/src/LanguageServer/Protocol/Handler/Formatting/FormatDocumentOnTypeHandler.cs b/src/LanguageServer/Protocol/Handler/Formatting/FormatDocumentOnTypeHandler.cs index f2191c061bc9f..18b6576a779f7 100644 --- a/src/LanguageServer/Protocol/Handler/Formatting/FormatDocumentOnTypeHandler.cs +++ b/src/LanguageServer/Protocol/Handler/Formatting/FormatDocumentOnTypeHandler.cs @@ -12,7 +12,6 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.LanguageServer.Handler diff --git a/src/LanguageServer/Protocol/Handler/InitializeManager.cs b/src/LanguageServer/Protocol/Handler/InitializeManager.cs index 3dafa54fd5635..f5c1a9ae3b92c 100644 --- a/src/LanguageServer/Protocol/Handler/InitializeManager.cs +++ b/src/LanguageServer/Protocol/Handler/InitializeManager.cs @@ -4,7 +4,6 @@ using System; using Roslyn.LanguageServer.Protocol; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.Handler; diff --git a/src/LanguageServer/Protocol/Handler/InlayHint/InlayHintResolveData.cs b/src/LanguageServer/Protocol/Handler/InlayHint/InlayHintResolveData.cs index 37b4504ef9440..327ba52dc0222 100644 --- a/src/LanguageServer/Protocol/Handler/InlayHint/InlayHintResolveData.cs +++ b/src/LanguageServer/Protocol/Handler/InlayHint/InlayHintResolveData.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 Microsoft.CodeAnalysis.Text; using Roslyn.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.LanguageServer.Handler.InlayHint; diff --git a/src/LanguageServer/Protocol/Handler/InlayHint/InlayHintResolveHandler.cs b/src/LanguageServer/Protocol/Handler/InlayHint/InlayHintResolveHandler.cs index 08cc5c33bd95e..1e2df2c6cf297 100644 --- a/src/LanguageServer/Protocol/Handler/InlayHint/InlayHintResolveHandler.cs +++ b/src/LanguageServer/Protocol/Handler/InlayHint/InlayHintResolveHandler.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.InlineHints; using Microsoft.CodeAnalysis.Options; using Roslyn.LanguageServer.Protocol; -using Roslyn.Utilities; using StreamJsonRpc; using LSP = Roslyn.LanguageServer.Protocol; diff --git a/src/LanguageServer/Protocol/Handler/InlineCompletions/XmlSnippetParser.cs b/src/LanguageServer/Protocol/Handler/InlineCompletions/XmlSnippetParser.cs index ed5b3cd09dbde..0a6a776ebe156 100644 --- a/src/LanguageServer/Protocol/Handler/InlineCompletions/XmlSnippetParser.cs +++ b/src/LanguageServer/Protocol/Handler/InlineCompletions/XmlSnippetParser.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Snippets; using Microsoft.CommonLanguageServerProtocol.Framework; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.Handler.InlineCompletions; diff --git a/src/LanguageServer/Protocol/Handler/PullHandlers/VersionedPullCache.CacheItem.cs b/src/LanguageServer/Protocol/Handler/PullHandlers/VersionedPullCache.CacheItem.cs index 6def0f52d7f81..1ecbf8fcc33e8 100644 --- a/src/LanguageServer/Protocol/Handler/PullHandlers/VersionedPullCache.CacheItem.cs +++ b/src/LanguageServer/Protocol/Handler/PullHandlers/VersionedPullCache.CacheItem.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.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics; @@ -57,6 +56,7 @@ private sealed class CacheItem(string uniqueKey) PreviousPullResult? previousPullResult, bool isFullyLoaded, TState state, + string language, CancellationToken cancellationToken) { // Ensure that we only update the cache item one at a time. @@ -99,7 +99,7 @@ _lastResult is not null && // Compute the new result for the request. var data = await cache.ComputeDataAsync(state, cancellationToken).ConfigureAwait(false); - var dataChecksum = cache.ComputeChecksum(data); + var dataChecksum = cache.ComputeChecksum(data, language); string newResultId; if (_lastResult is not null && _lastResult?.resultId == previousPullResult?.PreviousResultId && _lastResult?.dataChecksum == dataChecksum) diff --git a/src/LanguageServer/Protocol/Handler/PullHandlers/VersionedPullCache.cs b/src/LanguageServer/Protocol/Handler/PullHandlers/VersionedPullCache.cs index aacaeca1cdc14..f378b4b092ecf 100644 --- a/src/LanguageServer/Protocol/Handler/PullHandlers/VersionedPullCache.cs +++ b/src/LanguageServer/Protocol/Handler/PullHandlers/VersionedPullCache.cs @@ -59,7 +59,7 @@ internal abstract partial class VersionedPullCache public abstract Task ComputeDataAsync(TState state, CancellationToken cancellationToken); - public abstract Checksum ComputeChecksum(TComputedData data); + public abstract Checksum ComputeChecksum(TComputedData data, string language); /// /// If results have changed since the last request this calculates and returns a new @@ -75,14 +75,16 @@ internal abstract partial class VersionedPullCache new CacheItem(uniqueKey)); - return await cacheEntry.UpdateCacheItemAsync(this, previousResult, isFullyLoaded, state, cancellationToken).ConfigureAwait(false); + var cacheEntry = _idToLastReportedResult.GetOrAdd( + (project.Solution.Workspace, projectOrDocumentId), + static (_, uniqueKey) => new CacheItem(uniqueKey), + uniqueKey); + return await cacheEntry.UpdateCacheItemAsync( + this, previousResult, isFullyLoaded, state, project.Language, cancellationToken).ConfigureAwait(false); } private long GetNextResultId() diff --git a/src/LanguageServer/Protocol/Handler/References/FindAllReferencesHandler.cs b/src/LanguageServer/Protocol/Handler/References/FindAllReferencesHandler.cs index 20a1c131bfcea..f272f3f49fbd4 100644 --- a/src/LanguageServer/Protocol/Handler/References/FindAllReferencesHandler.cs +++ b/src/LanguageServer/Protocol/Handler/References/FindAllReferencesHandler.cs @@ -16,7 +16,6 @@ using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Text; using Roslyn.LanguageServer.Protocol; -using Roslyn.Utilities; using LSP = Roslyn.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.LanguageServer.Handler diff --git a/src/LanguageServer/Protocol/Handler/References/FindUsagesLSPContext.cs b/src/LanguageServer/Protocol/Handler/References/FindUsagesLSPContext.cs index 4196abef13bbe..93e03de3f093a 100644 --- a/src/LanguageServer/Protocol/Handler/References/FindUsagesLSPContext.cs +++ b/src/LanguageServer/Protocol/Handler/References/FindUsagesLSPContext.cs @@ -20,6 +20,7 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Threading; using Roslyn.LanguageServer.Protocol; using Roslyn.Text.Adornments; using Roslyn.Utilities; diff --git a/src/LanguageServer/Protocol/Handler/RequestContext.cs b/src/LanguageServer/Protocol/Handler/RequestContext.cs index f7169785d6951..e4562e16772a6 100644 --- a/src/LanguageServer/Protocol/Handler/RequestContext.cs +++ b/src/LanguageServer/Protocol/Handler/RequestContext.cs @@ -390,4 +390,9 @@ public IEnumerable GetRequiredServices() where T : class { return _lspServices.GetRequiredServices(); } + + public T? GetService() where T : class, ILspService + { + return _lspServices.GetService(); + } } diff --git a/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensFullHandler.cs b/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensFullHandler.cs new file mode 100644 index 0000000000000..35c8400eec316 --- /dev/null +++ b/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensFullHandler.cs @@ -0,0 +1,43 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Options; +using Roslyn.LanguageServer.Protocol; +using LSP = Roslyn.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.LanguageServer.Handler.SemanticTokens; + +[Method(Methods.TextDocumentSemanticTokensFullName)] +internal sealed class SemanticTokensFullHandler( + IGlobalOptionService globalOptions, + SemanticTokensRefreshQueue semanticTokensRefreshQueue) + : ILspServiceDocumentRequestHandler +{ + private readonly IGlobalOptionService _globalOptions = globalOptions; + private readonly SemanticTokensRefreshQueue _semanticTokenRefreshQueue = semanticTokensRefreshQueue; + + public bool MutatesSolutionState => false; + public bool RequiresLSPSolution => true; + + public TextDocumentIdentifier GetTextDocumentIdentifier(LSP.SemanticTokensFullParams request) + { + Contract.ThrowIfNull(request.TextDocument); + return request.TextDocument; + } + + public async Task HandleRequestAsync( + SemanticTokensFullParams request, + RequestContext context, + CancellationToken cancellationToken) + { + Contract.ThrowIfNull(request.TextDocument); + + // Passing an null array of ranges will cause the helper to return tokens for the entire document. + var tokensData = await SemanticTokensHelpers.HandleRequestHelperAsync( + _globalOptions, _semanticTokenRefreshQueue, ranges: null, context, cancellationToken).ConfigureAwait(false); + return new LSP.SemanticTokens { Data = tokensData }; + } +} diff --git a/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensFullHandlerFactory.cs b/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensFullHandlerFactory.cs new file mode 100644 index 0000000000000..0cdf2dfd8e495 --- /dev/null +++ b/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensFullHandlerFactory.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; +using System.Composition; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.LanguageServer.Handler.SemanticTokens; + +[ExportCSharpVisualBasicLspServiceFactory(typeof(SemanticTokensFullHandler)), Shared] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class SemanticTokensFullHandlerFactory(IGlobalOptionService globalOptions) : ILspServiceFactory +{ + private readonly IGlobalOptionService _globalOptions = globalOptions; + + public ILspService CreateILspService(LspServices lspServices, WellKnownLspServerKinds serverKind) + { + var semanticTokensRefreshQueue = lspServices.GetRequiredService(); + return new SemanticTokensFullHandler(_globalOptions, semanticTokensRefreshQueue); + } +} diff --git a/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensHelpers.cs b/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensHelpers.cs index f291526b0e130..8b290487620c1 100644 --- a/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensHelpers.cs +++ b/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensHelpers.cs @@ -15,375 +15,361 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; using LSP = Roslyn.LanguageServer.Protocol; -namespace Microsoft.CodeAnalysis.LanguageServer.Handler.SemanticTokens +namespace Microsoft.CodeAnalysis.LanguageServer.Handler.SemanticTokens; + +internal static class SemanticTokensHelpers { - internal static class SemanticTokensHelpers + private static readonly ObjectPool> s_tokenListPool = new(() => new List(capacity: 1000)); + + /// The ranges to get semantic tokens for. If null then the entire document will be + /// processed. + internal static async Task HandleRequestHelperAsync( + IGlobalOptionService globalOptions, + SemanticTokensRefreshQueue semanticTokensRefreshQueue, + LSP.Range[]? ranges, + RequestContext context, + CancellationToken cancellationToken) { - private static readonly ObjectPool> s_tokenListPool = new ObjectPool>(() => new List(capacity: 1000)); - - internal static async Task HandleRequestHelperAsync( - IGlobalOptionService globalOptions, - SemanticTokensRefreshQueue semanticTokensRefreshQueue, - LSP.Range[] ranges, - RequestContext context, - CancellationToken cancellationToken) - { - if (ranges.Length == 0) - { - return []; - } + var contextDocument = context.GetRequiredDocument(); - var contextDocument = context.GetRequiredDocument(); - var project = contextDocument.Project; - var options = globalOptions.GetClassificationOptions(project.Language); - var supportsVisualStudioExtensions = context.GetRequiredClientCapabilities().HasVisualStudioLspCapability(); + // If the client didn't provide any ranges, we'll just return the entire document. + var text = await contextDocument.GetTextAsync(cancellationToken).ConfigureAwait(false); + ranges ??= [ProtocolConversions.TextSpanToRange(new TextSpan(0, text.Length), text)]; - var spans = new FixedSizeArrayBuilder(ranges.Length); - foreach (var range in ranges) - spans.Add(ProtocolConversions.RangeToLinePositionSpan(range)); + var project = contextDocument.Project; + var options = globalOptions.GetClassificationOptions(project.Language); + var supportsVisualStudioExtensions = context.GetRequiredClientCapabilities().HasVisualStudioLspCapability(); - var tokensData = await HandleRequestHelperAsync(contextDocument, spans.MoveToImmutable(), supportsVisualStudioExtensions, options, cancellationToken).ConfigureAwait(false); + var spans = new FixedSizeArrayBuilder(ranges.Length); + foreach (var range in ranges) + spans.Add(ProtocolConversions.RangeToLinePositionSpan(range)); - // The above call to get semantic tokens may be inaccurate (because we use frozen partial semantics). Kick - // off a request to ensure that the OOP side gets a fully up to compilation for this project. Once it does - // we can optionally choose to notify our caller to do a refresh if we computed a compilation for a new - // solution snapshot. - await semanticTokensRefreshQueue.TryEnqueueRefreshComputationAsync(project, cancellationToken).ConfigureAwait(false); - return tokensData; - } + var tokensData = await HandleRequestHelperAsync(contextDocument, spans.MoveToImmutable(), supportsVisualStudioExtensions, options, cancellationToken).ConfigureAwait(false); - public static async Task HandleRequestHelperAsync(Document document, ImmutableArray spans, bool supportsVisualStudioExtensions, ClassificationOptions options, CancellationToken cancellationToken) - { - // If the full compilation is not yet available, we'll try getting a partial one. It may contain inaccurate - // results but will speed up how quickly we can respond to the client's request. - document = document.WithFrozenPartialSemantics(cancellationToken); - options = options with { FrozenPartialSemantics = true }; - - // The results from the range handler should not be cached since we don't want to cache - // partial token results. In addition, a range request is only ever called with a whole - // document request, so caching range results is unnecessary since the whole document - // handler will cache the results anyway. - return await ComputeSemanticTokensDataAsync( - document, - spans, - supportsVisualStudioExtensions, - options, - cancellationToken).ConfigureAwait(false); - } - - /// - /// Returns the semantic tokens data for a given document with an optional ranges. - /// - /// Spans to compute tokens for. If empty, the whole document will be used. - public static async Task ComputeSemanticTokensDataAsync( - Document document, - ImmutableArray spans, - bool supportsVisualStudioExtensions, - ClassificationOptions options, - CancellationToken cancellationToken) - { - var tokenTypesToIndex = SemanticTokensSchema.GetSchema(supportsVisualStudioExtensions).TokenTypeToIndex; - var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var text = await document.GetValueTextAsync(cancellationToken).ConfigureAwait(false); - 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 - // can pass in a range from the full document if they wish. - ImmutableArray textSpans; - if (spans.Length == 0) - { - textSpans = [root.FullSpan]; - } - else - { - var textSpansBuilder = new FixedSizeArrayBuilder(spans.Length); - foreach (var span in spans) - textSpansBuilder.Add(text.Lines.GetTextSpan(span)); + // The above call to get semantic tokens may be inaccurate (because we use frozen partial semantics). Kick + // off a request to ensure that the OOP side gets a fully up to compilation for this project. Once it does + // we can optionally choose to notify our caller to do a refresh if we computed a compilation for a new + // solution snapshot. + await semanticTokensRefreshQueue.TryEnqueueRefreshComputationAsync(project, cancellationToken).ConfigureAwait(false); + return tokensData; + } - textSpans = textSpansBuilder.MoveToImmutable(); - } + public static async Task HandleRequestHelperAsync( + Document document, ImmutableArray spans, bool supportsVisualStudioExtensions, ClassificationOptions options, CancellationToken cancellationToken) + { + // If the full compilation is not yet available, we'll try getting a partial one. It may contain inaccurate + // results but will speed up how quickly we can respond to the client's request. + document = document.WithFrozenPartialSemantics(cancellationToken); + options = options with { FrozenPartialSemantics = true }; + + // The results from the range handler should not be cached since we don't want to cache + // partial token results. In addition, a range request is only ever called with a whole + // document request, so caching range results is unnecessary since the whole document + // handler will cache the results anyway. + return await ComputeSemanticTokensDataAsync( + document, + spans, + supportsVisualStudioExtensions, + options, + cancellationToken).ConfigureAwait(false); + } - await GetClassifiedSpansForDocumentAsync( - classifiedSpans, document, textSpans, options, cancellationToken).ConfigureAwait(false); + /// + /// Returns the semantic tokens data for a given document with an optional ranges. + /// + /// Spans to compute tokens for. + public static async Task ComputeSemanticTokensDataAsync( + Document document, + ImmutableArray spans, + bool supportsVisualStudioExtensions, + ClassificationOptions options, + CancellationToken cancellationToken) + { + var tokenTypesToIndex = SemanticTokensSchema.GetSchema(supportsVisualStudioExtensions).TokenTypeToIndex; + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var text = await document.GetValueTextAsync(cancellationToken).ConfigureAwait(false); + using var _1 = Classifier.GetPooledList(out var classifiedSpans); + using var _2 = Classifier.GetPooledList(out var updatedClassifiedSpans); + + var textSpans = spans.SelectAsArray(static (span, text) => text.Lines.GetTextSpan(span), text); + await GetClassifiedSpansForDocumentAsync( + classifiedSpans, document, textSpans, options, cancellationToken).ConfigureAwait(false); + + // Classified spans are not guaranteed to be returned in a certain order so we sort them to be safe. + classifiedSpans.Sort(ClassifiedSpanComparer.Instance); + + // Multi-line tokens are not supported by VS (tracked by https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1265495). + // Roslyn's classifier however can return multi-line classified spans, so we must break these up into single-line spans. + ConvertMultiLineToSingleLineSpans(text, classifiedSpans, updatedClassifiedSpans); + + // TO-DO: We should implement support for streaming if LSP adds support for it: + // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1276300 + return ComputeTokens(text.Lines, updatedClassifiedSpans, supportsVisualStudioExtensions, tokenTypesToIndex); + } - // Classified spans are not guaranteed to be returned in a certain order so we sort them to be safe. - classifiedSpans.Sort(ClassifiedSpanComparer.Instance); + private static async Task GetClassifiedSpansForDocumentAsync( + SegmentedList classifiedSpans, + Document document, + ImmutableArray textSpans, + ClassificationOptions options, + CancellationToken cancellationToken) + { + var classificationService = document.GetRequiredLanguageService(); - // Multi-line tokens are not supported by VS (tracked by https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1265495). - // Roslyn's classifier however can return multi-line classified spans, so we must break these up into single-line spans. - ConvertMultiLineToSingleLineSpans(text, classifiedSpans, updatedClassifiedSpans); + // We always return both syntactic and semantic classifications. If there is a syntactic classifier running on the client + // then the semantic token classifications will override them. - // TO-DO: We should implement support for streaming if LSP adds support for it: - // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1276300 - return ComputeTokens(text.Lines, updatedClassifiedSpans, supportsVisualStudioExtensions, tokenTypesToIndex); - } + // `includeAdditiveSpans` will add token modifiers such as 'static', which we want to include in LSP. + var spans = await ClassifierHelper.GetClassifiedSpansAsync( + document, textSpans, options, includeAdditiveSpans: true, cancellationToken).ConfigureAwait(false); - private static async Task GetClassifiedSpansForDocumentAsync( - SegmentedList classifiedSpans, - Document document, - ImmutableArray textSpans, - ClassificationOptions options, - CancellationToken cancellationToken) - { - var classificationService = document.GetRequiredLanguageService(); + // The spans returned to us may include some empty spans, which we don't care about. We also don't care + // about the 'text' classification. It's added for everything between real classifications (including + // whitespace), and just means 'don't classify this'. No need for us to actually include that in + // semantic tokens as it just wastes space in the result. + var nonEmptySpans = spans.Where(s => !s.TextSpan.IsEmpty && s.ClassificationType != ClassificationTypeNames.Text); + classifiedSpans.AddRange(nonEmptySpans); + } - // We always return both syntactic and semantic classifications. If there is a syntactic classifier running on the client - // then the semantic token classifications will override them. + private static void ConvertMultiLineToSingleLineSpans(SourceText text, SegmentedList classifiedSpans, SegmentedList updatedClassifiedSpans) + { - // `includeAdditiveSpans` will add token modifiers such as 'static', which we want to include in LSP. - var spans = await ClassifierHelper.GetClassifiedSpansAsync( - document, textSpans, options, includeAdditiveSpans: true, cancellationToken).ConfigureAwait(false); + for (var spanIndex = 0; spanIndex < classifiedSpans.Count; spanIndex++) + { + var span = classifiedSpans[spanIndex]; + text.GetLinesAndOffsets(span.TextSpan, out var startLine, out var startOffset, out var endLine, out var endOffSet); - // The spans returned to us may include some empty spans, which we don't care about. We also don't care - // about the 'text' classification. It's added for everything between real classifications (including - // whitespace), and just means 'don't classify this'. No need for us to actually include that in - // semantic tokens as it just wastes space in the result. - var nonEmptySpans = spans.Where(s => !s.TextSpan.IsEmpty && s.ClassificationType != ClassificationTypeNames.Text); - classifiedSpans.AddRange(nonEmptySpans); + // If the start and end of the classified span are not on the same line, we're dealing with a multi-line span. + // Since VS doesn't support multi-line spans/tokens, we need to break the span up into single-line spans. + if (startLine != endLine) + { + ConvertToSingleLineSpan( + text, classifiedSpans, updatedClassifiedSpans, ref spanIndex, span.ClassificationType, + startLine, startOffset, endLine, endOffSet); + } + else + { + // This is already a single-line span, so no modification is necessary. + updatedClassifiedSpans.Add(span); + } } - private static void ConvertMultiLineToSingleLineSpans(SourceText text, SegmentedList classifiedSpans, SegmentedList updatedClassifiedSpans) + static void ConvertToSingleLineSpan( + SourceText text, + SegmentedList originalClassifiedSpans, + SegmentedList updatedClassifiedSpans, + ref int spanIndex, + string classificationType, + int startLine, + int startOffset, + int endLine, + int endOffSet) { + var numLinesInSpan = endLine - startLine + 1; + Contract.ThrowIfTrue(numLinesInSpan < 1); - for (var spanIndex = 0; spanIndex < classifiedSpans.Count; spanIndex++) + for (var currentLine = 0; currentLine < numLinesInSpan; currentLine++) { - var span = classifiedSpans[spanIndex]; - text.GetLinesAndOffsets(span.TextSpan, out var startLine, out var startOffset, out var endLine, out var endOffSet); + TextSpan textSpan; + var line = text.Lines[startLine + currentLine]; - // If the start and end of the classified span are not on the same line, we're dealing with a multi-line span. - // Since VS doesn't support multi-line spans/tokens, we need to break the span up into single-line spans. - if (startLine != endLine) + // Case 1: First line of span + if (currentLine == 0) + { + var absoluteStart = line.Start + startOffset; + + // This start could be past the regular end of the line if it's within the newline character if we have a CRLF newline. In that case, just skip emitting a span for the LF. + // One example where this could happen is an embedded regular expression that we're classifying; regular expression comments contained within a multi-line string + // contain the carriage return but not the linefeed, so the linefeed could be the start of the next classification. + textSpan = TextSpan.FromBounds(Math.Min(absoluteStart, line.End), line.End); + } + // Case 2: Any of the span's middle lines + else if (currentLine != numLinesInSpan - 1) { - ConvertToSingleLineSpan( - text, classifiedSpans, updatedClassifiedSpans, ref spanIndex, span.ClassificationType, - startLine, startOffset, endLine, endOffSet); + textSpan = line.Span; } + // Case 3: Last line of span else { - // This is already a single-line span, so no modification is necessary. - updatedClassifiedSpans.Add(span); + textSpan = new TextSpan(line.Start, endOffSet); } - } - static void ConvertToSingleLineSpan( - SourceText text, - SegmentedList originalClassifiedSpans, - SegmentedList updatedClassifiedSpans, - ref int spanIndex, - string classificationType, - int startLine, - int startOffset, - int endLine, - int endOffSet) - { - var numLinesInSpan = endLine - startLine + 1; - Contract.ThrowIfTrue(numLinesInSpan < 1); + // Omit 0-length spans created in this fashion. + if (textSpan.Length > 0) + { + var updatedClassifiedSpan = new ClassifiedSpan(textSpan, classificationType); + updatedClassifiedSpans.Add(updatedClassifiedSpan); + } - for (var currentLine = 0; currentLine < numLinesInSpan; currentLine++) + // Since spans are expected to be ordered, when breaking up a multi-line span, we may have to insert + // other spans in-between. For example, we may encounter this case when breaking up a multi-line verbatim + // string literal containing escape characters: + // var x = @"one "" + // two"; + // The check below ensures we correctly return the spans in the correct order, i.e. 'one', '""', 'two'. + while (spanIndex + 1 < originalClassifiedSpans.Count && + textSpan.Contains(originalClassifiedSpans[spanIndex + 1].TextSpan)) { - TextSpan textSpan; - var line = text.Lines[startLine + currentLine]; - - // Case 1: First line of span - if (currentLine == 0) - { - var absoluteStart = line.Start + startOffset; - - // This start could be past the regular end of the line if it's within the newline character if we have a CRLF newline. In that case, just skip emitting a span for the LF. - // One example where this could happen is an embedded regular expression that we're classifying; regular expression comments contained within a multi-line string - // contain the carriage return but not the linefeed, so the linefeed could be the start of the next classification. - textSpan = TextSpan.FromBounds(Math.Min(absoluteStart, line.End), line.End); - } - // Case 2: Any of the span's middle lines - else if (currentLine != numLinesInSpan - 1) - { - textSpan = line.Span; - } - // Case 3: Last line of span - else - { - textSpan = new TextSpan(line.Start, endOffSet); - } - - // Omit 0-length spans created in this fashion. - if (textSpan.Length > 0) - { - var updatedClassifiedSpan = new ClassifiedSpan(textSpan, classificationType); - updatedClassifiedSpans.Add(updatedClassifiedSpan); - } - - // Since spans are expected to be ordered, when breaking up a multi-line span, we may have to insert - // other spans in-between. For example, we may encounter this case when breaking up a multi-line verbatim - // string literal containing escape characters: - // var x = @"one "" - // two"; - // The check below ensures we correctly return the spans in the correct order, i.e. 'one', '""', 'two'. - while (spanIndex + 1 < originalClassifiedSpans.Count && - textSpan.Contains(originalClassifiedSpans[spanIndex + 1].TextSpan)) - { - updatedClassifiedSpans.Add(originalClassifiedSpans[spanIndex + 1]); - spanIndex++; - } + updatedClassifiedSpans.Add(originalClassifiedSpans[spanIndex + 1]); + spanIndex++; } } } + } - private static int[] ComputeTokens( - TextLineCollection lines, - SegmentedList classifiedSpans, - bool supportsVisualStudioExtensions, - IReadOnlyDictionary tokenTypesToIndex) - { - // We keep track of the last line number and last start character since tokens are - // reported relative to each other. - var lastLineNumber = 0; - var lastStartCharacter = 0; - - var tokenTypeMap = SemanticTokensSchema.GetSchema(supportsVisualStudioExtensions).TokenTypeMap; + private static int[] ComputeTokens( + TextLineCollection lines, + SegmentedList classifiedSpans, + bool supportsVisualStudioExtensions, + IReadOnlyDictionary tokenTypesToIndex) + { + // We keep track of the last line number and last start character since tokens are + // reported relative to each other. + var lastLineNumber = 0; + var lastStartCharacter = 0; - using var pooledData = s_tokenListPool.GetPooledObject(); - var data = pooledData.Object; + var tokenTypeMap = SemanticTokensSchema.GetSchema(supportsVisualStudioExtensions).TokenTypeMap; - // Items in the pool may not have been cleared - data.Clear(); + using var pooledData = s_tokenListPool.GetPooledObject(); + var data = pooledData.Object; - for (var currentClassifiedSpanIndex = 0; currentClassifiedSpanIndex < classifiedSpans.Count; currentClassifiedSpanIndex++) - { - currentClassifiedSpanIndex = ComputeNextToken( - lines, ref lastLineNumber, ref lastStartCharacter, classifiedSpans, - currentClassifiedSpanIndex, tokenTypeMap, tokenTypesToIndex, - out var deltaLine, out var startCharacterDelta, out var tokenLength, - out var tokenType, out var tokenModifiers); - - data.Add(deltaLine); - data.Add(startCharacterDelta); - data.Add(tokenLength); - data.Add(tokenType); - data.Add(tokenModifiers); - } + // Items in the pool may not have been cleared + data.Clear(); - return [.. data]; + for (var currentClassifiedSpanIndex = 0; currentClassifiedSpanIndex < classifiedSpans.Count; currentClassifiedSpanIndex++) + { + currentClassifiedSpanIndex = ComputeNextToken( + lines, ref lastLineNumber, ref lastStartCharacter, classifiedSpans, + currentClassifiedSpanIndex, tokenTypeMap, tokenTypesToIndex, + out var deltaLine, out var startCharacterDelta, out var tokenLength, + out var tokenType, out var tokenModifiers); + + data.Add(deltaLine); + data.Add(startCharacterDelta); + data.Add(tokenLength); + data.Add(tokenType); + data.Add(tokenModifiers); } - private static int ComputeNextToken( - TextLineCollection lines, - ref int lastLineNumber, - ref int lastStartCharacter, - SegmentedList classifiedSpans, - int currentClassifiedSpanIndex, - IReadOnlyDictionary tokenTypeMap, - IReadOnlyDictionary tokenTypesToIndex, - out int deltaLineOut, - out int startCharacterDeltaOut, - out int tokenLengthOut, - out int tokenTypeOut, - out int tokenModifiersOut) + return [.. data]; + } + + private static int ComputeNextToken( + TextLineCollection lines, + ref int lastLineNumber, + ref int lastStartCharacter, + SegmentedList classifiedSpans, + int currentClassifiedSpanIndex, + IReadOnlyDictionary tokenTypeMap, + IReadOnlyDictionary tokenTypesToIndex, + out int deltaLineOut, + out int startCharacterDeltaOut, + out int tokenLengthOut, + out int tokenTypeOut, + out int tokenModifiersOut) + { + // Each semantic token is represented in LSP by five numbers: + // 1. Token line number delta, relative to the previous token + // 2. Token start character delta, relative to the previous token + // 3. Token length + // 4. Token type (index) - looked up in SemanticTokensLegend.tokenTypes + // 5. Token modifiers - each set bit will be looked up in SemanticTokensLegend.tokenModifiers + + var classifiedSpan = classifiedSpans[currentClassifiedSpanIndex]; + var originalTextSpan = classifiedSpan.TextSpan; + var linePosition = lines.GetLinePositionSpan(originalTextSpan).Start; + var lineNumber = linePosition.Line; + + // 1. Token line number delta, relative to the previous token + var deltaLine = lineNumber - lastLineNumber; + Contract.ThrowIfTrue(deltaLine < 0, $"deltaLine is less than 0: {deltaLine}"); + + // 2. Token start character delta, relative to the previous token + // (Relative to 0 or the previous token’s start if they're on the same line) + var deltaStartCharacter = linePosition.Character; + if (lastLineNumber == lineNumber) { - // Each semantic token is represented in LSP by five numbers: - // 1. Token line number delta, relative to the previous token - // 2. Token start character delta, relative to the previous token - // 3. Token length - // 4. Token type (index) - looked up in SemanticTokensLegend.tokenTypes - // 5. Token modifiers - each set bit will be looked up in SemanticTokensLegend.tokenModifiers - - var classifiedSpan = classifiedSpans[currentClassifiedSpanIndex]; - var originalTextSpan = classifiedSpan.TextSpan; - var linePosition = lines.GetLinePositionSpan(originalTextSpan).Start; - var lineNumber = linePosition.Line; - - // 1. Token line number delta, relative to the previous token - var deltaLine = lineNumber - lastLineNumber; - Contract.ThrowIfTrue(deltaLine < 0, $"deltaLine is less than 0: {deltaLine}"); - - // 2. Token start character delta, relative to the previous token - // (Relative to 0 or the previous token’s start if they're on the same line) - var deltaStartCharacter = linePosition.Character; - if (lastLineNumber == lineNumber) - { - deltaStartCharacter -= lastStartCharacter; - } + deltaStartCharacter -= lastStartCharacter; + } - lastLineNumber = lineNumber; - lastStartCharacter = linePosition.Character; + lastLineNumber = lineNumber; + lastStartCharacter = linePosition.Character; - // 3. Token length - var tokenLength = originalTextSpan.Length; - Contract.ThrowIfFalse(tokenLength > 0); + // 3. Token length + var tokenLength = originalTextSpan.Length; + Contract.ThrowIfFalse(tokenLength > 0); - // We currently only have one modifier (static). The logic below will need to change in the future if other - // modifiers are added in the future. - var modifierBits = TokenModifiers.None; - var tokenTypeIndex = 0; + // We currently only have one modifier (static). The logic below will need to change in the future if other + // modifiers are added in the future. + var modifierBits = TokenModifiers.None; + var tokenTypeIndex = 0; - // Classified spans with the same text span should be combined into one token. - while (classifiedSpans[currentClassifiedSpanIndex].TextSpan == originalTextSpan) + // Classified spans with the same text span should be combined into one token. + while (classifiedSpans[currentClassifiedSpanIndex].TextSpan == originalTextSpan) + { + var classificationType = classifiedSpans[currentClassifiedSpanIndex].ClassificationType; + if (classificationType == ClassificationTypeNames.StaticSymbol) { - var classificationType = classifiedSpans[currentClassifiedSpanIndex].ClassificationType; - if (classificationType == ClassificationTypeNames.StaticSymbol) - { - // 4. Token modifiers - each set bit will be looked up in SemanticTokensLegend.tokenModifiers - modifierBits |= TokenModifiers.Static; - } - else if (classificationType == ClassificationTypeNames.ReassignedVariable) - { - // 5. Token modifiers - each set bit will be looked up in SemanticTokensLegend.tokenModifiers - modifierBits |= TokenModifiers.ReassignedVariable; - } - else if (classificationType == ClassificationTypeNames.ObsoleteSymbol) - { - // 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 - // from integer to LSP token types). - tokenTypeIndex = GetTokenTypeIndex(classificationType); - } - - // Break out of the loop if we have no more classified spans left, or if the next classified span has - // a different text span than our current text span. - if (currentClassifiedSpanIndex + 1 >= classifiedSpans.Count || classifiedSpans[currentClassifiedSpanIndex + 1].TextSpan != originalTextSpan) - { - break; - } + // 4. Token modifiers - each set bit will be looked up in SemanticTokensLegend.tokenModifiers + modifierBits |= TokenModifiers.Static; + } + else if (classificationType == ClassificationTypeNames.ReassignedVariable) + { + // 5. Token modifiers - each set bit will be looked up in SemanticTokensLegend.tokenModifiers + modifierBits |= TokenModifiers.ReassignedVariable; + } + else if (classificationType == ClassificationTypeNames.ObsoleteSymbol) + { + // 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 + // from integer to LSP token types). + tokenTypeIndex = GetTokenTypeIndex(classificationType); + } - currentClassifiedSpanIndex++; + // Break out of the loop if we have no more classified spans left, or if the next classified span has + // a different text span than our current text span. + if (currentClassifiedSpanIndex + 1 >= classifiedSpans.Count || classifiedSpans[currentClassifiedSpanIndex + 1].TextSpan != originalTextSpan) + { + break; } - deltaLineOut = deltaLine; - startCharacterDeltaOut = deltaStartCharacter; - tokenLengthOut = tokenLength; - tokenTypeOut = tokenTypeIndex; - tokenModifiersOut = (int)modifierBits; + currentClassifiedSpanIndex++; + } - return currentClassifiedSpanIndex; + deltaLineOut = deltaLine; + startCharacterDeltaOut = deltaStartCharacter; + tokenLengthOut = tokenLength; + tokenTypeOut = tokenTypeIndex; + tokenModifiersOut = (int)modifierBits; - int GetTokenTypeIndex(string classificationType) - { - if (!tokenTypeMap.TryGetValue(classificationType, out var tokenTypeStr)) - { - tokenTypeStr = classificationType; - } + return currentClassifiedSpanIndex; - Contract.ThrowIfFalse(tokenTypesToIndex.TryGetValue(tokenTypeStr, out var tokenTypeIndex), "No matching token type index found."); - return tokenTypeIndex; + int GetTokenTypeIndex(string classificationType) + { + if (!tokenTypeMap.TryGetValue(classificationType, out var tokenTypeStr)) + { + tokenTypeStr = classificationType; } + + Contract.ThrowIfFalse(tokenTypesToIndex.TryGetValue(tokenTypeStr, out var tokenTypeIndex), "No matching token type index found."); + return tokenTypeIndex; } + } - private class ClassifiedSpanComparer : IComparer - { - public static readonly ClassifiedSpanComparer Instance = new(); + private class ClassifiedSpanComparer : IComparer + { + public static readonly ClassifiedSpanComparer Instance = new(); - public int Compare(ClassifiedSpan x, ClassifiedSpan y) => x.TextSpan.CompareTo(y.TextSpan); - } + public int Compare(ClassifiedSpan x, ClassifiedSpan y) => x.TextSpan.CompareTo(y.TextSpan); } } diff --git a/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensRangeHandler.cs b/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensRangeHandler.cs index 4ee36deb369e7..4aa2df67382c2 100644 --- a/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensRangeHandler.cs +++ b/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensRangeHandler.cs @@ -6,43 +6,36 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Options; using Roslyn.LanguageServer.Protocol; -using Roslyn.Utilities; using LSP = Roslyn.LanguageServer.Protocol; -namespace Microsoft.CodeAnalysis.LanguageServer.Handler.SemanticTokens +namespace Microsoft.CodeAnalysis.LanguageServer.Handler.SemanticTokens; + +[Method(Methods.TextDocumentSemanticTokensRangeName)] +internal sealed class SemanticTokensRangeHandler( + IGlobalOptionService globalOptions, + SemanticTokensRefreshQueue semanticTokensRefreshQueue) : ILspServiceDocumentRequestHandler { - [Method(Methods.TextDocumentSemanticTokensRangeName)] - internal class SemanticTokensRangeHandler : ILspServiceDocumentRequestHandler - { - private readonly IGlobalOptionService _globalOptions; - private readonly SemanticTokensRefreshQueue _semanticTokenRefreshQueue; + private readonly IGlobalOptionService _globalOptions = globalOptions; + private readonly SemanticTokensRefreshQueue _semanticTokenRefreshQueue = semanticTokensRefreshQueue; - public bool MutatesSolutionState => false; - public bool RequiresLSPSolution => true; + public bool MutatesSolutionState => false; + public bool RequiresLSPSolution => true; - public SemanticTokensRangeHandler( - IGlobalOptionService globalOptions, - SemanticTokensRefreshQueue semanticTokensRefreshQueue) - { - _globalOptions = globalOptions; - _semanticTokenRefreshQueue = semanticTokensRefreshQueue; - } + public TextDocumentIdentifier GetTextDocumentIdentifier(SemanticTokensRangeParams request) + { + Contract.ThrowIfNull(request.TextDocument); + return request.TextDocument; + } - public TextDocumentIdentifier GetTextDocumentIdentifier(LSP.SemanticTokensRangeParams request) - { - Contract.ThrowIfNull(request.TextDocument); - return request.TextDocument; - } + public async Task HandleRequestAsync( + SemanticTokensRangeParams request, + RequestContext context, + CancellationToken cancellationToken) + { + Contract.ThrowIfNull(request.TextDocument, "TextDocument is null."); - public async Task HandleRequestAsync( - SemanticTokensRangeParams request, - RequestContext context, - CancellationToken cancellationToken) - { - Contract.ThrowIfNull(request.TextDocument, "TextDocument is null."); - var ranges = new[] { request.Range }; - var tokensData = await SemanticTokensHelpers.HandleRequestHelperAsync(_globalOptions, _semanticTokenRefreshQueue, ranges, context, cancellationToken).ConfigureAwait(false); - return new LSP.SemanticTokens { Data = tokensData }; - } + var tokensData = await SemanticTokensHelpers.HandleRequestHelperAsync( + _globalOptions, _semanticTokenRefreshQueue, [request.Range], context, cancellationToken).ConfigureAwait(false); + return new LSP.SemanticTokens { Data = tokensData }; } } diff --git a/src/LanguageServer/Protocol/Handler/SignatureHelp/SignatureHelpHandler.cs b/src/LanguageServer/Protocol/Handler/SignatureHelp/SignatureHelpHandler.cs index 6a83ee35172d7..b249b22957498 100644 --- a/src/LanguageServer/Protocol/Handler/SignatureHelp/SignatureHelpHandler.cs +++ b/src/LanguageServer/Protocol/Handler/SignatureHelp/SignatureHelpHandler.cs @@ -9,7 +9,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.SignatureHelp; using Microsoft.CodeAnalysis.Text; diff --git a/src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratedDocumentCache.cs b/src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratedDocumentCache.cs index 4bbdc4e175db9..31ebb7e377f02 100644 --- a/src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratedDocumentCache.cs +++ b/src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratedDocumentCache.cs @@ -30,7 +30,7 @@ internal sealed class SourceGeneratedDocumentCache(string uniqueKey) : Versioned return SpecializedTasks.Null(); } - public override Checksum ComputeChecksum(SourceText? data) + public override Checksum ComputeChecksum(SourceText? data, string language) { return data is null ? Checksum.Null : Checksum.From(data.GetChecksum()); } diff --git a/src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratedDocumentGetTextHandler.cs b/src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratedDocumentGetTextHandler.cs index 6354c26e9b464..16203a80fabaf 100644 --- a/src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratedDocumentGetTextHandler.cs +++ b/src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratedDocumentGetTextHandler.cs @@ -3,14 +3,12 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Composition; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics; using Microsoft.CodeAnalysis.PooledObjects; -using Roslyn.Utilities; using LSP = Roslyn.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.LanguageServer.Handler.SourceGenerators; diff --git a/src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratorRefreshQueue.cs b/src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratorRefreshQueue.cs index f1e315fc18004..8c5bcba74e62a 100644 --- a/src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratorRefreshQueue.cs +++ b/src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratorRefreshQueue.cs @@ -3,11 +3,11 @@ // 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.Shared.TestHooks; +using Microsoft.CodeAnalysis.Threading; using Roslyn.LanguageServer.Protocol; using Roslyn.Utilities; using StreamJsonRpc; diff --git a/src/LanguageServer/Protocol/Handler/SpellCheck/AbstractSpellCheckingHandler.cs b/src/LanguageServer/Protocol/Handler/SpellCheck/AbstractSpellCheckingHandler.cs index 88197335d9adb..b7194578a1ad1 100644 --- a/src/LanguageServer/Protocol/Handler/SpellCheck/AbstractSpellCheckingHandler.cs +++ b/src/LanguageServer/Protocol/Handler/SpellCheck/AbstractSpellCheckingHandler.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics; @@ -15,7 +14,6 @@ using Microsoft.CodeAnalysis.SpellCheck; using Microsoft.CommonLanguageServerProtocol.Framework; using Roslyn.LanguageServer.Protocol; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.Handler.SpellCheck { diff --git a/src/LanguageServer/Protocol/Handler/SpellCheck/SpellCheckPullCache.cs b/src/LanguageServer/Protocol/Handler/SpellCheck/SpellCheckPullCache.cs index d997635b6cb60..b334349d74e92 100644 --- a/src/LanguageServer/Protocol/Handler/SpellCheck/SpellCheckPullCache.cs +++ b/src/LanguageServer/Protocol/Handler/SpellCheck/SpellCheckPullCache.cs @@ -29,7 +29,7 @@ internal sealed class SpellCheckPullCache(string uniqueKey) : VersionedPullCache return (parseOptionsChecksum, textChecksum); } - public override Checksum ComputeChecksum(ImmutableArray data) + public override Checksum ComputeChecksum(ImmutableArray data, string language) { var checksums = data.SelectAsArray(s => Checksum.Create(s, SerializeSpellCheckSpan)).Sort(); return Checksum.Create(checksums); diff --git a/src/LanguageServer/Protocol/Handler/Tasks/WorkspaceTaskDiagnosticSourceProvider.cs b/src/LanguageServer/Protocol/Handler/Tasks/WorkspaceTaskDiagnosticSourceProvider.cs index 2a273d85d398a..7b341125f4ec0 100644 --- a/src/LanguageServer/Protocol/Handler/Tasks/WorkspaceTaskDiagnosticSourceProvider.cs +++ b/src/LanguageServer/Protocol/Handler/Tasks/WorkspaceTaskDiagnosticSourceProvider.cs @@ -12,7 +12,6 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.TaskList; using Roslyn.LanguageServer.Protocol; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics.Tasks; diff --git a/src/LanguageServer/Protocol/Handler/Telemetry/RequestTelemetryLogger.cs b/src/LanguageServer/Protocol/Handler/Telemetry/RequestTelemetryLogger.cs index 7adef6d4cd998..6f1e983d9d6c7 100644 --- a/src/LanguageServer/Protocol/Handler/Telemetry/RequestTelemetryLogger.cs +++ b/src/LanguageServer/Protocol/Handler/Telemetry/RequestTelemetryLogger.cs @@ -3,12 +3,8 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Concurrent; -using System.Reflection; -using System.Threading; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Telemetry; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.Handler; diff --git a/src/LanguageServer/Protocol/LspServices/LspServiceMetadataView.cs b/src/LanguageServer/Protocol/LspServices/LspServiceMetadataView.cs index a53bc46252917..07494bf4bc4aa 100644 --- a/src/LanguageServer/Protocol/LspServices/LspServiceMetadataView.cs +++ b/src/LanguageServer/Protocol/LspServices/LspServiceMetadataView.cs @@ -7,7 +7,6 @@ using System.Collections.Immutable; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CommonLanguageServerProtocol.Framework; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer; diff --git a/src/LanguageServer/Protocol/Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj b/src/LanguageServer/Protocol/Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj index 0f49abbd7a401..621f0bb3c9201 100644 --- a/src/LanguageServer/Protocol/Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj +++ b/src/LanguageServer/Protocol/Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj @@ -14,7 +14,6 @@ - @@ -37,11 +36,24 @@ + + + + + - + + + + + + + + + @@ -84,12 +96,14 @@ + + diff --git a/src/LanguageServer/Protocol/Protocol/FileOperations/FileSystemWatcher.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/FileSystemWatcher.cs index 0fba2560eadfe..ca199f394b4c5 100644 --- a/src/LanguageServer/Protocol/Protocol/FileOperations/FileSystemWatcher.cs +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/FileSystemWatcher.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.ComponentModel; using System.Text.Json.Serialization; namespace Roslyn.LanguageServer.Protocol; diff --git a/src/LanguageServer/Protocol/Protocol/Internal/Diagnostics/VSInternalDiagnosticKind.cs b/src/LanguageServer/Protocol/Protocol/Internal/Diagnostics/VSInternalDiagnosticKind.cs index 3ac8099a356ec..1956ef22d949c 100644 --- a/src/LanguageServer/Protocol/Protocol/Internal/Diagnostics/VSInternalDiagnosticKind.cs +++ b/src/LanguageServer/Protocol/Protocol/Internal/Diagnostics/VSInternalDiagnosticKind.cs @@ -22,6 +22,11 @@ internal readonly record struct VSInternalDiagnosticKind(string Value) : IString /// /// Edit and Continue diagnostic kind. /// - public static readonly VSInternalDiagnosticKind EditAndContiue = new("enc"); + public static readonly VSInternalDiagnosticKind EditAndContinue = new("enc"); + + /// + /// Syntax diagnostic kind. + /// + public static readonly VSInternalDiagnosticKind Syntax = new("syntax"); } } diff --git a/src/LanguageServer/Protocol/Protocol/Internal/Diagnostics/VSInternalDiagnosticRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/Internal/Diagnostics/VSInternalDiagnosticRegistrationOptions.cs new file mode 100644 index 0000000000000..b1f8b0956b421 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Internal/Diagnostics/VSInternalDiagnosticRegistrationOptions.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. + +namespace Roslyn.LanguageServer.Protocol +{ + using System.Text.Json.Serialization; + + /// + /// Diagnostic registration options. + /// + internal record class VSInternalDiagnosticRegistrationOptions : VSInternalDiagnosticOptions, ITextDocumentRegistrationOptions, IStaticRegistrationOptions + { + /// + /// Gets or sets the document filters for this registration option. + /// + [JsonPropertyName("documentSelector")] + public DocumentFilter[]? DocumentSelector { get; set; } + + /// + /// Gets or sets 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/Internal/Text/ContainerElement.cs b/src/LanguageServer/Protocol/Protocol/Internal/Text/ContainerElement.cs index 0d237c7b55ce7..c3dbf34793b83 100644 --- a/src/LanguageServer/Protocol/Protocol/Internal/Text/ContainerElement.cs +++ b/src/LanguageServer/Protocol/Protocol/Internal/Text/ContainerElement.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.Immutable; diff --git a/src/LanguageServer/Protocol/Protocol/Internal/VSInternalDataTips.cs b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalDataTips.cs index cddf349772e96..7ed3d3421619c 100644 --- a/src/LanguageServer/Protocol/Protocol/Internal/VSInternalDataTips.cs +++ b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalDataTips.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Runtime.Serialization; using System.Text.Json.Serialization; namespace Roslyn.LanguageServer.Protocol; diff --git a/src/LanguageServer/Protocol/Protocol/Internal/VSInternalInlineCompletionRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalInlineCompletionRegistrationOptions.cs new file mode 100644 index 0000000000000..2b759b4460ac6 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalInlineCompletionRegistrationOptions.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. + +namespace Roslyn.LanguageServer.Protocol +{ + using System.Text.Json.Serialization; + + /// + /// Class representing the registration options for inline completion support. + /// + /// See the Language Server Protocol specification for additional information. + /// + internal class VSInternalInlineCompletionRegistrationOptions : VSInternalInlineCompletionOptions, ITextDocumentRegistrationOptions, IStaticRegistrationOptions + { + /// + /// Gets or sets the document filters for this registration option. + /// + [JsonPropertyName("documentSelector")] + public DocumentFilter[]? DocumentSelector + { + get; + set; + } + + /// + /// Gets or sets 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/Internal/VSInternalLocation.cs b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalLocation.cs index 915dc06853f81..540cc629c01d7 100644 --- a/src/LanguageServer/Protocol/Protocol/Internal/VSInternalLocation.cs +++ b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalLocation.cs @@ -30,7 +30,7 @@ public object? Text set { - if (value is ImageElement || value is ContainerElement || value is ClassifiedTextElement || value is string) + if (value is ImageElement or ContainerElement or ClassifiedTextElement or string) { this.textValue = value; } @@ -41,4 +41,4 @@ public object? Text } } } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Protocol/Protocol/Internal/VSInternalMapCodeParams.cs b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalMapCodeParams.cs index e1460443c6612..4cf49e5466f12 100644 --- a/src/LanguageServer/Protocol/Protocol/Internal/VSInternalMapCodeParams.cs +++ b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalMapCodeParams.cs @@ -4,6 +4,7 @@ namespace Roslyn.LanguageServer.Protocol { + using System; using System.Text.Json.Serialization; /// @@ -11,6 +12,18 @@ namespace Roslyn.LanguageServer.Protocol /// internal class VSInternalMapCodeParams { + /// + /// Internal correlation GUID, used to correlate map code messages from Copilot + /// with LSP Client actions. Used for telemetry. + /// + [JsonPropertyName("_vs_map_code_correlation_id")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Guid? MapCodeCorrelationId + { + get; + set; + } + /// /// Set of code blocks, associated with documents and regions, to map. /// diff --git a/src/LanguageServer/Protocol/Protocol/Internal/VSInternalReferenceItem.cs b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalReferenceItem.cs index fefbd26e43797..ad08e41e7b7d0 100644 --- a/src/LanguageServer/Protocol/Protocol/Internal/VSInternalReferenceItem.cs +++ b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalReferenceItem.cs @@ -68,8 +68,8 @@ public object? DefinitionText set { - if (value == null || // Null is accepted since for non-definition references - (value is ImageElement || value is ContainerElement || value is ClassifiedTextElement || value is string)) + // Null is accepted since for non-definition references + if (value is null or ImageElement or ContainerElement or ClassifiedTextElement or string) { this.definitionTextValue = value; } @@ -157,7 +157,7 @@ public object? Text set { - if (value is ImageElement || value is ContainerElement || value is ClassifiedTextElement || value is string) + if (value is ImageElement or ContainerElement or ClassifiedTextElement or string) { this.textValue = value; } diff --git a/src/LanguageServer/Protocol/Protocol/Methods.DocumentSynchronization.cs b/src/LanguageServer/Protocol/Protocol/Methods.DocumentSynchronization.cs index cf3b68c31e35a..812ffeb39016d 100644 --- a/src/LanguageServer/Protocol/Protocol/Methods.DocumentSynchronization.cs +++ b/src/LanguageServer/Protocol/Protocol/Methods.DocumentSynchronization.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Roslyn.LanguageServer.Protocol; - namespace Roslyn.LanguageServer.Protocol; // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_synchronization diff --git a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensFullParams.cs b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensFullParams.cs new file mode 100644 index 0000000000000..ab4a5cb8300d7 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensFullParams.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; + +/// +/// Parameters for 'textDocument/semanticTokens/full' request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal sealed class SemanticTokensFullParams : ITextDocumentParams, IWorkDoneProgressParams, IPartialResultParams +{ + /// + /// Gets or sets an identifier for the document to fetch semantic tokens from. + /// + [JsonPropertyName("textDocument")] + [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/RoslynLanguageServer.cs b/src/LanguageServer/Protocol/RoslynLanguageServer.cs index a68788ad03c87..fda759ead5c8c 100644 --- a/src/LanguageServer/Protocol/RoslynLanguageServer.cs +++ b/src/LanguageServer/Protocol/RoslynLanguageServer.cs @@ -15,7 +15,6 @@ using Microsoft.CodeAnalysis.LanguageServer.Handler.ServerLifetime; using Microsoft.CommonLanguageServerProtocol.Framework; using Roslyn.LanguageServer.Protocol; -using Roslyn.Utilities; using StreamJsonRpc; namespace Microsoft.CodeAnalysis.LanguageServer diff --git a/src/LanguageServer/Protocol/WellKnownLspServerKinds.cs b/src/LanguageServer/Protocol/WellKnownLspServerKinds.cs index a99f84b743393..678734b21f1d7 100644 --- a/src/LanguageServer/Protocol/WellKnownLspServerKinds.cs +++ b/src/LanguageServer/Protocol/WellKnownLspServerKinds.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Roslyn.Utilities; - namespace Microsoft.CodeAnalysis.LanguageServer; internal enum WellKnownLspServerKinds diff --git a/src/LanguageServer/Protocol/Workspaces/LspWorkspaceRegistrationEventListener.cs b/src/LanguageServer/Protocol/Workspaces/LspWorkspaceRegistrationEventListener.cs index d9b81548650c5..a4239bda4c2c0 100644 --- a/src/LanguageServer/Protocol/Workspaces/LspWorkspaceRegistrationEventListener.cs +++ b/src/LanguageServer/Protocol/Workspaces/LspWorkspaceRegistrationEventListener.cs @@ -16,25 +16,16 @@ namespace Microsoft.CodeAnalysis.LanguageServer; WorkspaceKind.MetadataAsSource, WorkspaceKind.Interactive, WorkspaceKind.SemanticSearch), Shared] -internal sealed class LspWorkspaceRegistrationEventListener : IEventListener, IEventListenerStoppable +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class LspWorkspaceRegistrationEventListener(LspWorkspaceRegistrationService lspWorkspaceRegistrationService) : IEventListener { - private readonly LspWorkspaceRegistrationService _lspWorkspaceRegistrationService; + private readonly LspWorkspaceRegistrationService _lspWorkspaceRegistrationService = lspWorkspaceRegistrationService; - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public LspWorkspaceRegistrationEventListener(LspWorkspaceRegistrationService lspWorkspaceRegistrationService) - { - _lspWorkspaceRegistrationService = lspWorkspaceRegistrationService; - } - - public void StartListening(Workspace workspace, object _) - { - _lspWorkspaceRegistrationService.Register(workspace); - } + public void StartListening(Workspace workspace) + => _lspWorkspaceRegistrationService.Register(workspace); public void StopListening(Workspace workspace) - { - _lspWorkspaceRegistrationService.Deregister(workspace); - } + => _lspWorkspaceRegistrationService.Deregister(workspace); } diff --git a/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionResolveTests.cs b/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionResolveTests.cs index 115998c9c86ca..8acf17687cc4b 100644 --- a/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionResolveTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionResolveTests.cs @@ -26,7 +26,7 @@ public CodeActionResolveTests(ITestOutputHelper testOutputHelper) : base(testOut { } - [WpfTheory, CombinatorialData] + [Theory, CombinatorialData] public async Task TestCodeActionResolveHandlerAsync(bool mutatingLspWorkspace) { var initialMarkup = @@ -77,7 +77,7 @@ void M() AssertJsonEquals(expectedResolvedAction, actualResolvedAction); } - [WpfTheory, CombinatorialData] + [Theory, CombinatorialData] public async Task TestCodeActionResolveHandlerAsync_NestedAction(bool mutatingLspWorkspace) { var initialMarkup = @@ -138,7 +138,7 @@ void M() AssertJsonEquals(expectedResolvedAction, actualResolvedAction); } - [WpfTheory, CombinatorialData] + [Theory, CombinatorialData] public async Task TestRename(bool mutatingLspWorkspace) { var markUp = @" @@ -198,23 +198,35 @@ class {|caret:ABC|} AssertJsonEquals(expectedCodeAction, actualResolvedAction); } - [WpfTheory, CombinatorialData] + [Theory, CombinatorialData] public async Task TestLinkedDocuments(bool mutatingLspWorkspace) { - var xmlWorkspace = @" + var originalMarkup = """ + class C + { + public static readonly int {|caret:_value|} = 10; + } + """; + var xmlWorkspace = $""" - class C -{ - public static readonly int {|caret:_value|} = 10; -} - + {originalMarkup} -"; + """; + + var expectedText = """ + class C + { + private static readonly int value = 10; + + public static int Value => value; + } + """; + await using var testLspServer = await CreateXmlTestLspServerAsync(xmlWorkspace, mutatingLspWorkspace); var titlePath = new string[] { string.Format(FeaturesResources.Encapsulate_field_colon_0_and_use_property, "_value") }; var unresolvedCodeAction = CodeActionsTests.CreateCodeAction( @@ -230,78 +242,18 @@ public async Task TestLinkedDocuments(bool mutatingLspWorkspace) diagnostics: null); var actualResolvedAction = await RunGetCodeActionResolveAsync(testLspServer, unresolvedCodeAction); - var edits = new SumType[] - { - new TextEdit() - { - NewText = "private", - Range = new LSP.Range() - { - Start = new Position - { - Line = 2, - Character = 4 - }, - End = new Position - { - Line = 2, - Character = 10 - } - } - }, - new TextEdit - { - NewText = string.Empty, - Range = new LSP.Range - { - Start = new Position - { - Line = 2, - Character = 31 - }, - End = new Position - { - Line = 2, - Character = 32 - } - } - }, - new TextEdit - { - NewText = @" - public static int Value => value;", - Range = new LSP.Range - { - Start = new Position - { - Line = 2, - Character = 43 - }, - End = new Position - { - Line = 2, - Character = 43 - } - } - } - }; - var expectedCodeAction = CodeActionsTests.CreateCodeAction( - title: string.Format(FeaturesResources.Encapsulate_field_colon_0_and_use_property, "_value"), - kind: CodeActionKind.Refactor, - children: [], - data: CreateCodeActionResolveData( - string.Format(FeaturesResources.Encapsulate_field_colon_0_and_use_property, "_value"), - testLspServer.GetLocations("caret").Single(), titlePath), - priority: VSInternalPriorityLevel.Normal, - groupName: "Roslyn2", - applicableRange: new LSP.Range { Start = new Position { Line = 2, Character = 33 }, End = new Position { Line = 39, Character = 2 } }, - diagnostics: null, - edit: GenerateWorkspaceEdit(testLspServer.GetLocations("caret"), edits)); - AssertJsonEquals(expectedCodeAction, actualResolvedAction); + AssertEx.NotNull(actualResolvedAction.Edit); + var textDocumentEdit = (LSP.TextDocumentEdit[])actualResolvedAction.Edit.DocumentChanges.Value; + Assert.Single(textDocumentEdit); + var originalText = await testLspServer.GetDocumentTextAsync(textDocumentEdit[0].TextDocument.Uri); + var edits = textDocumentEdit[0].Edits.Select(e => (LSP.TextEdit)e.Value).ToArray(); + var updatedText = ApplyTextEdits(edits, originalText); + Assert.Equal(expectedText, updatedText); + } - [WpfTheory, CombinatorialData] + [Theory, CombinatorialData] public async Task TestMoveTypeToDifferentFile(bool mutatingLspWorkspace) { var markUp = @" @@ -423,7 +375,7 @@ class BCD AssertJsonEquals(expectedCodeAction, actualResolvedAction); } - [WpfTheory, CombinatorialData] + [Theory, CombinatorialData] public async Task TestMoveTypeToDifferentFileInDirectory(bool mutatingLspWorkspace) { var markup = diff --git a/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionsTests.cs b/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionsTests.cs index e62cd3c664ca5..e04e6459b4a65 100644 --- a/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionsTests.cs @@ -20,7 +20,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.CodeActions; public class CodeActionsTests(ITestOutputHelper testOutputHelper) : AbstractLanguageServerProtocolTests(testOutputHelper) { - [WpfTheory, CombinatorialData] + [Theory, CombinatorialData] public async Task TestCodeActionHandlerAsync(bool mutatingLspWorkspace) { var markup = @@ -57,7 +57,7 @@ void M() AssertJsonEquals(expected, useImplicitType); } - [WpfTheory, CombinatorialData] + [Theory, CombinatorialData] public async Task TestCodeActionHandlerAsync_NestedAction(bool mutatingLspWorkspace) { var markup = @@ -90,13 +90,13 @@ void M() var results = await RunGetCodeActionsAsync(testLspServer, CreateCodeActionParams(caretLocation)); var topLevelAction = Assert.Single(results, action => action.Title == titlePath[0]); - var introduceConstant = topLevelAction.Children.FirstOrDefault( + var introduceConstant = topLevelAction.Children!.FirstOrDefault( r => JsonSerializer.Deserialize((JsonElement)r.Data!, ProtocolConversions.LspJsonSerializerOptions)!.UniqueIdentifier == titlePath[1]); AssertJsonEquals(expected, introduceConstant); } - [WpfTheory, CombinatorialData] + [Theory, CombinatorialData] public async Task TestCodeActionHasCorrectDiagnostics(bool mutatingLspWorkspace) { var markup = @@ -134,11 +134,11 @@ void M() var results = await RunGetCodeActionsAsync(testLspServer, codeActionParams); var addImport = results.FirstOrDefault(r => r.Title.Contains($"using System.Threading.Tasks")); - Assert.Equal(1, addImport.Diagnostics!.Length); + Assert.Equal(1, addImport!.Diagnostics!.Length); Assert.Equal(AddImportDiagnosticIds.CS0103, addImport.Diagnostics.Single().Code!.Value); } - [WpfTheory, CombinatorialData] + [Theory, CombinatorialData] public async Task TestNoSuppressionFixerInStandardLSP(bool mutatingLspWorkspace) { var markup = """ @@ -175,7 +175,7 @@ class ABC Assert.Equal("Make method synchronous", results[0].Title); } - [WpfTheory, CombinatorialData] + [Theory, CombinatorialData] public async Task TestStandardLspNestedCodeAction(bool mutatingLspWorkspace) { var markup = """ @@ -204,7 +204,7 @@ private void XYZ() var results = await RunGetCodeActionsAsync(testLspServer, codeActionParams); var inline = results.FirstOrDefault(r => r.Title.Contains($"Inline 'A()'")); - var data = GetCodeActionResolveData(inline); + var data = GetCodeActionResolveData(inline!); Assert.NotNull(data); // Asserts that there are NestedActions on Inline @@ -218,10 +218,10 @@ private void XYZ() Assert.Equal("Inline and keep 'A()'", nestedActionData!.CodeActionPath[1]); // Asserts that there is a Command present on an action with nested actions - Assert.NotNull(inline.Command); + Assert.NotNull(inline?.Command); } - [WpfTheory, CombinatorialData] + [Theory, CombinatorialData] public async Task TestStandardLspNestedFixAllCodeAction(bool mutatingLspWorkspace) { var markup = """ @@ -266,7 +266,7 @@ class ABC Assert.Equal("Fix All: in Source", data.NestedCodeActions!.Value[1].Title); } - [WpfTheory, CombinatorialData] + [Theory, CombinatorialData] public async Task TestStandardLspNestedResolveTopLevelCodeAction(bool mutatingLspWorkspace) { var markup = """ @@ -296,7 +296,7 @@ private void XYZ() var results = await RunGetCodeActionsAsync(testLspServer, codeActionParams); // Assert that nested code actions aren't enumerated. var inline = results.FirstOrDefault(r => r.Title.Contains($"Inline 'A()'")); - var resolvedAction = await RunGetCodeActionResolveAsync(testLspServer, inline); + var resolvedAction = await RunGetCodeActionResolveAsync(testLspServer, inline!); Assert.Null(resolvedAction.Edit); } @@ -306,7 +306,7 @@ private static async Task RunGetCodeActionsAsync( { var result = await testLspServer.ExecuteRequestAsync( LSP.Methods.TextDocumentCodeActionName, codeActionParams, CancellationToken.None); - return [.. result.Cast()]; + return [.. result!.Cast()]; } private static async Task RunGetCodeActionResolveAsync( diff --git a/src/LanguageServer/ProtocolUnitTests/CodeActions/RunCodeActionsTests.cs b/src/LanguageServer/ProtocolUnitTests/CodeActions/RunCodeActionsTests.cs index 80bd47e9d2207..1b679d550649e 100644 --- a/src/LanguageServer/ProtocolUnitTests/CodeActions/RunCodeActionsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/CodeActions/RunCodeActionsTests.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Immutable; using System.Linq; using System.Text.Json; using System.Threading; @@ -11,7 +10,6 @@ using Microsoft.CodeAnalysis.LanguageServer.Handler; using Microsoft.CodeAnalysis.LanguageServer.Handler.CodeActions; using Roslyn.Test.Utilities; -using Roslyn.Utilities; using Xunit; using Xunit.Abstractions; using LSP = Roslyn.LanguageServer.Protocol; @@ -24,7 +22,7 @@ public RunCodeActionsTests(ITestOutputHelper testOutputHelper) : base(testOutput { } - [WpfTheory(Skip = "https://github.com/dotnet/roslyn/issues/65303"), CombinatorialData] + [Theory(Skip = "https://github.com/dotnet/roslyn/issues/65303"), CombinatorialData] public async Task TestRunCodeActions(bool mutatingLspWorkspace) { var markup = diff --git a/src/LanguageServer/ProtocolUnitTests/CodeLens/CSharpCodeLensTests.cs b/src/LanguageServer/ProtocolUnitTests/CodeLens/CSharpCodeLensTests.cs index 37ff9c71e2789..1a9156b341aeb 100644 --- a/src/LanguageServer/ProtocolUnitTests/CodeLens/CSharpCodeLensTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/CodeLens/CSharpCodeLensTests.cs @@ -386,8 +386,8 @@ void UseM() }; var actualCodeLenses = await testLspServer.ExecuteRequestAsync(LSP.Methods.TextDocumentCodeLensName, codeLensParamsDoc1, CancellationToken.None); - var firstCodeLens = actualCodeLenses.First(); - var data = JsonSerializer.Deserialize(firstCodeLens.Data!.ToString(), ProtocolConversions.LspJsonSerializerOptions); + var firstCodeLens = actualCodeLenses!.First(); + var data = JsonSerializer.Deserialize(firstCodeLens.Data!.ToString()!, ProtocolConversions.LspJsonSerializerOptions); AssertEx.NotNull(data); // Update the document so the syntax version changes @@ -412,10 +412,7 @@ void M(A a) await using var testLspServer = await CreateTestLspServerAsync(markup, lspMutatingWorkspace, new InitializationOptions { ClientCapabilities = CapabilitiesWithVSExtensions, - OptionUpdater = (globalOptions) => - { - globalOptions.SetGlobalOption(LspOptionsStorage.LspEnableReferencesCodeLens, LanguageNames.CSharp, false); - } + OptionUpdater = (globalOptions) => globalOptions.SetGlobalOption(LspOptionsStorage.LspEnableReferencesCodeLens, LanguageNames.CSharp, false) }); var actualCodeLenses = await GetCodeLensAsync(testLspServer); AssertEx.Empty(actualCodeLenses); @@ -446,10 +443,7 @@ class A await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, new InitializationOptions { ClientCapabilities = CapabilitiesWithVSExtensions, - OptionUpdater = (globalOptions) => - { - globalOptions.SetGlobalOption(LspOptionsStorage.LspUsingDevkitFeatures, false); - } + OptionUpdater = (globalOptions) => globalOptions.SetGlobalOption(LspOptionsStorage.LspUsingDevkitFeatures, false) }); await VerifyTestCodeLensAsync(testLspServer, FeaturesResources.Run_Test, FeaturesResources.Debug_Test); } @@ -479,10 +473,7 @@ public void M() await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, new InitializationOptions { ClientCapabilities = CapabilitiesWithVSExtensions, - OptionUpdater = (globalOptions) => - { - globalOptions.SetGlobalOption(LspOptionsStorage.LspUsingDevkitFeatures, false); - } + OptionUpdater = (globalOptions) => globalOptions.SetGlobalOption(LspOptionsStorage.LspUsingDevkitFeatures, false) }); await VerifyTestCodeLensAsync(testLspServer, FeaturesResources.Run_All_Tests, FeaturesResources.Debug_All_Tests); } @@ -512,10 +503,7 @@ class A await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, new InitializationOptions { ClientCapabilities = CapabilitiesWithVSExtensions, - OptionUpdater = (globalOptions) => - { - globalOptions.SetGlobalOption(LspOptionsStorage.LspUsingDevkitFeatures, true); - } + OptionUpdater = (globalOptions) => globalOptions.SetGlobalOption(LspOptionsStorage.LspUsingDevkitFeatures, true) }); await VerifyTestCodeLensMissingAsync(testLspServer); } @@ -545,10 +533,7 @@ class A await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, new InitializationOptions { ClientCapabilities = CapabilitiesWithVSExtensions, - OptionUpdater = (globalOptions) => - { - globalOptions.SetGlobalOption(LspOptionsStorage.LspEnableTestsCodeLens, LanguageNames.CSharp, false); - } + OptionUpdater = (globalOptions) => globalOptions.SetGlobalOption(LspOptionsStorage.LspEnableTestsCodeLens, LanguageNames.CSharp, false) }); await VerifyTestCodeLensMissingAsync(testLspServer); } diff --git a/src/LanguageServer/ProtocolUnitTests/Commands/ExecuteWorkspaceCommandTests.cs b/src/LanguageServer/ProtocolUnitTests/Commands/ExecuteWorkspaceCommandTests.cs new file mode 100644 index 0000000000000..5e8094d8274c8 --- /dev/null +++ b/src/LanguageServer/ProtocolUnitTests/Commands/ExecuteWorkspaceCommandTests.cs @@ -0,0 +1,74 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using System.Linq; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Microsoft.CodeAnalysis.LanguageServer.Handler.Commands; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.LanguageServer.Protocol; +using Roslyn.Test.Utilities; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.Commands; +public class ExecuteWorkspaceCommandTests : AbstractLanguageServerProtocolTests +{ + protected override TestComposition Composition => base.Composition.AddParts( + typeof(TestWorkspaceCommandHandler)); + + public ExecuteWorkspaceCommandTests(ITestOutputHelper? testOutputHelper) : base(testOutputHelper) + { + } + + [Theory, CombinatorialData] + public async Task TestExecuteWorkspaceCommand(bool mutatingLspWorkspace) + { + await using var server = await CreateTestLspServerAsync("", mutatingLspWorkspace); + + var request = new ExecuteCommandParams() + { + Arguments = new object[] { JsonSerializer.Serialize(new TextDocumentIdentifier { Uri = ProtocolConversions.CreateAbsoluteUri(@"C:\someFile.cs") }) }, + Command = TestWorkspaceCommandHandler.CommandName + }; + var response = await server.ExecuteRequestAsync(Methods.WorkspaceExecuteCommandName, request, CancellationToken.None); + AssertEx.NotNull(response); + Assert.True((bool)response); + + } + + [ExportCSharpVisualBasicStatelessLspService(typeof(TestWorkspaceCommandHandler)), Shared, PartNotDiscoverable] + [Command(CommandName)] + internal class TestWorkspaceCommandHandler : AbstractExecuteWorkspaceCommandHandler + { + internal const string CommandName = nameof(TestWorkspaceCommandHandler); + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public TestWorkspaceCommandHandler() + { + } + + public override string Command => CommandName; + + public override bool MutatesSolutionState => false; + + public override bool RequiresLSPSolution => true; + + public override TextDocumentIdentifier GetTextDocumentIdentifier(ExecuteCommandParams request) + { + return JsonSerializer.Deserialize((JsonElement)request.Arguments!.First(), ProtocolConversions.LspJsonSerializerOptions)!; + } + + public override Task HandleRequestAsync(ExecuteCommandParams request, RequestContext context, CancellationToken cancellationToken) + { + return Task.FromResult(true); + } + } +} diff --git a/src/LanguageServer/ProtocolUnitTests/Completion/CompletionTests.cs b/src/LanguageServer/ProtocolUnitTests/Completion/CompletionTests.cs index bf88d490792f3..ad00091a58b60 100644 --- a/src/LanguageServer/ProtocolUnitTests/Completion/CompletionTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Completion/CompletionTests.cs @@ -1471,6 +1471,62 @@ public async Task EditRangeShouldNotEndAtCursorPosition(bool mutatingLspWorkspac Assert.Equal(new() { Start = new(2, 0), End = new(2, 8) }, results.ItemDefaults.EditRange.Value.First); } + [Theory, CombinatorialData] + public async Task TestHasInsertTextModeIfSupportedAsync(bool mutatingLspWorkspace) + { + var markup = +@"class A +{ + void M() + { + {|caret:|} + } +}"; + var capabilities = CreateCoreCompletionCapabilities(); + capabilities.TextDocument.Completion.CompletionItem = new LSP.CompletionItemSetting + { + InsertTextModeSupport = new LSP.InsertTextModeSupportSetting { ValueSet = [LSP.InsertTextMode.AsIs] } + }; + + await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, capabilities); + var completionParams = CreateCompletionParams( + testLspServer.GetLocations("caret").Single(), + invokeKind: LSP.VSInternalCompletionInvokeKind.Explicit, + triggerCharacter: "\0", + triggerKind: LSP.CompletionTriggerKind.Invoked); + + var results = await RunGetCompletionsAsync(testLspServer, completionParams).ConfigureAwait(false); + Assert.Equal(LSP.InsertTextMode.AsIs, results.ItemDefaults.InsertTextMode); + } + + [Theory, CombinatorialData] + public async Task TestDoesNotHaveInsertTextModeIfNotSupportedAsync(bool mutatingLspWorkspace) + { + var markup = +@"class A +{ + void M() + { + {|caret:|} + } +}"; + var capabilities = CreateCoreCompletionCapabilities(); + capabilities.TextDocument.Completion.CompletionItem = new LSP.CompletionItemSetting + { + InsertTextModeSupport = new LSP.InsertTextModeSupportSetting { ValueSet = [] } + }; + + await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, capabilities); + var completionParams = CreateCompletionParams( + testLspServer.GetLocations("caret").Single(), + invokeKind: LSP.VSInternalCompletionInvokeKind.Explicit, + triggerCharacter: "\0", + triggerKind: LSP.CompletionTriggerKind.Invoked); + + var results = await RunGetCompletionsAsync(testLspServer, completionParams).ConfigureAwait(false); + Assert.Null(results.ItemDefaults.InsertTextMode); + } + internal static Task RunGetCompletionsAsync(TestLspServer testLspServer, LSP.CompletionParams completionParams) { return testLspServer.ExecuteRequestAsync(LSP.Methods.TextDocumentCompletionName, diff --git a/src/LanguageServer/ProtocolUnitTests/Configuration/DidChangeConfigurationNotificationHandlerTest.cs b/src/LanguageServer/ProtocolUnitTests/Configuration/DidChangeConfigurationNotificationHandlerTest.cs index 12c2b718c5e91..04875a010bc6f 100644 --- a/src/LanguageServer/ProtocolUnitTests/Configuration/DidChangeConfigurationNotificationHandlerTest.cs +++ b/src/LanguageServer/ProtocolUnitTests/Configuration/DidChangeConfigurationNotificationHandlerTest.cs @@ -156,7 +156,7 @@ public void VerifyLspClientOptionNames() string.Join(Environment.NewLine, actualNames)); } - private static void VerifyValuesInServer(EditorTestWorkspace workspace, List expectedValues) + private static void VerifyValuesInServer(LspTestWorkspace workspace, List expectedValues) { var globalOptionService = workspace.GetService(); var supportedOptions = DidChangeConfigurationNotificationHandler.SupportedOptions; @@ -244,7 +244,7 @@ private static string ConvertToString(object? value) => value switch { null => "null", - _ => value.ToString() + _ => value.ToString()! }; private static string GenerateNonDefaultValue(IOption2 option) diff --git a/src/LanguageServer/ProtocolUnitTests/Definitions/GoToDefinitionTests.cs b/src/LanguageServer/ProtocolUnitTests/Definitions/GoToDefinitionTests.cs index 7eb8c621e703c..5970d60fddfe6 100644 --- a/src/LanguageServer/ProtocolUnitTests/Definitions/GoToDefinitionTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Definitions/GoToDefinitionTests.cs @@ -4,10 +4,10 @@ #nullable disable -using System.Collections.Immutable; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Roslyn.Test.Utilities; using Roslyn.Test.Utilities.TestGenerators; using Xunit; @@ -205,6 +205,53 @@ public partial class C AssertLocationsEqual(testLspServer.GetLocations("definition"), results); } + [Theory, CombinatorialData] + public async Task TestGotoDefinitionPartialEvents(bool mutatingLspWorkspace) + { + var markup = """ + using System; + + public partial class C + { + partial event Action {|caret:|}E; + } + + public partial class C + { + partial event Action {|definition:E|} { add { } remove { } } + } + """; + await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); + + var results = await RunGotoDefinitionAsync(testLspServer, testLspServer.GetLocations("caret").Single()); + AssertLocationsEqual(testLspServer.GetLocations("definition"), results); + } + + [Theory, CombinatorialData] + public async Task TestGotoDefinitionPartialConstructors(bool mutatingLspWorkspace) + { + var markup = """ + using System; + + public partial class C + { + partial {|caret:|}C(); + } + + public partial class C + { + partial {|definition:C|}() { } + } + """; + await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, new InitializationOptions + { + ParseOptions = TestOptions.RegularPreview, + }); + + var results = await RunGotoDefinitionAsync(testLspServer, testLspServer.GetLocations("caret").Single()); + AssertLocationsEqual(testLspServer.GetLocations("definition"), results); + } + [Theory] [InlineData("ValueTuple valueTuple1;")] [InlineData("ValueTuple valueTuple2;")] diff --git a/src/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs b/src/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs index 094dec54538ad..d13000fa95ea2 100644 --- a/src/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs +++ b/src/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs @@ -279,7 +279,8 @@ private protected static async Task> RunGet if (useProgress) { Assert.Null(diagnostics); - diagnostics = progress!.Value.GetValues().Single().First; + AssertEx.NotNull(progress); + diagnostics = progress.Value.GetValues()!.Single().First; } if (diagnostics == null) diff --git a/src/LanguageServer/ProtocolUnitTests/Diagnostics/AdditionalFileDiagnosticsTests.cs b/src/LanguageServer/ProtocolUnitTests/Diagnostics/AdditionalFileDiagnosticsTests.cs index 140598171eaa0..1fcbd5de786d4 100644 --- a/src/LanguageServer/ProtocolUnitTests/Diagnostics/AdditionalFileDiagnosticsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Diagnostics/AdditionalFileDiagnosticsTests.cs @@ -40,7 +40,7 @@ public async Task TestWorkspaceDiagnosticsReportsAdditionalFileDiagnostic(bool u @"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)); @@ -64,7 +64,7 @@ public async Task TestWorkspaceDiagnosticsWithRemovedAdditionalFile(bool useVSDi Assert.Equal(3, results.Length); AssertEx.Empty(results[0].Diagnostics); - Assert.Equal(MockAdditionalFileDiagnosticAnalyzer.Id, results[1].Diagnostics.Single().Code); + Assert.Equal(MockAdditionalFileDiagnosticAnalyzer.Id, results[1].Diagnostics!.Single().Code); Assert.Equal(@"C:\Test.txt", results[1].Uri.LocalPath); AssertEx.Empty(results[2].Diagnostics); @@ -100,12 +100,12 @@ public async Task TestWorkspaceDiagnosticsWithAdditionalFileInMultipleProjects(b var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics: true); Assert.Equal(6, results.Length); - Assert.Equal(MockAdditionalFileDiagnosticAnalyzer.Id, results[1].Diagnostics.Single().Code); + Assert.Equal(MockAdditionalFileDiagnosticAnalyzer.Id, results[1].Diagnostics!.Single().Code); Assert.Equal(@"C:\Test.txt", results[1].Uri.LocalPath); - Assert.Equal("CSProj1", ((LSP.VSDiagnostic)results[1].Diagnostics.Single()).Projects.First().ProjectName); - Assert.Equal(MockAdditionalFileDiagnosticAnalyzer.Id, results[4].Diagnostics.Single().Code); + Assert.Equal("CSProj1", ((LSP.VSDiagnostic)results[1].Diagnostics!.Single()).Projects!.First().ProjectName); + Assert.Equal(MockAdditionalFileDiagnosticAnalyzer.Id, results[4].Diagnostics!.Single().Code); Assert.Equal(@"C:\Test.txt", results[4].Uri.LocalPath); - Assert.Equal("CSProj2", ((LSP.VSDiagnostic)results[4].Diagnostics.Single()).Projects.First().ProjectName); + Assert.Equal("CSProj2", ((LSP.VSDiagnostic)results[4].Diagnostics!.Single()).Projects!.First().ProjectName); // Asking again should give us back an unchanged diagnostic. var results2 = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics: true, previousResults: CreateDiagnosticParamsFromPreviousReports(results)); diff --git a/src/LanguageServer/ProtocolUnitTests/Diagnostics/DiagnosticsPullCacheTests.cs b/src/LanguageServer/ProtocolUnitTests/Diagnostics/DiagnosticsPullCacheTests.cs index 0fc045014346d..4d83a1ccaa0a9 100644 --- a/src/LanguageServer/ProtocolUnitTests/Diagnostics/DiagnosticsPullCacheTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Diagnostics/DiagnosticsPullCacheTests.cs @@ -35,7 +35,7 @@ public async Task TestDocumentDiagnosticsCallsDiagnosticSourceWhenVersionChanges await OpenDocumentAsync(testLspServer, document); var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI(), useVSDiagnostics); - Assert.Equal(TestDiagnosticSource.Id, results[0].Diagnostics.Single().Code); + Assert.Equal(TestDiagnosticSource.Id, results[0].Diagnostics!.Single().Code); Assert.Equal(1, testProvider.DiagnosticsRequestedCount); // Make a change that modifies the versions we use to cache. @@ -65,7 +65,7 @@ public async Task TestDocumentDiagnosticsCallsDiagnosticSourceWhenGlobalVersionC await OpenDocumentAsync(testLspServer, document); var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI(), useVSDiagnostics); - Assert.Equal(TestDiagnosticSource.Id, results[0].Diagnostics.Single().Code); + Assert.Equal(TestDiagnosticSource.Id, results[0].Diagnostics!.Single().Code); Assert.Equal(1, testProvider.DiagnosticsRequestedCount); // Make a global version change @@ -96,7 +96,7 @@ public async Task TestDocumentDiagnosticsDoesNotCallDiagnosticSourceWhenVersionS await OpenDocumentAsync(testLspServer, document); var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI(), useVSDiagnostics); - Assert.Equal(TestDiagnosticSource.Id, results[0].Diagnostics.Single().Code); + Assert.Equal(TestDiagnosticSource.Id, results[0].Diagnostics!.Single().Code); Assert.Equal(1, testProvider.DiagnosticsRequestedCount); // Make another request without modifying anything and assert we did not re-calculate anything. diff --git a/src/LanguageServer/ProtocolUnitTests/Diagnostics/NonLocalDiagnosticTests.cs b/src/LanguageServer/ProtocolUnitTests/Diagnostics/NonLocalDiagnosticTests.cs index c1379550ec811..a728c2f2a568e 100644 --- a/src/LanguageServer/ProtocolUnitTests/Diagnostics/NonLocalDiagnosticTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Diagnostics/NonLocalDiagnosticTests.cs @@ -45,7 +45,7 @@ internal async Task TestNonLocalDocumentDiagnosticsAreReportedWhenFSAEnabled(boo { Assert.Equal(1, results.Length); Assert.Equal(2, results[0].Diagnostics?.Length); - var orderedDiagnostics = results[0].Diagnostics.OrderBy(d => d.Code!.Value.Value).ToList(); + var orderedDiagnostics = results[0].Diagnostics!.OrderBy(d => d.Code!.Value.Value).ToList(); Assert.Equal(NonLocalDiagnosticsAnalyzer.NonLocalDescriptor.Id, orderedDiagnostics[0].Code); Assert.Equal(NonLocalDiagnosticsAnalyzer.CompilationEndDescriptor.Id, orderedDiagnostics[1].Code); Assert.Equal(document.GetURI(), results[0].Uri); diff --git a/src/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs b/src/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs index a840823f2adc5..e1ac7c2162ff0 100644 --- a/src/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.EditAndContinue; using Microsoft.CodeAnalysis.EditAndContinue.UnitTests; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -18,6 +19,7 @@ using Microsoft.CodeAnalysis.SolutionCrawler; using Microsoft.CodeAnalysis.TaskList; using Microsoft.CodeAnalysis.Text; +using Microsoft.VisualStudio.Threading; using Roslyn.LanguageServer.Protocol; using Roslyn.Test.Utilities; using Roslyn.Test.Utilities.TestGenerators; @@ -35,8 +37,7 @@ public sealed class PullDiagnosticTests(ITestOutputHelper testOutputHelper) : Ab [Theory, CombinatorialData] public async Task TestNoDocumentDiagnosticsForClosedFilesWithFSAOff(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var markup = -@"class A {"; + var markup = @"class A {"; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync(markup, mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics); var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); @@ -54,13 +55,9 @@ public async Task TestNoDocumentDiagnosticsForClosedFilesWithFSAOff(bool useVSDi [Theory, CombinatorialData] public async Task TestDocumentDiagnosticsForOpenFilesWithFSAOff(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var markup = -@"class A {"; + var markup = @"class A {"; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync(markup, mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics); - // Calling GetTextBuffer will effectively open the file. - testLspServer.TestWorkspace.Documents.Single().GetTextBuffer(); - var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); await OpenDocumentAsync(testLspServer, document); @@ -68,23 +65,19 @@ public async Task TestDocumentDiagnosticsForOpenFilesWithFSAOff(bool useVSDiagno var results = await RunGetDocumentPullDiagnosticsAsync( testLspServer, document.GetURI(), useVSDiagnostics); - Assert.Equal("CS1513", results.Single().Diagnostics.Single().Code); - Assert.NotNull(results.Single().Diagnostics.Single().CodeDescription!.Href); + Assert.Equal("CS1513", results.Single().Diagnostics!.Single().Code); + Assert.NotNull(results.Single().Diagnostics!.Single().CodeDescription!.Href); } [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/fsharp/issues/15972")] public async Task TestDocumentDiagnosticsForOpenFilesWithFSAOff_Categories(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var markup = -@"class A : B {"; + var markup = @"class A : B {"; var additionalAnalyzers = new DiagnosticAnalyzer[] { new CSharpSyntaxAnalyzer(), new CSharpSemanticAnalyzer() }; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync( markup, mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics, additionalAnalyzers: additionalAnalyzers); - // Calling GetTextBuffer will effectively open the file. - testLspServer.TestWorkspace.Documents.Single().GetTextBuffer(); - var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); await OpenDocumentAsync(testLspServer, document); @@ -95,8 +88,8 @@ public async Task TestDocumentDiagnosticsForOpenFilesWithFSAOff_Categories(bool var semanticResults = await RunGetDocumentPullDiagnosticsAsync( testLspServer, document.GetURI(), useVSDiagnostics, category: PullDiagnosticCategories.DocumentCompilerSemantic); - Assert.Equal("CS1513", syntaxResults.Single().Diagnostics.Single().Code); - Assert.Equal("CS0246", semanticResults.Single().Diagnostics.Single().Code); + Assert.Equal("CS1513", syntaxResults.Single().Diagnostics!.Single().Code); + Assert.Equal("CS0246", semanticResults.Single().Diagnostics!.Single().Code); var syntaxResults2 = await RunGetDocumentPullDiagnosticsAsync( testLspServer, document.GetURI(), useVSDiagnostics, previousResultId: syntaxResults.Single().ResultId, category: PullDiagnosticCategories.DocumentCompilerSyntax); @@ -112,8 +105,8 @@ public async Task TestDocumentDiagnosticsForOpenFilesWithFSAOff_Categories(bool var semanticAnalyzerResults = await RunGetDocumentPullDiagnosticsAsync( testLspServer, document.GetURI(), useVSDiagnostics, category: PullDiagnosticCategories.DocumentAnalyzerSemantic); - Assert.Equal(CSharpSyntaxAnalyzer.RuleId, syntaxAnalyzerResults.Single().Diagnostics.Single().Code); - Assert.Equal(CSharpSemanticAnalyzer.RuleId, semanticAnalyzerResults.Single().Diagnostics.Single().Code); + Assert.Equal(CSharpSyntaxAnalyzer.RuleId, syntaxAnalyzerResults.Single().Diagnostics!.Single().Code); + Assert.Equal(CSharpSemanticAnalyzer.RuleId, semanticAnalyzerResults.Single().Diagnostics!.Single().Code); var syntaxAnalyzerResults2 = await RunGetDocumentPullDiagnosticsAsync( testLspServer, document.GetURI(), useVSDiagnostics, previousResultId: syntaxAnalyzerResults.Single().ResultId, category: PullDiagnosticCategories.DocumentAnalyzerSyntax); @@ -157,38 +150,33 @@ public override void Initialize(AnalysisContext context) public async Task TestDocumentDiagnosticsHasVSExpandedMessage(bool mutatingLspWorkspace) { var markup = -@"internal class Program -{ - static void Main(string[] args) - { - } -}"; + """ + internal class Program + { + static void Main(string[] args) + { + } + } + """; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync(markup, mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics: true); - // Calling GetTextBuffer will effectively open the file. - testLspServer.TestWorkspace.Documents.Single().GetTextBuffer(); - var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); await OpenDocumentAsync(testLspServer, document); var results = await RunGetDocumentPullDiagnosticsAsync( testLspServer, document.GetURI(), useVSDiagnostics: true); - Assert.Equal("IDE0060", results.Single().Diagnostics.Single().Code); - var vsDiagnostic = (VSDiagnostic)results.Single().Diagnostics.Single(); + Assert.Equal("IDE0060", results.Single().Diagnostics!.Single().Code); + var vsDiagnostic = (VSDiagnostic)results.Single().Diagnostics!.Single(); Assert.Equal(vsDiagnostic.ExpandedMessage, AnalyzersResources.Avoid_unused_parameters_in_your_code_If_the_parameter_cannot_be_removed_then_change_its_name_so_it_starts_with_an_underscore_and_is_optionally_followed_by_an_integer_such_as__comma__1_comma__2_etc_These_are_treated_as_special_discard_symbol_names); } [Theory, CombinatorialData, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/2050705")] public async Task TestDocumentDiagnosticsUsesNullForExpandedMessage(bool mutatingLspWorkspace) { - var markup = -@"class A {"; + var markup = @"class A {"; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync(markup, mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics: true); - // Calling GetTextBuffer will effectively open the file. - testLspServer.TestWorkspace.Documents.Single().GetTextBuffer(); - var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); await OpenDocumentAsync(testLspServer, document); @@ -196,8 +184,8 @@ public async Task TestDocumentDiagnosticsUsesNullForExpandedMessage(bool mutatin var results = await RunGetDocumentPullDiagnosticsAsync( testLspServer, document.GetURI(), useVSDiagnostics: true); - Assert.Equal("CS1513", results.Single().Diagnostics.Single().Code); - var vsDiagnostic = (VSDiagnostic)results.Single().Diagnostics.Single(); + Assert.Equal("CS1513", results.Single().Diagnostics!.Single().Code); + var vsDiagnostic = (VSDiagnostic)results.Single().Diagnostics!.Single(); Assert.Null(vsDiagnostic.ExpandedMessage); } @@ -205,15 +193,13 @@ public async Task TestDocumentDiagnosticsUsesNullForExpandedMessage(bool mutatin public async Task TestDocumentTodoCommentsDiagnosticsForOpenFile_Category(bool mutatingLspWorkspace) { var markup = -@" -// todo: goo -class A { -}"; + """ + // todo: goo + class A { + } + """; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync(markup, mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics: true); - // Calling GetTextBuffer will effectively open the file. - testLspServer.TestWorkspace.Documents.Single().GetTextBuffer(); - var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); await OpenDocumentAsync(testLspServer, document); @@ -221,38 +207,31 @@ class A { var results = await RunGetDocumentPullDiagnosticsAsync( testLspServer, document.GetURI(), useVSDiagnostics: true, category: PullDiagnosticCategories.Task); - Assert.Equal("TODO", results.Single().Diagnostics.Single().Code); - Assert.Equal("todo: goo", results.Single().Diagnostics.Single().Message); + Assert.Equal("TODO", results.Single().Diagnostics!.Single().Code); + Assert.Equal("todo: goo", results.Single().Diagnostics!.Single().Message); } [Theory, CombinatorialData] public async Task TestDocumentDiagnosticsForOpenFilesIfDefaultAndFeatureFlagOn(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var markup = -@"class A {"; + var markup = @"class A {"; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, GetInitializationOptions(BackgroundAnalysisScope.OpenFiles, CompilerDiagnosticsScope.OpenFiles, useVSDiagnostics)); - // Calling GetTextBuffer will effectively open the file. - testLspServer.TestWorkspace.Documents.Single().GetTextBuffer(); var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); await OpenDocumentAsync(testLspServer, document); var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI(), useVSDiagnostics); - Assert.Equal("CS1513", results.Single().Diagnostics.Single().Code); + Assert.Equal("CS1513", results.Single().Diagnostics!.Single().Code); } [Theory, CombinatorialData] public async Task TestDocumentDiagnosticsForRemovedDocument(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var markup = -@"class A {"; + var markup = @"class A {"; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync(markup, mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics); var workspace = testLspServer.TestWorkspace; - // Calling GetTextBuffer will effectively open the file. - workspace.Documents.Single().GetTextBuffer(); - var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); // Get the diagnostics for the solution containing the doc. @@ -262,7 +241,7 @@ public async Task TestDocumentDiagnosticsForRemovedDocument(bool useVSDiagnostic var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI(), useVSDiagnostics).ConfigureAwait(false); - Assert.Equal("CS1513", results.Single().Diagnostics.Single().Code); + Assert.Equal("CS1513", results.Single().Diagnostics!.Single().Code); // Now remove the doc. workspace.OnDocumentRemoved(workspace.Documents.Single().Id); @@ -278,20 +257,16 @@ public async Task TestDocumentDiagnosticsForRemovedDocument(bool useVSDiagnostic [Theory, CombinatorialData] public async Task TestNoChangeIfDocumentDiagnosticsCalledTwice(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var markup = -@"class A {"; + var markup = @"class A {"; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync(markup, mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics); - // Calling GetTextBuffer will effectively open the file. - testLspServer.TestWorkspace.Documents.Single().GetTextBuffer(); - var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); await OpenDocumentAsync(testLspServer, document); var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI(), useVSDiagnostics); - Assert.Equal("CS1513", results.Single().Diagnostics.Single().Code); + Assert.Equal("CS1513", results.Single().Diagnostics!.Single().Code); var resultId = results.Single().ResultId; results = await RunGetDocumentPullDiagnosticsAsync( @@ -305,20 +280,16 @@ public async Task TestNoChangeIfDocumentDiagnosticsCalledTwice(bool useVSDiagnos [WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1481208")] public async Task TestDocumentDiagnosticsWhenGlobalStateChanges(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var markup = -@"class A {"; + var markup = @"class A {"; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync(markup, mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics); - // Calling GetTextBuffer will effectively open the file. - testLspServer.TestWorkspace.Documents.Single().GetTextBuffer(); - var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); await OpenDocumentAsync(testLspServer, document); var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI(), useVSDiagnostics); - Assert.Equal("CS1513", results.Single().Diagnostics.Single().Code); + Assert.Equal("CS1513", results.Single().Diagnostics!.Single().Code); var resultId = results.Single().ResultId; @@ -336,21 +307,18 @@ public async Task TestDocumentDiagnosticsWhenGlobalStateChanges(bool useVSDiagno [Theory, CombinatorialData] public async Task TestDocumentDiagnosticsRemovedAfterErrorIsFixed(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var markup = -@"class A {"; + var markup = @"class A {"; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync(markup, mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics); - // Calling GetTextBuffer will effectively open the file. - var buffer = testLspServer.TestWorkspace.Documents.Single().GetTextBuffer(); - var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); + var text = await document.GetTextAsync(); await OpenDocumentAsync(testLspServer, document); var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI(), useVSDiagnostics); - Assert.Equal("CS1513", results[0].Diagnostics.Single().Code); + Assert.Equal("CS1513", results[0].Diagnostics!.Single().Code); - await InsertTextAsync(testLspServer, document, buffer.CurrentSnapshot.Length, "}"); + await InsertTextAsync(testLspServer, document, text.Length, "}"); results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI(), useVSDiagnostics, results.Single().ResultId); AssertEx.Empty(results[0].Diagnostics); @@ -359,42 +327,37 @@ public async Task TestDocumentDiagnosticsRemovedAfterErrorIsFixed(bool useVSDiag [Theory, CombinatorialData] public async Task TestDocumentDiagnosticsRemainAfterErrorIsNotFixed(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var markup = -@"class A {"; + var markup = @"class A {"; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync(markup, mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics); - // Calling GetTextBuffer will effectively open the file. - var buffer = testLspServer.TestWorkspace.Documents.Single().GetTextBuffer(); - var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); + var text = await document.GetTextAsync(); await OpenDocumentAsync(testLspServer, document); var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI(), useVSDiagnostics); - Assert.Equal("CS1513", results[0].Diagnostics.Single().Code); - Assert.Equal(new Position { Line = 0, Character = 9 }, results[0].Diagnostics.Single().Range.Start); + Assert.Equal("CS1513", results[0].Diagnostics!.Single().Code); + Assert.Equal(new Position { Line = 0, Character = 9 }, results[0].Diagnostics!.Single().Range.Start); - buffer.Insert(0, " "); await InsertTextAsync(testLspServer, document, position: 0, text: " "); results = await RunGetDocumentPullDiagnosticsAsync( testLspServer, document.GetURI(), useVSDiagnostics, previousResultId: results[0].ResultId); - Assert.Equal("CS1513", results[0].Diagnostics.Single().Code); - Assert.Equal(new Position { Line = 0, Character = 10 }, results[0].Diagnostics.Single().Range.Start); + Assert.Equal("CS1513", results[0].Diagnostics!.Single().Code); + Assert.Equal(new Position { Line = 0, Character = 10 }, results[0].Diagnostics!.Single().Range.Start); } [Theory, CombinatorialData] public async Task TestDocumentDiagnosticsAreNotMapped(bool useVSDiagnostics, bool mutatingLspWorkspace) { var markup = -@"#line 1 ""test.txt"" -class A {"; + """ + #line 1 "test.txt" + class A { + """; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync(markup, mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics); - // Calling GetTextBuffer will effectively open the file. - testLspServer.TestWorkspace.Documents.Single().GetTextBuffer(); - var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); await OpenDocumentAsync(testLspServer, document); @@ -402,46 +365,46 @@ class A {"; var results = await RunGetDocumentPullDiagnosticsAsync( testLspServer, document.GetURI(), useVSDiagnostics); - Assert.Equal("CS1513", results.Single().Diagnostics.Single().Code); - Assert.Equal(1, results.Single().Diagnostics.Single().Range.Start.Line); + Assert.Equal("CS1513", results.Single().Diagnostics!.Single().Code); + Assert.Equal(1, results.Single().Diagnostics!.Single().Range.Start.Line); } [Theory, CombinatorialData] public async Task TestStreamingDocumentDiagnostics(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var markup = -@"class A {"; + var markup = @"class A {"; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync(markup, mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics); - // Calling GetTextBuffer will effectively open the file. - testLspServer.TestWorkspace.Documents.Single().GetTextBuffer(); - var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); await OpenDocumentAsync(testLspServer, document); var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI(), useVSDiagnostics, useProgress: true); - Assert.Equal("CS1513", results!.Single().Diagnostics.Single().Code); + Assert.Equal("CS1513", results!.Single().Diagnostics!.Single().Code); } [Theory, CombinatorialData] public async Task TestDocumentDiagnosticsForOpenFilesUsesActiveContext(bool useVSDiagnostics, bool mutatingLspWorkspace) { var documentText = -@"#if ONE -class A { -#endif -class B {"; + """ + #if ONE + class A { + #endif + class B { + """; var workspaceXml = -@$" - - {documentText} - - - {documentText} - -"; + $""" + + + {documentText} + + + {documentText} + + + """; await using var testLspServer = await CreateTestWorkspaceFromXmlAsync(workspaceXml, mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics); @@ -451,18 +414,21 @@ class B {"; // Open either of the documents via LSP, we're tracking the URI and text. await OpenDocumentAsync(testLspServer, csproj1Document); - // This opens all documents in the workspace and ensures buffers are created. - testLspServer.TestWorkspace.GetTestDocument(csproj1Document.Id)!.GetTextBuffer(); + // If we don't have a mutating workspace, we need to manually open all linked documents in the workspace (otherwise updating the context will not succeed). + if (!mutatingLspWorkspace) + { + await testLspServer.OpenDocumentInWorkspaceAsync(csproj2Document.Id, openAllLinkedDocuments: true); + } // Set CSProj2 as the active context and get diagnostics. testLspServer.TestWorkspace.SetDocumentContext(csproj2Document.Id); var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, csproj2Document.GetURI(), useVSDiagnostics); - Assert.Equal("CS1513", results.Single().Diagnostics.Single().Code); + Assert.Equal("CS1513", results.Single().Diagnostics!.Single().Code); if (useVSDiagnostics) { // Only VSDiagnostics will have the project. - var vsDiagnostic = (LSP.VSDiagnostic)results.Single().Diagnostics.Single(); - Assert.Equal("CSProj2", vsDiagnostic.Projects.Single().ProjectName); + var vsDiagnostic = (LSP.VSDiagnostic)results.Single().Diagnostics!.Single(); + Assert.Equal("CSProj2", vsDiagnostic.Projects!.Single().ProjectName); } // Set CSProj1 as the active context and get diagnostics. @@ -473,24 +439,25 @@ class B {"; if (useVSDiagnostics) { - AssertEx.All(results.Single().Diagnostics, d => Assert.Equal("CSProj1", ((VSDiagnostic)d).Projects.Single().ProjectName)); + AssertEx.All(results.Single().Diagnostics, d => Assert.Equal("CSProj1", ((VSDiagnostic)d).Projects!.Single().ProjectName)); } } [Theory, CombinatorialData] public async Task TestDocumentDiagnosticsHasSameIdentifierForLinkedFile(bool mutatingLspWorkspace) { - var documentText = -@"class A { err }"; + var documentText = @"class A { err }"; var workspaceXml = -@$" - - {documentText} - - - {documentText} - -"; + $""" + + + {documentText} + + + {documentText} + + + """; await using var testLspServer = await CreateTestWorkspaceFromXmlAsync(workspaceXml, mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics: false); @@ -501,9 +468,9 @@ public async Task TestDocumentDiagnosticsHasSameIdentifierForLinkedFile(bool mut await OpenDocumentAsync(testLspServer, csproj1Document); var csproj1Results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, GetVsTextDocumentIdentifier(csproj1Document), useVSDiagnostics: true); - var csproj1Diagnostic = (VSDiagnostic)csproj1Results.Single().Diagnostics.Single(); + var csproj1Diagnostic = (VSDiagnostic)csproj1Results.Single().Diagnostics!.Single(); var csproj2Results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, GetVsTextDocumentIdentifier(csproj2Document), useVSDiagnostics: true); - var csproj2Diagnostic = (VSDiagnostic)csproj2Results.Single().Diagnostics.Single(); + var csproj2Diagnostic = (VSDiagnostic)csproj2Results.Single().Diagnostics!.Single(); Assert.Equal(csproj1Diagnostic.Identifier, csproj2Diagnostic.Identifier); static VSTextDocumentIdentifier GetVsTextDocumentIdentifier(Document document) @@ -525,26 +492,32 @@ static VSTextDocumentIdentifier GetVsTextDocumentIdentifier(Document document) public async Task TestDocumentDiagnosticsWithChangeInReferencedProject(bool useVSDiagnostics, bool mutatingLspWorkspace) { var markup1 = -@"namespace M -{ - class A : B { } -}"; + """ + namespace M + { + class A : B { } + } + """; var markup2 = -@"namespace M -{ - public class {|caret:|} { } -}"; + """ + namespace M + { + public class {|caret:|} { } + } + """; var workspaceXml = -@$" - - {markup1} - CSProj2 - - - {markup2} - -"; + $""" + + + {markup1} + CSProj2 + + + {markup2} + + + """; await using var testLspServer = await CreateTestWorkspaceFromXmlAsync(workspaceXml, mutatingLspWorkspace, BackgroundAnalysisScope.FullSolution, useVSDiagnostics).ConfigureAwait(false); var csproj1Document = testLspServer.GetCurrentSolution().Projects.Where(p => p.Name == "CSProj1").Single().Documents.First(); @@ -556,7 +529,7 @@ public class {|caret:|} { } // Verify we a diagnostic in A.cs since B does not exist. var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, csproj1Document.GetURI(), useVSDiagnostics); Assert.Single(results); - Assert.Equal("CS0246", results.Single().Diagnostics.Single().Code); + Assert.Equal("CS0246", results.Single().Diagnostics!.Single().Code); // Insert B into B.cs and verify that the error in A.cs is now gone. var locationToReplace = testLspServer.GetLocations("caret").Single().Range; @@ -572,25 +545,31 @@ public class {|caret:|} { } public async Task TestDocumentDiagnosticsWithChangeInNotReferencedProject(bool useVSDiagnostics, bool mutatingLspWorkspace) { var markup1 = -@"namespace M -{ - class A : B { } -}"; + """ + namespace M + { + class A : B { } + } + """; var markup2 = -@"namespace M -{ - public class {|caret:|} { } -}"; + """ + namespace M + { + public class {|caret:|} { } + } + """; var workspaceXml = -@$" - - {markup1} - - - {markup2} - -"; + $""" + + + {markup1} + + + {markup2} + + + """; await using var testLspServer = await CreateTestWorkspaceFromXmlAsync(workspaceXml, mutatingLspWorkspace, BackgroundAnalysisScope.FullSolution, useVSDiagnostics).ConfigureAwait(false); var csproj1Document = testLspServer.GetCurrentSolution().Projects.Where(p => p.Name == "CSProj1").Single().Documents.First(); @@ -602,7 +581,7 @@ public class {|caret:|} { } // Verify we get a diagnostic in A since the class B does not exist. var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, csproj1Document.GetURI(), useVSDiagnostics); Assert.Single(results); - Assert.Equal("CS0246", results.Single().Diagnostics.Single().Code); + Assert.Equal("CS0246", results.Single().Diagnostics!.Single().Code); // Add B to CSProj2 and verify that we get an unchanged result (still has diagnostic) for A.cs // since CSProj1 does not reference CSProj2 @@ -618,15 +597,11 @@ public class {|caret:|} { } [Theory, CombinatorialData] public async Task TestDocumentDiagnosticsFromRazorServer(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var markup = -@"class A {"; + var markup = @"class A {"; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, GetInitializationOptions(BackgroundAnalysisScope.OpenFiles, CompilerDiagnosticsScope.OpenFiles, useVSDiagnostics, WellKnownLspServerKinds.RazorLspServer)); - // Calling GetTextBuffer will effectively open the file. - testLspServer.TestWorkspace.Documents.Single().GetTextBuffer(); - var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); await OpenDocumentAsync(testLspServer, document); @@ -635,22 +610,18 @@ public async Task TestDocumentDiagnosticsFromRazorServer(bool useVSDiagnostics, testLspServer, document.GetURI(), useVSDiagnostics); // Assert that we have diagnostics even though the option is set to push. - Assert.Equal("CS1513", results.Single().Diagnostics.Single().Code); - Assert.NotNull(results.Single().Diagnostics.Single().CodeDescription!.Href); + Assert.Equal("CS1513", results.Single().Diagnostics!.Single().Code); + Assert.NotNull(results.Single().Diagnostics!.Single().CodeDescription!.Href); } [Theory, CombinatorialData] public async Task TestDocumentDiagnosticsFromLiveShareServer(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var markup = -@"class A {"; + var markup = @"class A {"; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, GetInitializationOptions(BackgroundAnalysisScope.OpenFiles, CompilerDiagnosticsScope.OpenFiles, useVSDiagnostics, WellKnownLspServerKinds.LiveShareLspServer)); - // Calling GetTextBuffer will effectively open the file. - testLspServer.TestWorkspace.Documents.Single().GetTextBuffer(); - var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); await OpenDocumentAsync(testLspServer, document); @@ -659,8 +630,96 @@ public async Task TestDocumentDiagnosticsFromLiveShareServer(bool useVSDiagnosti testLspServer, document.GetURI(), useVSDiagnostics); // Assert that we have diagnostics even though the option is set to push. - Assert.Equal("CS1513", results.Single().Diagnostics.Single().Code); - Assert.NotNull(results.Single().Diagnostics.Single().CodeDescription!.Href); + Assert.Equal("CS1513", results.Single().Diagnostics!.Single().Code); + Assert.NotNull(results.Single().Diagnostics!.Single().CodeDescription!.Href); + } + + [Theory, CombinatorialData] + internal async Task TestDocumentDiagnosticsUpdatesSourceGeneratorDiagnostics(bool useVSDiagnostics, bool mutatingLspWorkspace, SourceGeneratorExecutionPreference executionPreference) + { + var markup = """ + public {|insert:|}class C + { + public int F => _field; + } + """; + + await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync( + markup, mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics); + + // Set execution mode preference. + var configService = testLspServer.TestWorkspace.ExportProvider.GetExportedValue(); + configService.Options = new WorkspaceConfigurationOptions(SourceGeneratorExecution: executionPreference); + + var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); + + // Add a generator to the solution that reports a diagnostic if the text matches original markup + var generator = new CallbackGenerator(onInit: (_) => { }, onExecute: context => + { + var tree = context.Compilation.SyntaxTrees.Single(); + var text = tree.GetText(CancellationToken.None).ToString(); + if (text.Contains("public partial class C")) + { + context.AddSource("blah", """ + public partial class C + { + private readonly int _field = 1; + } + """); + } + }); + + testLspServer.TestWorkspace.OnAnalyzerReferenceAdded( + document.Project.Id, + new TestGeneratorReference(generator)); + await testLspServer.WaitForSourceGeneratorsAsync(); + + await OpenDocumentAsync(testLspServer, document); + + // First diagnostic request should report a diagnostic since the generator does not produce any source (text does not match). + var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI(), useVSDiagnostics); + var diagnostic = AssertEx.Single(results.Single().Diagnostics); + Assert.Equal("CS0103", diagnostic.Code); + + // Update the text to include the text trigger the source generator relies on. + var textLocation = testLspServer.GetLocations()["insert"].Single(); + + var textEdit = new LSP.TextEdit { Range = textLocation.Range, NewText = "partial " }; + if (mutatingLspWorkspace) + { + // In the mutating workspace, we just need to update the LSP text (which will flow into the workspace). + await testLspServer.ReplaceTextAsync(textLocation.Uri, (textEdit.Range, textEdit.NewText)); + await WaitForWorkspaceOperationsAsync(testLspServer.TestWorkspace); + } + else + { + // In the non-mutating workspace, we need to ensure that both the workspace and LSP view of the world are updated. + var workspaceText = await document.GetTextAsync(CancellationToken.None); + var textChange = ProtocolConversions.TextEditToTextChange(textEdit, workspaceText); + await testLspServer.TestWorkspace.ChangeDocumentAsync(document.Id, workspaceText.WithChanges(textChange)); + await testLspServer.ReplaceTextAsync(textLocation.Uri, (textEdit.Range, textEdit.NewText)); + } + + await testLspServer.WaitForSourceGeneratorsAsync(); + results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI(), useVSDiagnostics); + + if (executionPreference == SourceGeneratorExecutionPreference.Automatic) + { + // In automatic mode, the diagnostic should be immediately removed as the source generator ran and produced the required field. + Assert.Empty(results.Single().Diagnostics!); + } + else + { + // In balanced mode, the diagnostic should remain until there is a manual source generator run that updates the sg text. + diagnostic = AssertEx.Single(results.Single().Diagnostics); + Assert.Equal("CS0103", diagnostic.Code); + + testLspServer.TestWorkspace.EnqueueUpdateSourceGeneratorVersion(document.Project.Id, forceRegeneration: false); + await testLspServer.WaitForSourceGeneratorsAsync(); + + results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI(), useVSDiagnostics); + Assert.Empty(results.Single().Diagnostics!); + } } [Theory, CombinatorialData] @@ -670,12 +729,12 @@ public async Task TestDocumentDiagnosticsIncludesSourceGeneratorDiagnostics(bool await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync( markup, mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics); - // Calling GetTextBuffer will effectively open the file. - testLspServer.TestWorkspace.Documents.Single().GetTextBuffer(); - var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); - var generator = new DiagnosticProducingGenerator(context => Location.Create(context.Compilation.SyntaxTrees.Single(), new TextSpan(0, 10))); + var generator = new DiagnosticProducingGenerator(context => + { + return Location.Create(context.Compilation.SyntaxTrees.Single(), new TextSpan(0, 10)); + }); testLspServer.TestWorkspace.OnAnalyzerReferenceAdded( document.Project.Id, @@ -694,12 +753,13 @@ public async Task TestDocumentDiagnosticsIncludesSourceGeneratorDiagnostics(bool public async Task TestDocumentDiagnosticsWithFadingOptionOn(bool useVSDiagnostics, bool mutatingLspWorkspace) { var markup = -@" -{|first:using System.Linq; -using System.Threading;|} -class A -{ -}"; + """ + {|first:using System.Linq; + using System.Threading;|} + class A + { + } + """; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync(markup, mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics); var firstLocation = testLspServer.GetLocations("first").Single().Range; testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption(FadingOptions.FadeOutUnusedImports, LanguageNames.CSharp, true); @@ -733,12 +793,13 @@ class A public async Task TestDocumentDiagnosticsWithFadingOptionOff(bool useVSDiagnostics, bool mutatingLspWorkspace) { var markup = -@" -{|first:using System.Linq; -using System.Threading;|} -class A -{ -}"; + """ + {|first:using System.Linq; + using System.Threading;|} + class A + { + } + """; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync(markup, mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics); var firstLocation = testLspServer.GetLocations("first").Single().Range; testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption(FadingOptions.FadeOutUnusedImports, LanguageNames.CSharp, false); @@ -757,14 +818,16 @@ class A public async Task TestDocumentDiagnosticsWithNotConfigurableFading(bool useVSDiagnostics, bool mutatingLspWorkspace) { var markup = -@"class A -{ - void M() - { - _ = {|line:{|open:(|}1 + 2 +|} - 3 + 4{|close:)|}; - } -}"; + """ + class A + { + void M() + { + _ = {|line:{|open:(|}1 + 2 +|} + 3 + 4{|close:)|}; + } + } + """; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync(markup, mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics); var openLocation = testLspServer.GetLocations("open").Single().Range; var closeLocation = testLspServer.GetLocations("close").Single().Range; @@ -794,14 +857,14 @@ void M() else { // There should be one unnecessary diagnostic. - Assert.True(results.Single().Diagnostics.Single().Tags!.Contains(DiagnosticTag.Unnecessary)); - Assert.Equal(lineLocation, results.Single().Diagnostics.Single().Range); + Assert.True(results.Single().Diagnostics!.Single().Tags!.Contains(DiagnosticTag.Unnecessary)); + Assert.Equal(lineLocation, results.Single().Diagnostics!.Single().Range); // There should be an additional location for the open paren. - Assert.Equal(openLocation, results.Single().Diagnostics.Single().RelatedInformation![0].Location.Range); + Assert.Equal(openLocation, results.Single().Diagnostics!.Single().RelatedInformation![0].Location.Range); // There should be an additional location for the close paren. - Assert.Equal(closeLocation, results.Single().Diagnostics.Single().RelatedInformation![1].Location.Range); + Assert.Equal(closeLocation, results.Single().Diagnostics!.Single().RelatedInformation![1].Location.Range); } } @@ -818,22 +881,23 @@ public async Task TestDocumentDiagnosticsForUnnecessarySuppressions(bool useVSDi var results = await RunGetDocumentPullDiagnosticsAsync( testLspServer, document.GetURI(), useVSDiagnostics); - Assert.Equal(IDEDiagnosticIds.RemoveUnnecessarySuppressionDiagnosticId, results.Single().Diagnostics.Single().Code); + Assert.Equal(IDEDiagnosticIds.RemoveUnnecessarySuppressionDiagnosticId, results.Single().Diagnostics!.Single().Code); } [Theory, CombinatorialData, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1824321")] public async Task TestDocumentDiagnosticsForSourceSuppressions(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var markup = @" -class C -{ - void M() - { -#pragma warning disable CS0168 // Variable is declared but never used - int x; -#pragma warning restore CS0168 // Variable is declared but never used - } -}"; + var markup = """ + class C + { + void M() + { + #pragma warning disable CS0168 // Variable is declared but never used + int x; + #pragma warning restore CS0168 // Variable is declared but never used + } + } + """; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync(markup, mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics); var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); @@ -850,15 +914,14 @@ void M() public async Task TestInfoDiagnosticsAreReportedAsInformationInVS(bool mutatingLspWorkspace) { var markup = -@"class A -{ - public A SomeA = new A(); -}"; + """ + class A + { + public A SomeA = new A(); + } + """; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync(markup, mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics: true); - // Calling GetTextBuffer will effectively open the file. - testLspServer.TestWorkspace.Documents.Single().GetTextBuffer(); - var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); await OpenDocumentAsync(testLspServer, document); @@ -866,32 +929,8 @@ public async Task TestInfoDiagnosticsAreReportedAsInformationInVS(bool mutatingL var results = await RunGetDocumentPullDiagnosticsAsync( testLspServer, document.GetURI(), useVSDiagnostics: true); - Assert.Equal("IDE0090", results.Single().Diagnostics.Single().Code); - Assert.Equal(LSP.DiagnosticSeverity.Information, results.Single().Diagnostics.Single().Severity); - } - - [Theory, CombinatorialData] - public async Task TestInfoDiagnosticsAreReportedAsHintInVSCode(bool mutatingLspWorkspace) - { - var markup = -@"class A -{ - public A SomeA = new A(); -}"; - await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync(markup, mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics: false); - - // Calling GetTextBuffer will effectively open the file. - testLspServer.TestWorkspace.Documents.Single().GetTextBuffer(); - - var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); - - await OpenDocumentAsync(testLspServer, document); - - var results = await RunGetDocumentPullDiagnosticsAsync( - testLspServer, document.GetURI(), useVSDiagnostics: false); - - Assert.Equal("IDE0090", results.Single().Diagnostics.Single().Code); - Assert.Equal(LSP.DiagnosticSeverity.Hint, results.Single().Diagnostics.Single().Severity); + Assert.Equal("IDE0090", results.Single().Diagnostics!.Single().Code); + Assert.Equal(LSP.DiagnosticSeverity.Information, results.Single().Diagnostics!.Single().Severity); } #endregion @@ -901,8 +940,7 @@ public async Task TestInfoDiagnosticsAreReportedAsHintInVSCode(bool mutatingLspW [Theory, CombinatorialData] public async Task TestNoWorkspaceDiagnosticsForClosedFilesWithFSAOff(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var markup1 = -@"class A {"; + var markup1 = @"class A {"; var markup2 = ""; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync( [markup1, markup2], mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics); @@ -915,8 +953,7 @@ public async Task TestNoWorkspaceDiagnosticsForClosedFilesWithFSAOff(bool useVSD [Theory, CombinatorialData] public async Task TestWorkspaceDiagnosticsForClosedFilesWithFSAOn(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var markup1 = -@"class A {"; + var markup1 = @"class A {"; var markup2 = ""; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync( [markup1, markup2], mutatingLspWorkspace, BackgroundAnalysisScope.FullSolution, useVSDiagnostics); @@ -924,7 +961,7 @@ public async Task TestWorkspaceDiagnosticsForClosedFilesWithFSAOn(bool useVSDiag var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); Assert.Equal(3, results.Length); - Assert.Equal("CS1513", results[0].Diagnostics.Single().Code); + Assert.Equal("CS1513", results[0].Diagnostics!.Single().Code); AssertEx.Empty(results[1].Diagnostics); AssertEx.Empty(results[2].Diagnostics); } @@ -932,8 +969,7 @@ public async Task TestWorkspaceDiagnosticsForClosedFilesWithFSAOn(bool useVSDiag [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/65967")] public async Task TestWorkspaceDiagnosticsForClosedFilesWithRunCodeAnalysisAndFSAOff(bool useVSDiagnostics, bool mutatingLspWorkspace, bool scopeRunCodeAnalysisToProject) { - var markup1 = -@"class A {"; + var markup1 = @"class A {"; var markup2 = ""; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync( [markup1, markup2], mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics); @@ -944,16 +980,15 @@ public async Task TestWorkspaceDiagnosticsForClosedFilesWithRunCodeAnalysisAndFS var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); Assert.Equal(3, results.Length); - Assert.Equal("CS1513", results[0].Diagnostics.Single().Code); + Assert.Equal("CS1513", results[0].Diagnostics!.Single().Code); // this should be considered a build-error, since it was produced by the last code-analysis run. - Assert.Contains(VSDiagnosticTags.BuildError, results[0].Diagnostics.Single().Tags!); + Assert.Contains(VSDiagnosticTags.BuildError, results[0].Diagnostics!.Single().Tags!); AssertEx.Empty(results[1].Diagnostics); AssertEx.Empty(results[2].Diagnostics); // Now fix the compiler error, but don't re-execute code analysis. // Verify that we still get the workspace diagnostics from the prior snapshot on which code analysis was executed. - var buffer = testLspServer.TestWorkspace.Documents.First().GetTextBuffer(); - buffer.Insert(buffer.CurrentSnapshot.Length, "}"); + await InsertInClosedDocumentAsync(testLspServer, testLspServer.TestWorkspace.Documents.First().Id, "}"); var results2 = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics, previousResults: CreateDiagnosticParamsFromPreviousReports(results)); @@ -973,8 +1008,7 @@ public async Task TestWorkspaceDiagnosticsForClosedFilesWithRunCodeAnalysisAndFS [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/65967")] public async Task TestWorkspaceDiagnosticsForClosedFilesWithRunCodeAnalysisFSAOn(bool useVSDiagnostics, bool mutatingLspWorkspace, bool scopeRunCodeAnalysisToProject) { - var markup1 = -@"class A {"; + var markup1 = @"class A {"; var markup2 = ""; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync( [markup1, markup2], mutatingLspWorkspace, BackgroundAnalysisScope.FullSolution, useVSDiagnostics); @@ -986,16 +1020,15 @@ public async Task TestWorkspaceDiagnosticsForClosedFilesWithRunCodeAnalysisFSAOn var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); Assert.Equal(3, results.Length); - Assert.Equal("CS1513", results[0].Diagnostics.Single().Code); + Assert.Equal("CS1513", results[0].Diagnostics!.Single().Code); // this should *not* be considered a build-error, since it was produced by the live workspace results. - Assert.DoesNotContain(VSDiagnosticTags.BuildError, results[0].Diagnostics.Single().Tags!); + Assert.DoesNotContain(VSDiagnosticTags.BuildError, results[0].Diagnostics!.Single().Tags!); AssertEx.Empty(results[1].Diagnostics); AssertEx.Empty(results[2].Diagnostics); // Now fix the compiler error, but don't rerun code analysis. // Verify that we get up-to-date workspace diagnostics, i.e. no compiler errors, from the current snapshot because FSA is enabled. - var buffer = testLspServer.TestWorkspace.Documents.First().GetTextBuffer(); - buffer.Insert(buffer.CurrentSnapshot.Length, "}"); + await InsertInClosedDocumentAsync(testLspServer, testLspServer.TestWorkspace.Documents.First().Id, "}"); var results2 = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics, previousResults: CreateDiagnosticParamsFromPreviousReports(results)); @@ -1033,17 +1066,18 @@ public async Task SourceGeneratorFailures_FSA(bool useVSDiagnostics, bool mutati Assert.Equal(2, results.Length); AssertEx.Empty(results[0].Diagnostics); - Assert.True(results[1].Diagnostics.Single().Message.Contains("Source generator failed")); + Assert.True(results[1].Diagnostics!.Single().Message.Contains("Source generator failed")); } [Theory, CombinatorialData] public async Task TestWorkspaceTodoForClosedFilesWithFSAOffAndTodoOff(bool mutatingLspWorkspace) { var markup1 = -@" -// todo: goo -class A { -}"; + """ + // todo: goo + class A { + } + """; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync( [markup1], mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics: true); @@ -1056,19 +1090,20 @@ class A { public async Task TestWorkspaceTodoForClosedFilesWithFSAOffAndTodoOn(bool mutatingLspWorkspace) { var markup1 = -@" -// todo: goo -class A { -}"; + """ + // todo: goo + class A { + } + """; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync( [markup1], mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics: true); var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics: true, includeTaskListItems: true, category: PullDiagnosticCategories.Task); Assert.Equal(1, results.Length); - Assert.Equal("TODO", results[0].Diagnostics.Single().Code); - Assert.Equal("todo: goo", results[0].Diagnostics.Single().Message); - Assert.Equal(VSDiagnosticRank.Default, ((VSDiagnostic)results[0].Diagnostics.Single()).DiagnosticRank); + Assert.Equal("TODO", results[0].Diagnostics!.Single().Code); + Assert.Equal("todo: goo", results[0].Diagnostics!.Single().Message); + Assert.Equal(VSDiagnosticRank.Default, ((VSDiagnostic)results[0].Diagnostics!.Single()).DiagnosticRank); } [Theory] @@ -1083,10 +1118,11 @@ public async Task TestWorkspaceTodoForClosedFilesWithFSAOffAndTodoOn_Priorities( { var rank = (VSDiagnosticRank)intRank; var markup1 = -@" -// todo: goo -class A { -}"; + """ + // todo: goo + class A { + } + """; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync( [markup1], mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics: true); @@ -1097,19 +1133,20 @@ class A { var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics: true, includeTaskListItems: true, category: PullDiagnosticCategories.Task); Assert.Equal(1, results.Length); - Assert.Equal("TODO", results[0].Diagnostics.Single().Code); - Assert.Equal("todo: goo", results[0].Diagnostics.Single().Message); - Assert.Equal(rank, ((VSDiagnostic)results[0].Diagnostics.Single()).DiagnosticRank); + Assert.Equal("TODO", results[0].Diagnostics!.Single().Code); + Assert.Equal("todo: goo", results[0].Diagnostics!.Single().Message); + Assert.Equal(rank, ((VSDiagnostic)results[0].Diagnostics!.Single()).DiagnosticRank); } [Theory, CombinatorialData] public async Task TestWorkspaceTodoForClosedFilesWithFSAOnAndTodoOff(bool mutatingLspWorkspace) { var markup1 = -@" -// todo: goo -class A { -}"; + """ + // todo: goo + class A { + } + """; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync( [markup1], mutatingLspWorkspace, BackgroundAnalysisScope.FullSolution, useVSDiagnostics: true); @@ -1122,10 +1159,11 @@ class A { public async Task TestWorkspaceTodoForClosedFilesWithFSAOnAndTodoOn(bool mutatingLspWorkspace) { var markup1 = -@" -// todo: goo -class A { -}"; + """ + // todo: goo + class A { + } + """; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync( [markup1], mutatingLspWorkspace, BackgroundAnalysisScope.FullSolution, useVSDiagnostics: true); @@ -1133,18 +1171,19 @@ class A { Assert.Equal(1, results.Length); - Assert.Equal("TODO", results[0].Diagnostics.Single().Code); - Assert.Equal("todo: goo", results[0].Diagnostics.Single().Message); + Assert.Equal("TODO", results[0].Diagnostics!.Single().Code); + Assert.Equal("todo: goo", results[0].Diagnostics!.Single().Message); } [Theory, CombinatorialData] public async Task TestWorkspaceTodoAndDiagnosticForClosedFilesWithFSAOnAndTodoOn(bool mutatingLspWorkspace) { var markup1 = -@" -// todo: goo -class A { -"; + """ + // todo: goo + class A { + + """; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync( [markup1], mutatingLspWorkspace, BackgroundAnalysisScope.FullSolution, useVSDiagnostics: true); @@ -1276,30 +1315,33 @@ public async Task EditAndContinue(bool useVSDiagnostics, bool mutatingLspWorkspa AssertEx.Equal([], workspaceResults3.Select(Inspect)); static DiagnosticData CreateDiagnostic(string id, Document? document = null, Project? project = null) - => new( - id, - category: "EditAndContinue", - message: "test message", - severity: DiagnosticSeverity.Error, - defaultSeverity: DiagnosticSeverity.Error, - isEnabledByDefault: true, - warningLevel: 0, - projectId: project?.Id, - customTags: [], - properties: ImmutableDictionary.Empty, - location: new DiagnosticDataLocation(new FileLinePositionSpan("file", span: default), document?.Id), - additionalLocations: [], - language: (project ?? document!.Project).Language); + { + return new( + id, + category: "EditAndContinue", + message: "test message", + severity: DiagnosticSeverity.Error, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true, + warningLevel: 0, + projectId: project?.Id, + customTags: [], + properties: ImmutableDictionary.Empty, + location: new DiagnosticDataLocation(new FileLinePositionSpan("file", span: default), document?.Id), + additionalLocations: [], + language: (project ?? document!.Project).Language); + } static string Inspect(TestDiagnosticResult result) - => $"{result.TextDocument.Uri} -> [{string.Join(",", result.Diagnostics?.Select(d => d.Code?.Value) ?? [])}]"; + { + return $"{result.TextDocument.Uri} -> [{string.Join(",", result.Diagnostics?.Select(d => d.Code?.Value) ?? [])}]"; + } } [Theory, CombinatorialData] public async Task TestNoWorkspaceDiagnosticsForClosedFilesWithFSAOffWithFileInProjectOpen(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var markup1 = -@"class A {"; + var markup1 = @"class A {"; var markup2 = ""; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync( [markup1, markup2], mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics); @@ -1329,7 +1371,7 @@ public async Task TestWorkspaceDiagnosticsIncludesSourceGeneratorDiagnosticsClos var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); - Assert.Equal(DiagnosticProducingGenerator.Descriptor.Id, results[0].Diagnostics.Single().Code); + Assert.Equal(DiagnosticProducingGenerator.Descriptor.Id, results[0].Diagnostics!.Single().Code); AssertEx.Empty(results[1].Diagnostics); } @@ -1356,19 +1398,20 @@ public async Task TestWorkspaceDiagnosticsDoesNotIncludeSourceGeneratorDiagnosti [Theory, CombinatorialData] public async Task TestNoWorkspaceDiagnosticsForClosedFilesInProjectsWithIncorrectLanguage(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var csharpMarkup = -@"class A {"; + var csharpMarkup = @"class A {"; var typeScriptMarkup = "???"; var workspaceXml = -@$" - - {csharpMarkup} - - - {typeScriptMarkup} - -"; + $""" + + + {csharpMarkup} + + + {typeScriptMarkup} + + + """; await using var testLspServer = await CreateTestWorkspaceFromXmlAsync(workspaceXml, mutatingLspWorkspace, BackgroundAnalysisScope.FullSolution, useVSDiagnostics).ConfigureAwait(false); @@ -1380,8 +1423,7 @@ public async Task TestNoWorkspaceDiagnosticsForClosedFilesInProjectsWithIncorrec [Theory, CombinatorialData] public async Task TestWorkspaceDiagnosticsForSourceGeneratedFiles(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var markup1 = -@"class A {"; + var markup1 = @"class A {"; var markup2 = ""; await using var testLspServer = await CreateTestLspServerAsync( markups: [], mutatingLspWorkspace, @@ -1397,15 +1439,14 @@ public async Task TestWorkspaceDiagnosticsForSourceGeneratedFiles(bool useVSDiag Assert.Equal(3, results.Length); // Since we sorted above by URI the first result is the project. AssertEx.Empty(results[0].Diagnostics); - Assert.Equal("CS1513", results[1].Diagnostics.Single().Code); + Assert.Equal("CS1513", results[1].Diagnostics!.Single().Code); AssertEx.Empty(results[2].Diagnostics); } [Theory, CombinatorialData] public async Task TestWorkspaceDiagnosticsForRemovedDocument(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var markup1 = -@"class A {"; + var markup1 = @"class A {"; var markup2 = ""; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync( [markup1, markup2], mutatingLspWorkspace, BackgroundAnalysisScope.FullSolution, useVSDiagnostics); @@ -1413,7 +1454,7 @@ public async Task TestWorkspaceDiagnosticsForRemovedDocument(bool useVSDiagnosti var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); Assert.Equal(3, results.Length); - Assert.Equal("CS1513", results[0].Diagnostics.Single().Code); + Assert.Equal("CS1513", results[0].Diagnostics!.Single().Code); AssertEx.Empty(results[1].Diagnostics); AssertEx.Empty(results[2].Diagnostics); @@ -1431,8 +1472,7 @@ public async Task TestWorkspaceDiagnosticsForRemovedDocument(bool useVSDiagnosti [Theory, CombinatorialData] public async Task TestNoChangeIfWorkspaceDiagnosticsCalledTwice(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var markup1 = -@"class A {"; + var markup1 = @"class A {"; var markup2 = ""; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync( [markup1, markup2], mutatingLspWorkspace, BackgroundAnalysisScope.FullSolution, useVSDiagnostics); @@ -1440,7 +1480,7 @@ public async Task TestNoChangeIfWorkspaceDiagnosticsCalledTwice(bool useVSDiagno var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); Assert.Equal(3, results.Length); - Assert.Equal("CS1513", results[0].Diagnostics.Single().Code); + Assert.Equal("CS1513", results[0].Diagnostics!.Single().Code); AssertEx.Empty(results[1].Diagnostics); AssertEx.Empty(results[2].Diagnostics); @@ -1453,8 +1493,7 @@ public async Task TestNoChangeIfWorkspaceDiagnosticsCalledTwice(bool useVSDiagno [Theory, CombinatorialData] public async Task TestWorkspaceDiagnosticsRemovedAfterErrorIsFixed(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var markup1 = -@"class A {"; + var markup1 = @"class A {"; var markup2 = ""; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync( [markup1, markup2], mutatingLspWorkspace, BackgroundAnalysisScope.FullSolution, useVSDiagnostics); @@ -1462,12 +1501,11 @@ public async Task TestWorkspaceDiagnosticsRemovedAfterErrorIsFixed(bool useVSDia var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); Assert.Equal(3, results.Length); - Assert.Equal("CS1513", results[0].Diagnostics.Single().Code); + Assert.Equal("CS1513", results[0].Diagnostics!.Single().Code); AssertEx.Empty(results[1].Diagnostics); AssertEx.Empty(results[2].Diagnostics); - var buffer = testLspServer.TestWorkspace.Documents.First().GetTextBuffer(); - buffer.Insert(buffer.CurrentSnapshot.Length, "}"); + await InsertInClosedDocumentAsync(testLspServer, testLspServer.TestWorkspace.Documents.First().Id, "}"); var results2 = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics, previousResults: CreateDiagnosticParamsFromPreviousReports(results)); @@ -1480,8 +1518,7 @@ public async Task TestWorkspaceDiagnosticsRemovedAfterErrorIsFixed(bool useVSDia [Theory, CombinatorialData] public async Task TestWorkspaceDiagnosticsRemainAfterErrorIsNotFixed(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var markup1 = -@"class A {"; + var markup1 = @"class A {"; var markup2 = ""; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync( [markup1, markup2], mutatingLspWorkspace, BackgroundAnalysisScope.FullSolution, useVSDiagnostics); @@ -1489,27 +1526,21 @@ public async Task TestWorkspaceDiagnosticsRemainAfterErrorIsNotFixed(bool useVSD var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); Assert.Equal(3, results.Length); - Assert.Equal("CS1513", results[0].Diagnostics.Single().Code); - Assert.Equal(new Position { Line = 0, Character = 9 }, results[0].Diagnostics.Single().Range.Start); + Assert.Equal("CS1513", results[0].Diagnostics!.Single().Code); + Assert.Equal(new Position { Line = 0, Character = 9 }, results[0].Diagnostics!.Single().Range.Start); AssertEx.Empty(results[1].Diagnostics); AssertEx.Empty(results[2].Diagnostics); - var buffer = testLspServer.TestWorkspace.Documents.First().GetTextBuffer(); - buffer.Insert(0, " "); + await InsertInClosedDocumentAsync(testLspServer, testLspServer.TestWorkspace.Documents.First().Id, " ", position: 0); var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.First(); var text = await document.GetTextAsync(); - // Hacky, but we need to close the document manually since editing the text-buffer will open it in the - // test-workspace. - testLspServer.TestWorkspace.OnDocumentClosed( - document.Id, TextLoader.From(TextAndVersion.Create(text, VersionStamp.Create()))); - var results2 = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); - Assert.Equal("CS1513", results2[0].Diagnostics.Single().Code); - Assert.Equal(new Position { Line = 0, Character = 10 }, results2[0].Diagnostics.Single().Range.Start); + Assert.Equal("CS1513", results2[0].Diagnostics!.Single().Code); + Assert.Equal(new Position { Line = 0, Character = 10 }, results2[0].Diagnostics!.Single().Range.Start); AssertEx.Empty(results2[1].Diagnostics); Assert.NotEqual(results[1].ResultId, results2[1].ResultId); @@ -1520,8 +1551,7 @@ public async Task TestWorkspaceDiagnosticsRemainAfterErrorIsNotFixed(bool useVSD [Theory, CombinatorialData] public async Task TestStreamingWorkspaceDiagnostics(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var markup1 = -@"class A {"; + var markup1 = @"class A {"; var markup2 = ""; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync( [markup1, markup2], mutatingLspWorkspace, BackgroundAnalysisScope.FullSolution, useVSDiagnostics); @@ -1529,8 +1559,8 @@ public async Task TestStreamingWorkspaceDiagnostics(bool useVSDiagnostics, bool var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); Assert.Equal(3, results.Length); - Assert.Equal("CS1513", results[0].Diagnostics.Single().Code); - Assert.Equal(new Position { Line = 0, Character = 9 }, results[0].Diagnostics.Single().Range.Start); + Assert.Equal("CS1513", results[0].Diagnostics!.Single().Code); + Assert.Equal(new Position { Line = 0, Character = 9 }, results[0].Diagnostics!.Single().Range.Start); results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics, useProgress: true); @@ -1541,8 +1571,10 @@ public async Task TestStreamingWorkspaceDiagnostics(bool useVSDiagnostics, bool public async Task TestWorkspaceDiagnosticsAreNotMapped(bool useVSDiagnostics, bool mutatingLspWorkspace) { var markup1 = -@"#line 1 ""test.txt"" -class A {"; + """ + #line 1 "test.txt" + class A { + """; var markup2 = ""; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync( [markup1, markup2], mutatingLspWorkspace, BackgroundAnalysisScope.FullSolution, useVSDiagnostics); @@ -1550,8 +1582,8 @@ class A {"; var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); Assert.Equal(3, results.Length); Assert.Equal(ProtocolConversions.CreateAbsoluteUri(@"C:\test1.cs"), results[0].TextDocument!.Uri); - Assert.Equal("CS1513", results[0].Diagnostics.Single().Code); - Assert.Equal(1, results[0].Diagnostics.Single().Range.Start.Line); + Assert.Equal("CS1513", results[0].Diagnostics!.Single().Code); + Assert.Equal(1, results[0].Diagnostics!.Single().Range.Start.Line); AssertEx.Empty(results[1].Diagnostics); AssertEx.Empty(results[2].Diagnostics); } @@ -1560,26 +1592,32 @@ class A {"; public async Task TestWorkspaceDiagnosticsWithChangeInReferencedProject(bool useVSDiagnostics, bool mutatingLspWorkspace) { var markup1 = -@"namespace M -{ - class A : B { } -}"; + """ + namespace M + { + class A : B { } + } + """; var markup2 = -@"namespace M -{ - public class {|caret:|} { } -}"; + """ + namespace M + { + public class {|caret:|} { } + } + """; var workspaceXml = -@$" - - {markup1} - CSProj2 - - - {markup2} - -"; + $""" + + + {markup1} + CSProj2 + + + {markup2} + + + """; await using var testLspServer = await CreateTestWorkspaceFromXmlAsync(workspaceXml, mutatingLspWorkspace, BackgroundAnalysisScope.FullSolution, useVSDiagnostics).ConfigureAwait(false); var csproj2Document = testLspServer.GetCurrentSolution().Projects.Where(p => p.Name == "CSProj2").Single().Documents.First(); @@ -1589,8 +1627,8 @@ public class {|caret:|} { } var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); AssertEx.NotNull(results); Assert.Equal(4, results.Length); - Assert.Equal("CS0246", results[0].Diagnostics.Single().Code); - Assert.Equal("CS1001", results[2].Diagnostics.Single().Code); + Assert.Equal("CS0246", results[0].Diagnostics!.Single().Code); + Assert.Equal("CS1001", results[2].Diagnostics!.Single().Code); // Insert B into B.cs via the workspace. var caretLocation = testLspServer.GetLocations("caret").First().Range; @@ -1619,41 +1657,49 @@ public class {|caret:|} { } public async Task TestWorkspaceDiagnosticsWithChangeInRecursiveReferencedProject(bool useVSDiagnostics, bool mutatingLspWorkspace) { var markup1 = -@"namespace M -{ - public class A : B - { - } -}"; + """ + namespace M + { + public class A : B + { + } + } + """; var markup2 = -@"namespace M -{ - public class B : C - { - } -}"; + """ + namespace M + { + public class B : C + { + } + } + """; var markup3 = -@"namespace M -{ - public class {|caret:|} - { - } -}"; + """ + namespace M + { + public class {|caret:|} + { + } + } + """; var workspaceXml = -@$" - - CSProj2 - {markup1} - - - CSProj3 - {markup2} - - - {markup3} - -"; + $""" + + + CSProj2 + {markup1} + + + CSProj3 + {markup2} + + + {markup3} + + + """; await using var testLspServer = await CreateTestWorkspaceFromXmlAsync(workspaceXml, mutatingLspWorkspace, BackgroundAnalysisScope.FullSolution, useVSDiagnostics).ConfigureAwait(false); var csproj3Document = testLspServer.GetCurrentSolution().Projects.Where(p => p.Name == "CSProj3").Single().Documents.First(); @@ -1663,13 +1709,13 @@ public class {|caret:|} AssertEx.NotNull(results); Assert.Equal(6, results.Length); // Type C does not exist. - Assert.Equal("CS0246", results[0].Diagnostics.Single().Code); + Assert.Equal("CS0246", results[0].Diagnostics!.Single().Code); AssertEx.Empty(results[1].Diagnostics); // Type C does not exist. - Assert.Equal("CS0246", results[2].Diagnostics.Single().Code); + Assert.Equal("CS0246", results[2].Diagnostics!.Single().Code); AssertEx.Empty(results[3].Diagnostics); // Syntax error missing identifier. - Assert.Equal("CS1001", results[4].Diagnostics.Single().Code); + Assert.Equal("CS1001", results[4].Diagnostics!.Single().Code); AssertEx.Empty(results[5].Diagnostics); // Insert C into C.cs via the workspace. @@ -1687,7 +1733,7 @@ public class {|caret:|} Assert.Equal(3, results.Length); // A.cs should report CS0012 indicating that C is not directly referenced. - Assert.Equal("CS0012", results[0].Diagnostics.Single().Code); + Assert.Equal("CS0012", results[0].Diagnostics!.Single().Code); Assert.NotEqual(previousResultIds[0].resultId, results[0].ResultId); // B.cs should no longer have a diagnostic since C exists. @@ -1703,25 +1749,31 @@ public class {|caret:|} public async Task TestWorkspaceDiagnosticsWithChangeInNotReferencedProject(bool useVSDiagnostics, bool mutatingLspWorkspace) { var markup1 = -@"namespace M -{ - class A : B { } -}"; + """ + namespace M + { + class A : B { } + } + """; var markup2 = -@"namespace M -{ - public class {|caret:|} { } -}"; + """ + namespace M + { + public class {|caret:|} { } + } + """; var workspaceXml = -@$" - - {markup1} - - - {markup2} - -"; + $""" + + + {markup1} + + + {markup2} + + + """; await using var testLspServer = await CreateTestWorkspaceFromXmlAsync(workspaceXml, mutatingLspWorkspace, BackgroundAnalysisScope.FullSolution, useVSDiagnostics).ConfigureAwait(false); var csproj2Document = testLspServer.GetCurrentSolution().Projects.Where(p => p.Name == "CSProj2").Single().Documents.First(); @@ -1731,9 +1783,9 @@ public class {|caret:|} { } var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); AssertEx.NotNull(results); Assert.Equal(4, results.Length); - Assert.Equal("CS0246", results[0].Diagnostics.Single().Code); + Assert.Equal("CS0246", results[0].Diagnostics!.Single().Code); AssertEx.Empty(results[1].Diagnostics); - Assert.Equal("CS1001", results[2].Diagnostics.Single().Code); + Assert.Equal("CS1001", results[2].Diagnostics!.Single().Code); AssertEx.Empty(results[3].Diagnostics); // Insert B into B.cs via the workspace. @@ -1753,40 +1805,43 @@ public class {|caret:|} { } AssertEx.Empty(results[0].Diagnostics); Assert.NotEqual(previousResultIds[2].resultId, results[0].ResultId); } -#if true -#else -#endif [Theory, CombinatorialData] public async Task TestWorkspaceDiagnosticsWithDependentProjectReloadedAndChanged(bool useVSDiagnostics, bool mutatingLspWorkspace) { var markup1 = -@"namespace M -{ - class A : B { } -}"; + """ + namespace M + { + class A : B { } + } + """; var markup2 = -@"namespace M -{ - public class B - { - public static void Do() - { - int unusedVariable; - } - } -}"; + """ + namespace M + { + public class B + { + public static void Do() + { + int unusedVariable; + } + } + } + """; var workspaceXml = -@$" - - {markup1} - CSProj2 - - - {markup2} - -"; + $""" + + + {markup1} + CSProj2 + + + {markup2} + + + """; await using var testLspServer = await CreateTestWorkspaceFromXmlAsync(workspaceXml, mutatingLspWorkspace, BackgroundAnalysisScope.FullSolution, useVSDiagnostics).ConfigureAwait(false); var csproj2Document = testLspServer.GetCurrentSolution().Projects.Where(p => p.Name == "CSProj2").Single().Documents.First(); @@ -1797,8 +1852,8 @@ public static void Do() AssertEx.NotNull(results); Assert.Equal(4, results.Length); AssertEx.Empty(results[0].Diagnostics); - Assert.Equal("CS0168", results[2].Diagnostics.Single().Code); - Assert.Equal(LSP.DiagnosticSeverity.Warning, results[2].Diagnostics.Single().Severity); + Assert.Equal("CS0168", results[2].Diagnostics!.Single().Code); + Assert.Equal(LSP.DiagnosticSeverity.Warning, results[2].Diagnostics!.Single().Severity); // Change and reload the project via the workspace. var projectInfo = testLspServer.TestWorkspace.Projects.Where(p => p.AssemblyName == "CSProj2").Single().ToProjectInfo(); @@ -1816,34 +1871,40 @@ public static void Do() // We should get a single report back for B.cs now that the diagnostic has been promoted to an error. // The diagnostics in A.cs did not change and so are not reported again. Assert.Equal(1, results.Length); - Assert.Equal("CS0168", results[0].Diagnostics.Single().Code); - Assert.Equal(LSP.DiagnosticSeverity.Error, results[0].Diagnostics.Single().Severity); + Assert.Equal("CS0168", results[0].Diagnostics!.Single().Code); + Assert.Equal(LSP.DiagnosticSeverity.Error, results[0].Diagnostics!.Single().Severity); } [Theory, CombinatorialData] public async Task TestWorkspaceDiagnosticsWithDependentProjectReloadedUnchanged(bool useVSDiagnostics, bool mutatingLspWorkspace) { var markup1 = -@"namespace M -{ - class A : B { } -}"; + """ + namespace M + { + class A : B { } + } + """; var markup2 = -@"namespace M -{ - public class {|caret:|} { } -}"; + """ + namespace M + { + public class {|caret:|} { } + } + """; var workspaceXml = -@$" - - {markup1} - CSProj2 - - - {markup2} - -"; + $""" + + + {markup1} + CSProj2 + + + {markup2} + + + """; await using var testLspServer = await CreateTestWorkspaceFromXmlAsync(workspaceXml, mutatingLspWorkspace, BackgroundAnalysisScope.FullSolution, useVSDiagnostics).ConfigureAwait(false); var csproj2Document = testLspServer.GetCurrentSolution().Projects.Where(p => p.Name == "CSProj2").Single().Documents.First(); @@ -1853,8 +1914,8 @@ public class {|caret:|} { } var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); AssertEx.NotNull(results); Assert.Equal(4, results.Length); - Assert.Equal("CS0246", results[0].Diagnostics.Single().Code); - Assert.Equal("CS1001", results[2].Diagnostics.Single().Code); + Assert.Equal("CS0246", results[0].Diagnostics!.Single().Code); + Assert.Equal("CS1001", results[2].Diagnostics!.Single().Code); // Reload the project via the workspace. var projectInfo = testLspServer.TestWorkspace.Projects.Where(p => p.AssemblyName == "CSProj2").Single().ToProjectInfo(); @@ -1877,25 +1938,29 @@ public class {|caret:|} { } public async Task TestWorkspaceDiagnosticsOrderOfReferencedProjectsReloadedDoesNotMatter(bool useVSDiagnostics, bool mutatingLspWorkspace) { var markup1 = -@"namespace M -{ - class A : B { } -}"; + """ + namespace M + { + class A : B { } + } + """; var workspaceXml = -@$" - - {markup1} - CSProj2 - CSProj3 - - - - - - - -"; + $""" + + + {markup1} + CSProj2 + CSProj3 + + + + + + + + + """; await using var testLspServer = await CreateTestWorkspaceFromXmlAsync(workspaceXml, mutatingLspWorkspace, BackgroundAnalysisScope.FullSolution, useVSDiagnostics).ConfigureAwait(false); var csproj2Document = testLspServer.GetCurrentSolution().Projects.Where(p => p.Name == "CSProj2").Single().Documents.First(); @@ -1905,7 +1970,7 @@ class A : B { } var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); AssertEx.NotNull(results); Assert.Equal(6, results.Length); - Assert.Equal("CS0246", results[0].Diagnostics.Single().Code); + Assert.Equal("CS0246", results[0].Diagnostics!.Single().Code); // Reload the project via the workspace. var projectInfo = testLspServer.TestWorkspace.Projects.Where(p => p.AssemblyName == "CSProj2").Single().ToProjectInfo(); @@ -1928,17 +1993,18 @@ class A : B { } [Theory, CombinatorialData] public async Task TestWorkspaceDiagnosticsDoesNotThrowIfProjectWithoutFilePathExists(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var csharpMarkup = -@"class A {"; + var csharpMarkup = @"class A {"; var workspaceXml = -@$" - - {csharpMarkup} - - - - -"; + $""" + + + {csharpMarkup} + + + + + + """; await using var testLspServer = await CreateTestWorkspaceFromXmlAsync(workspaceXml, mutatingLspWorkspace, BackgroundAnalysisScope.FullSolution, useVSDiagnostics).ConfigureAwait(false); @@ -1953,8 +2019,7 @@ public async Task TestWorkspaceDiagnosticsDoesNotThrowIfProjectWithoutFilePathEx [Theory, CombinatorialData] public async Task TestWorkspaceDiagnosticsWaitsForLspTextChanges(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var markup1 = -@"class A {"; + var markup1 = @"class A {"; var markup2 = ""; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync( [markup1, markup2], mutatingLspWorkspace, BackgroundAnalysisScope.FullSolution, useVSDiagnostics); @@ -1975,15 +2040,14 @@ public async Task TestWorkspaceDiagnosticsWaitsForLspTextChanges(bool useVSDiagn await testLspServer.OpenDocumentAsync(uri); // Assert the task completes after a change occurs - var results = await resultTask; + var results = await resultTask.WithTimeout(TestHelpers.HangMitigatingTimeout); Assert.NotEmpty(results); } [Theory, CombinatorialData] public async Task TestWorkspaceDiagnosticsWaitsForLspSolutionChanges(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var markup1 = -@"class A {"; + var markup1 = @"class A {"; var markup2 = ""; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync( [markup1, markup2], mutatingLspWorkspace, BackgroundAnalysisScope.FullSolution, useVSDiagnostics); @@ -2004,15 +2068,43 @@ public async Task TestWorkspaceDiagnosticsWaitsForLspSolutionChanges(bool useVSD testLspServer.TestWorkspace.OnProjectReloaded(projectInfo); // Assert the task completes after a change occurs - var results = await resultTask; + var results = await resultTask.WithTimeout(TestHelpers.HangMitigatingTimeout); + Assert.NotEmpty(results); + } + + [Theory, CombinatorialData] + [WorkItem("https://github.com/dotnet/roslyn/issues/77495")] + public async Task TestWorkspaceDiagnosticsWaitsForRefreshRequestedEvent(bool useVSDiagnostics, bool mutatingLspWorkspace) + { + var markup1 = @"class A {"; + var markup2 = ""; + await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync( + [markup1, markup2], mutatingLspWorkspace, BackgroundAnalysisScope.FullSolution, useVSDiagnostics); + + // The very first request should return immediately (as we're have no prior state to tell if the sln changed). + var resultTask = RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics, useProgress: true, triggerConnectionClose: false); + await resultTask; + + // The second request should wait for a solution change before returning. + resultTask = RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics, useProgress: true, triggerConnectionClose: false); + + // Assert that the connection isn't closed and task doesn't complete even after some delay. + await Task.Delay(TimeSpan.FromSeconds(5)); + Assert.False(resultTask.IsCompleted); + + // Make workspace change that will trigger connection close. + var refreshService = testLspServer.TestWorkspace.ExportProvider.GetExportedValue(); + refreshService.RequestWorkspaceRefresh(); + + // Assert the task completes after a change occurs + var results = await resultTask.WithTimeout(TestHelpers.HangMitigatingTimeout); Assert.NotEmpty(results); } [Theory(Skip = "https://github.com/dotnet/roslyn/issues/76503"), CombinatorialData] public async Task TestWorkspaceDiagnosticsWaitsForLspTextChangesWithMultipleSources(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var markup1 = -@"class A {"; + var markup1 = @"class A {"; var markup2 = ""; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync( [markup1, markup2], mutatingLspWorkspace, BackgroundAnalysisScope.FullSolution, useVSDiagnostics); @@ -2070,15 +2162,14 @@ public async Task TestWorkspaceDiagnosticsWaitsForLspTextChangesWithMultipleSour [Theory, CombinatorialData] public async Task TestWorkspaceDiagnosticsForClosedFilesSwitchFSAFromOnToOff(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var markup1 = -@"class A {"; + var markup1 = @"class A {"; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync( [markup1], mutatingLspWorkspace, BackgroundAnalysisScope.FullSolution, useVSDiagnostics); var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); Assert.Equal(2, results.Length); - Assert.Equal("CS1513", results[0].Diagnostics.Single().Code); + Assert.Equal("CS1513", results[0].Diagnostics!.Single().Code); AssertEx.Empty(results[1].Diagnostics); var options = testLspServer.TestWorkspace.ExportProvider.GetExportedValue(); @@ -2108,8 +2199,7 @@ public async Task TestWorkspaceDiagnosticsForClosedFilesSwitchFSAFromOnToOff(boo [Theory, CombinatorialData] public async Task TestWorkspaceDiagnosticsForClosedFilesSwitchFSAFromOffToOn(bool useVSDiagnostics, bool mutatingLspWorkspace) { - var markup1 = -@"class A {"; + var markup1 = @"class A {"; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync( [markup1], mutatingLspWorkspace, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics); @@ -2124,9 +2214,17 @@ public async Task TestWorkspaceDiagnosticsForClosedFilesSwitchFSAFromOffToOn(boo results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics, previousResults: CreateDiagnosticParamsFromPreviousReports(results)); Assert.Equal(2, results.Length); - Assert.Equal("CS1513", results[0].Diagnostics.Single().Code); + Assert.Equal("CS1513", results[0].Diagnostics!.Single().Code); AssertEx.Empty(results[1].Diagnostics); } + internal static async Task InsertInClosedDocumentAsync(TestLspServer testLspServer, DocumentId documentId, string textToInsert, int? position = null) + { + var text = await testLspServer.GetCurrentSolution().GetDocument(documentId)!.GetTextAsync(CancellationToken.None); + position ??= text.Length; + text = text.WithChanges(new TextChange(new TextSpan(position.Value, 0), textToInsert)); + await testLspServer.TestWorkspace.ChangeDocumentAsync(documentId, text); + } + #endregion } diff --git a/src/LanguageServer/ProtocolUnitTests/Diagnostics/WorkspaceProjectDiagnosticsTests.cs b/src/LanguageServer/ProtocolUnitTests/Diagnostics/WorkspaceProjectDiagnosticsTests.cs index ce607c6a9fc25..93cf0d63cc83f 100644 --- a/src/LanguageServer/ProtocolUnitTests/Diagnostics/WorkspaceProjectDiagnosticsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Diagnostics/WorkspaceProjectDiagnosticsTests.cs @@ -29,7 +29,7 @@ public async Task TestWorkspaceDiagnosticsReportsProjectDiagnostic(bool useVSDia Assert.Equal(2, results.Length); AssertEx.Empty(results[0].Diagnostics); - Assert.Equal(MockProjectDiagnosticAnalyzer.Id, results[1].Diagnostics.Single().Code); + Assert.Equal(MockProjectDiagnosticAnalyzer.Id, results[1].Diagnostics!.Single().Code); Assert.Equal(ProtocolConversions.CreateAbsoluteUri(testLspServer.GetCurrentSolution().Projects.First().FilePath!), results[1].Uri); // Asking again should give us back an unchanged diagnostic. @@ -46,7 +46,7 @@ public async Task TestWorkspaceDiagnosticsWithRemovedProject(bool useVSDiagnosti Assert.Equal(2, results.Length); AssertEx.Empty(results[0].Diagnostics); - Assert.Equal(MockProjectDiagnosticAnalyzer.Id, results[1].Diagnostics.Single().Code); + Assert.Equal(MockProjectDiagnosticAnalyzer.Id, results[1].Diagnostics!.Single().Code); Assert.Equal(ProtocolConversions.CreateAbsoluteUri(testLspServer.GetCurrentSolution().Projects.First().FilePath!), results[1].Uri); var initialSolution = testLspServer.GetCurrentSolution(); diff --git a/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.WithFindAllReferences.cs b/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.WithFindAllReferences.cs index ec2739b133c05..fcf5913cb5151 100644 --- a/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.WithFindAllReferences.cs +++ b/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.WithFindAllReferences.cs @@ -2,12 +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.Diagnostics; using System.Linq; -using System.Text.Json; using System.Threading.Tasks; using Microsoft.CodeAnalysis.LanguageServer.UnitTests.References; -using Roslyn.LanguageServer.Protocol; using Xunit; namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.DocumentChanges diff --git a/src/LanguageServer/ProtocolUnitTests/FoldingRanges/FoldingRangesTests.cs b/src/LanguageServer/ProtocolUnitTests/FoldingRanges/FoldingRangesTests.cs index f18a10d01e602..835d06b907f08 100644 --- a/src/LanguageServer/ProtocolUnitTests/FoldingRanges/FoldingRangesTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/FoldingRanges/FoldingRangesTests.cs @@ -7,7 +7,6 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Structure; using Roslyn.Test.Utilities; using Xunit; using Xunit.Abstractions; diff --git a/src/LanguageServer/ProtocolUnitTests/InlayHint/CSharpInlayHintTests.cs b/src/LanguageServer/ProtocolUnitTests/InlayHint/CSharpInlayHintTests.cs index 5968d8f97ca07..a5231be58caf8 100644 --- a/src/LanguageServer/ProtocolUnitTests/InlayHint/CSharpInlayHintTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/InlayHint/CSharpInlayHintTests.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.LanguageServer.Handler.InlayHint; using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; -using StreamJsonRpc; using Xunit; using Xunit.Abstractions; using LSP = Roslyn.LanguageServer.Protocol; @@ -130,8 +129,9 @@ void M() }; var actualInlayHints = await testLspServer.ExecuteRequestAsync(LSP.Methods.TextDocumentInlayHintName, inlayHintParams, CancellationToken.None); + AssertEx.NotNull(actualInlayHints); var firstInlayHint = actualInlayHints.First(); - var data = JsonSerializer.Deserialize(firstInlayHint.Data!.ToString(), ProtocolConversions.LspJsonSerializerOptions); + var data = JsonSerializer.Deserialize(firstInlayHint.Data!.ToString()!, ProtocolConversions.LspJsonSerializerOptions); AssertEx.NotNull(data); var firstResultId = data.ResultId; @@ -143,6 +143,7 @@ void M() await testLspServer.ExecuteRequestAsync(LSP.Methods.TextDocumentInlayHintName, inlayHintParams, CancellationToken.None); await testLspServer.ExecuteRequestAsync(LSP.Methods.TextDocumentInlayHintName, inlayHintParams, CancellationToken.None); var lastInlayHints = await testLspServer.ExecuteRequestAsync(LSP.Methods.TextDocumentInlayHintName, inlayHintParams, CancellationToken.None); + AssertEx.NotNull(lastInlayHints); Assert.True(lastInlayHints.Any()); // Assert that the first result id is no longer in the cache. diff --git a/src/LanguageServer/ProtocolUnitTests/InlineCompletions/InlineCompletionsTests.cs b/src/LanguageServer/ProtocolUnitTests/InlineCompletions/InlineCompletionsTests.cs index b709ade88f520..92e71ee794a7a 100644 --- a/src/LanguageServer/ProtocolUnitTests/InlineCompletions/InlineCompletionsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/InlineCompletions/InlineCompletionsTests.cs @@ -8,7 +8,6 @@ using Microsoft.CodeAnalysis.LanguageServer.Handler.InlineCompletions; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; -using Roslyn.Utilities; using Xunit; using Xunit.Abstractions; using LSP = Roslyn.LanguageServer.Protocol; diff --git a/src/LanguageServer/ProtocolUnitTests/InlineCompletions/TestSnippetInfoService.cs b/src/LanguageServer/ProtocolUnitTests/InlineCompletions/TestSnippetInfoService.cs index ae884917e1988..f1185e57cd466 100644 --- a/src/LanguageServer/ProtocolUnitTests/InlineCompletions/TestSnippetInfoService.cs +++ b/src/LanguageServer/ProtocolUnitTests/InlineCompletions/TestSnippetInfoService.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServer.Handler.InlineCompletions; using Microsoft.CodeAnalysis.Snippets; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests; @@ -45,7 +44,7 @@ public bool ShouldFormatSnippet(SnippetInfo snippetInfo) throw new NotImplementedException(); } - public bool SnippetShortcutExists_NonBlocking(string shortcut) + public bool SnippetShortcutExists_NonBlocking(string? shortcut) { throw new NotImplementedException(); } diff --git a/src/LanguageServer/ProtocolUnitTests/MapCode/MapCodeTests.cs b/src/LanguageServer/ProtocolUnitTests/MapCode/MapCodeTests.cs index 0aaf597dec428..2947fd4a7dcf1 100644 --- a/src/LanguageServer/ProtocolUnitTests/MapCode/MapCodeTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/MapCode/MapCodeTests.cs @@ -112,7 +112,7 @@ static void Main(string[] args) var results = await testLspServer.ExecuteRequestAsync(VSInternalMethods.WorkspaceMapCodeName, mapCodeParams, CancellationToken.None); AssertEx.NotNull(results); - TextEdit[] edits; + TextEdit[]? edits; if (supportDocumentChanges) { Assert.Null(results.Changes); @@ -131,6 +131,8 @@ static void Main(string[] args) Assert.True(results.Changes!.TryGetValue(ProtocolConversions.GetDocumentFilePathFromUri(documentUri), out edits)); } + AssertEx.NotNull(edits); + var documentText = await document.GetTextAsync(); var actualText = ApplyTextEdits(edits, documentText); Assert.Equal(expected, actualText); diff --git a/src/LanguageServer/ProtocolUnitTests/Metadata/LspMetadataAsSourceWorkspaceTests.cs b/src/LanguageServer/ProtocolUnitTests/Metadata/LspMetadataAsSourceWorkspaceTests.cs index 36e37923ab780..4092dcdee3c8c 100644 --- a/src/LanguageServer/ProtocolUnitTests/Metadata/LspMetadataAsSourceWorkspaceTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Metadata/LspMetadataAsSourceWorkspaceTests.cs @@ -8,7 +8,6 @@ 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; @@ -43,6 +42,7 @@ void M() var location = testLspServer.GetLocations("definition").Single(); var definition = await testLspServer.ExecuteRequestAsync(LSP.Methods.TextDocumentDefinitionName, CreateTextDocumentPositionParams(location), CancellationToken.None); + AssertEx.NotNull(definition); // Open the metadata file and verify it gets added to the metadata workspace. await testLspServer.OpenDocumentAsync(definition.Single().Uri, text: string.Empty).ConfigureAwait(false); @@ -89,6 +89,7 @@ public static void WriteLine(string value) {} var location = testLspServer.GetLocations("definition").Single(); var definition = await testLspServer.ExecuteRequestAsync(LSP.Methods.TextDocumentDefinitionName, CreateTextDocumentPositionParams(location), CancellationToken.None); + AssertEx.NotNull(definition); // 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. diff --git a/src/LanguageServer/ProtocolUnitTests/Microsoft.CodeAnalysis.LanguageServer.Protocol.UnitTests.csproj b/src/LanguageServer/ProtocolUnitTests/Microsoft.CodeAnalysis.LanguageServer.Protocol.UnitTests.csproj index b244b45d8789b..77dcec96afa1b 100644 --- a/src/LanguageServer/ProtocolUnitTests/Microsoft.CodeAnalysis.LanguageServer.Protocol.UnitTests.csproj +++ b/src/LanguageServer/ProtocolUnitTests/Microsoft.CodeAnalysis.LanguageServer.Protocol.UnitTests.csproj @@ -3,7 +3,7 @@ - net472 + $(NetVSCode);net472 Library Microsoft.CodeAnalysis.LanguageServer.UnitTests UnitTest @@ -13,10 +13,6 @@ Always - - - - @@ -27,13 +23,6 @@ - - - - - - - @@ -47,11 +36,9 @@ + - - - diff --git a/src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs b/src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs index be2a76a84c976..98a0fc076aa74 100644 --- a/src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs @@ -7,7 +7,6 @@ using System.Threading; using System.Threading.Tasks; using Roslyn.Test.Utilities; -using Roslyn.Utilities; using Xunit; using Xunit.Abstractions; using LSP = Roslyn.LanguageServer.Protocol; @@ -286,6 +285,7 @@ void M() Assert.Equal(LanguageNames.CSharp, miscDoc.Project.Language); // Verify GTD request succeeded. + AssertEx.NotNull(result); Assert.Equal(0, result.Single().Range.Start.Line); Assert.Equal(6, result.Single().Range.Start.Character); Assert.Equal(0, result.Single().Range.End.Line); diff --git a/src/LanguageServer/ProtocolUnitTests/OnAutoInsert/OnAutoInsertTests.cs b/src/LanguageServer/ProtocolUnitTests/OnAutoInsert/OnAutoInsertTests.cs index c0d60cc1c5588..5b96b3485b4e8 100644 --- a/src/LanguageServer/ProtocolUnitTests/OnAutoInsert/OnAutoInsertTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/OnAutoInsert/OnAutoInsertTests.cs @@ -8,7 +8,6 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.LanguageServer.Protocol; using Roslyn.Test.Utilities; -using Roslyn.Utilities; using Xunit; using Xunit.Abstractions; using LSP = Roslyn.LanguageServer.Protocol; diff --git a/src/LanguageServer/ProtocolUnitTests/Options/LspOptionsTests.cs b/src/LanguageServer/ProtocolUnitTests/Options/LspOptionsTests.cs index f85284982a6ef..22f7e85fe4175 100644 --- a/src/LanguageServer/ProtocolUnitTests/Options/LspOptionsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Options/LspOptionsTests.cs @@ -6,8 +6,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeGeneration; -using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.Editor.Test; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Test.Utilities; diff --git a/src/LanguageServer/ProtocolUnitTests/ProjectContext/GetTextDocumentWithContextHandlerTests.cs b/src/LanguageServer/ProtocolUnitTests/ProjectContext/GetTextDocumentWithContextHandlerTests.cs index 44befe94053bb..a255360e48280 100644 --- a/src/LanguageServer/ProtocolUnitTests/ProjectContext/GetTextDocumentWithContextHandlerTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/ProjectContext/GetTextDocumentWithContextHandlerTests.cs @@ -81,11 +81,9 @@ public async Task SwitchingContextsChangesDefaultContext(bool mutatingLspWorkspa await using var testLspServer = await CreateXmlTestLspServerAsync(workspaceXml, mutatingLspWorkspace); - // Ensure the documents are open so we can change contexts - foreach (var document in testLspServer.TestWorkspace.Documents) - { - _ = document.GetOpenTextContainer(); - } + // Ensure all the linked documents are open so we can change contexts + var document = testLspServer.TestWorkspace.Documents.First(); + await testLspServer.OpenDocumentInWorkspaceAsync(document.Id, openAllLinkedDocuments: true); var documentUri = testLspServer.GetLocations("caret").Single().Uri; diff --git a/src/LanguageServer/ProtocolUnitTests/References/FindAllReferencesHandlerFeaturesTests.cs b/src/LanguageServer/ProtocolUnitTests/References/FindAllReferencesHandlerFeaturesTests.cs index 8fda99724efe7..d57d43540f495 100644 --- a/src/LanguageServer/ProtocolUnitTests/References/FindAllReferencesHandlerFeaturesTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/References/FindAllReferencesHandlerFeaturesTests.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.Test; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; @@ -70,8 +69,8 @@ class SomeClass{{i}} } """; - 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])); + var testDocument = new TestHostDocument(text: source, displayName: @$"C:\SomeFile{i}.cs", exportProvider: testLspServer.TestWorkspace.ExportProvider, filePath: @$"C:\SomeFile{i}.cs"); + testLspServer.TestWorkspace.AddTestProject(new TestHostProject(testLspServer.TestWorkspace, documents: [testDocument])); } await WaitForWorkspaceOperationsAsync(testLspServer.TestWorkspace); diff --git a/src/LanguageServer/ProtocolUnitTests/References/FindImplementationsTests.cs b/src/LanguageServer/ProtocolUnitTests/References/FindImplementationsTests.cs index a4ae9d8449b3f..dfa0d5378f2e5 100644 --- a/src/LanguageServer/ProtocolUnitTests/References/FindImplementationsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/References/FindImplementationsTests.cs @@ -4,7 +4,6 @@ #nullable disable -using System.Collections.Immutable; using System.Linq; using System.Threading; using System.Threading.Tasks; diff --git a/src/LanguageServer/ProtocolUnitTests/RelatedDocuments/RelatedDocumentsTests.cs b/src/LanguageServer/ProtocolUnitTests/RelatedDocuments/RelatedDocumentsTests.cs index 979a37c00517c..d4965c90a9321 100644 --- a/src/LanguageServer/ProtocolUnitTests/RelatedDocuments/RelatedDocumentsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/RelatedDocuments/RelatedDocumentsTests.cs @@ -95,7 +95,7 @@ class Y useProgress: useProgress); Assert.Equal(1, results.Length); - Assert.Equal(project.Documents.Last().FilePath, results[0].FilePaths.Single()); + Assert.Equal(project.Documents.Last().FilePath, results[0].FilePaths!.Single()); } [Theory, CombinatorialData] @@ -129,8 +129,8 @@ class Z 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)); + 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] diff --git a/src/LanguageServer/ProtocolUnitTests/Rename/RenameTests.cs b/src/LanguageServer/ProtocolUnitTests/Rename/RenameTests.cs index 68c71fadb2528..870cbd83c119b 100644 --- a/src/LanguageServer/ProtocolUnitTests/Rename/RenameTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Rename/RenameTests.cs @@ -22,7 +22,7 @@ public RenameTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } - [WpfTheory, CombinatorialData] + [Theory, CombinatorialData] public async Task TestRenameAsync(bool mutatingLspWorkspace) { var markup = @@ -45,7 +45,7 @@ void M2() AssertJsonEquals(expectedEdits, ((TextDocumentEdit[])results.DocumentChanges).First().Edits); } - [WpfTheory, CombinatorialData] + [Theory, CombinatorialData] public async Task TestRename_InvalidIdentifierAsync(bool mutatingLspWorkspace) { var markup = @@ -67,7 +67,7 @@ void M2() Assert.Null(results); } - [WpfTheory, CombinatorialData] + [Theory, CombinatorialData] public async Task TestRename_WithLinkedFilesAsync(bool mutatingLspWorkspace) { var markup = @@ -101,7 +101,7 @@ void M2() AssertJsonEquals(expectedEdits, ((TextDocumentEdit[])results.DocumentChanges).First().Edits); } - [WpfTheory, CombinatorialData] + [Theory, CombinatorialData] public async Task TestRename_WithLinkedFilesAndPreprocessorAsync(bool mutatingLspWorkspace) { var markup = @@ -147,7 +147,7 @@ void M4() AssertJsonEquals(expectedEdits, ((TextDocumentEdit[])results.DocumentChanges).First().Edits); } - [WpfTheory, CombinatorialData] + [Theory, CombinatorialData] public async Task TestRename_WithMappedFileAsync(bool mutatingLspWorkspace) { var markup = diff --git a/src/LanguageServer/ProtocolUnitTests/SemanticTokens/AbstractSemanticTokensTests.cs b/src/LanguageServer/ProtocolUnitTests/SemanticTokens/AbstractSemanticTokensTests.cs index 007d6d4fbcfac..ef45a583c019b 100644 --- a/src/LanguageServer/ProtocolUnitTests/SemanticTokens/AbstractSemanticTokensTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/SemanticTokens/AbstractSemanticTokensTests.cs @@ -27,6 +27,14 @@ protected AbstractSemanticTokensTests(ITestOutputHelper testOutputHelper) : base private protected static IReadOnlyDictionary GetTokenTypeToIndex(TestLspServer server) => SemanticTokensSchema.GetSchema(server.ClientCapabilities.HasVisualStudioLspCapability()).TokenTypeToIndex; + private protected static async Task RunGetSemanticTokensFullAsync(TestLspServer testLspServer, LSP.Location caret) + { + var result = await testLspServer.ExecuteRequestAsync(LSP.Methods.TextDocumentSemanticTokensFullName, + CreateSemanticTokensFullParams(caret), CancellationToken.None); + Contract.ThrowIfNull(result); + return result; + } + private protected static async Task RunGetSemanticTokensRangeAsync(TestLspServer testLspServer, LSP.Location caret, LSP.Range range) { var result = await testLspServer.ExecuteRequestAsync(LSP.Methods.TextDocumentSemanticTokensRangeName, @@ -43,6 +51,12 @@ private protected static IReadOnlyDictionary GetTokenTypeToIndex(Te return result; } + private static LSP.SemanticTokensFullParams CreateSemanticTokensFullParams(LSP.Location caret) + => new LSP.SemanticTokensFullParams + { + TextDocument = new LSP.TextDocumentIdentifier { Uri = caret.Uri } + }; + private static LSP.SemanticTokensRangeParams CreateSemanticTokensRangeParams(LSP.Location caret, LSP.Range range) => new LSP.SemanticTokensRangeParams { diff --git a/src/LanguageServer/ProtocolUnitTests/SemanticTokens/SemanticTokensFullTests.cs b/src/LanguageServer/ProtocolUnitTests/SemanticTokens/SemanticTokensFullTests.cs new file mode 100644 index 0000000000000..8d9496ebf7700 --- /dev/null +++ b/src/LanguageServer/ProtocolUnitTests/SemanticTokens/SemanticTokensFullTests.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.Linq; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Classification; +using Microsoft.CodeAnalysis.LanguageServer.Handler.SemanticTokens; +using Roslyn.LanguageServer.Protocol; +using Roslyn.Test.Utilities; +using Xunit; +using Xunit.Abstractions; +using LSP = Roslyn.LanguageServer.Protocol; + +#pragma warning disable format // We want to force explicit column spacing within the collection literals in this file, so we disable formatting. + +namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.SemanticTokens; + +public sealed class SemanticTokensFullTests(ITestOutputHelper testOutputHelper) : AbstractSemanticTokensTests(testOutputHelper) +{ + [Theory, CombinatorialData] + public async Task TestGetSemanticTokensFull_FullDocAsync(bool mutatingLspWorkspace, bool isVS) + { + var markup = + """ + {|caret:|}// Comment + static class C { } + + """; + await using var testLspServer = await CreateTestLspServerAsync( + markup, mutatingLspWorkspace, GetCapabilities(isVS)); + + var results = await RunGetSemanticTokensFullAsync(testLspServer, testLspServer.GetLocations("caret").First()); + + var expectedResults = new LSP.SemanticTokens(); + var tokenTypeToIndex = GetTokenTypeToIndex(testLspServer); + if (isVS) + { + expectedResults.Data = + [ + // Line | Char | Len | Token type | Modifier + 0, 0, 10, tokenTypeToIndex[SemanticTokenTypes.Comment], 0, // '// Comment' + 1, 0, 6, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'static' + 0, 7, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' + 0, 6, 1, tokenTypeToIndex[ClassificationTypeNames.ClassName], (int)TokenModifiers.Static, // 'C' + 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' + 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '}' + ]; + } + else + { + expectedResults.Data = + [ + // Line | Char | Len | Token type | Modifier + 0, 0, 10, tokenTypeToIndex[SemanticTokenTypes.Comment], 0, // '// Comment' + 1, 0, 6, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'static' + 0, 7, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' + 0, 6, 1, tokenTypeToIndex[SemanticTokenTypes.Class], (int)TokenModifiers.Static, // 'C' + 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' + 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '}' + ]; + } + + await VerifyBasicInvariantsAndNoMultiLineTokens(testLspServer, results.Data).ConfigureAwait(false); + AssertEx.Equal(ConvertToReadableFormat(testLspServer.ClientCapabilities, expectedResults.Data), ConvertToReadableFormat(testLspServer.ClientCapabilities, results.Data)); + } +} diff --git a/src/LanguageServer/ProtocolUnitTests/SemanticTokens/SemanticTokensRangeTests.cs b/src/LanguageServer/ProtocolUnitTests/SemanticTokens/SemanticTokensRangeTests.cs index 34ff01d65aa4e..029e55d893df5 100644 --- a/src/LanguageServer/ProtocolUnitTests/SemanticTokens/SemanticTokensRangeTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/SemanticTokens/SemanticTokensRangeTests.cs @@ -17,581 +17,592 @@ #pragma warning disable format // We want to force explicit column spacing within the collection literals in this file, so we disable formatting. -namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.SemanticTokens +namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.SemanticTokens; + +public sealed class SemanticTokensRangeTests(ITestOutputHelper testOutputHelper) + : AbstractSemanticTokensTests(testOutputHelper) { - public class SemanticTokensRangeTests : AbstractSemanticTokensTests + [Theory, CombinatorialData] + public async Task TestGetSemanticTokensRange_FullDocAsync(bool mutatingLspWorkspace, bool isVS) { - public SemanticTokensRangeTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) + var markup = + """ + {|caret:|}// Comment + static class C { } + + """; + await using var testLspServer = await CreateTestLspServerAsync( + markup, mutatingLspWorkspace, GetCapabilities(isVS)); + + var range = new LSP.Range { Start = new Position(0, 0), End = new Position(2, 0) }; + var results = await RunGetSemanticTokensRangeAsync(testLspServer, testLspServer.GetLocations("caret").First(), range); + + var expectedResults = new LSP.SemanticTokens(); + var tokenTypeToIndex = GetTokenTypeToIndex(testLspServer); + if (isVS) { + expectedResults.Data = + [ + // Line | Char | Len | Token type | Modifier + 0, 0, 10, tokenTypeToIndex[SemanticTokenTypes.Comment], 0, // '// Comment' + 1, 0, 6, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'static' + 0, 7, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' + 0, 6, 1, tokenTypeToIndex[ClassificationTypeNames.ClassName], (int)TokenModifiers.Static, // 'C' + 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' + 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '}' + ]; } - - [Theory, CombinatorialData] - public async Task TestGetSemanticTokensRange_FullDocAsync(bool mutatingLspWorkspace, bool isVS) + else { - var markup = -@"{|caret:|}// Comment -static class C { } -"; - await using var testLspServer = await CreateTestLspServerAsync( - markup, mutatingLspWorkspace, GetCapabilities(isVS)); - - var range = new LSP.Range { Start = new Position(0, 0), End = new Position(2, 0) }; - var results = await RunGetSemanticTokensRangeAsync(testLspServer, testLspServer.GetLocations("caret").First(), range); - - var expectedResults = new LSP.SemanticTokens(); - var tokenTypeToIndex = GetTokenTypeToIndex(testLspServer); - if (isVS) - { - expectedResults.Data = - [ - // Line | Char | Len | Token type | Modifier - 0, 0, 10, tokenTypeToIndex[SemanticTokenTypes.Comment], 0, // '// Comment' - 1, 0, 6, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'static' - 0, 7, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' - 0, 6, 1, tokenTypeToIndex[ClassificationTypeNames.ClassName], (int)TokenModifiers.Static, // 'C' - 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' - 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '}' - ]; - } - else + expectedResults.Data = + [ + // Line | Char | Len | Token type | Modifier + 0, 0, 10, tokenTypeToIndex[SemanticTokenTypes.Comment], 0, // '// Comment' + 1, 0, 6, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'static' + 0, 7, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' + 0, 6, 1, tokenTypeToIndex[SemanticTokenTypes.Class], (int)TokenModifiers.Static, // 'C' + 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' + 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '}' + ]; + } + + await VerifyBasicInvariantsAndNoMultiLineTokens(testLspServer, results.Data).ConfigureAwait(false); + AssertEx.Equal(ConvertToReadableFormat(testLspServer.ClientCapabilities, expectedResults.Data), ConvertToReadableFormat(testLspServer.ClientCapabilities, results.Data)); + } + + [Theory, CombinatorialData] + public async Task TestGetSemanticTokensRanges_ComputesTokensWithMultipleRanges(bool mutatingLspWorkspace, bool isVS) + { + // Razor docs should be returning semantic + syntactic results. + var markup = + """ + {|caret:|}// + #pragma warning disable 1591 + namespace Razor { - expectedResults.Data = - [ - // Line | Char | Len | Token type | Modifier - 0, 0, 10, tokenTypeToIndex[SemanticTokenTypes.Comment], 0, // '// Comment' - 1, 0, 6, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'static' - 0, 7, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' - 0, 6, 1, tokenTypeToIndex[SemanticTokenTypes.Class], (int)TokenModifiers.Static, // 'C' - 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' - 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '}' - ]; + #line hidden + public class Template + { + #pragma warning disable 219 + private void __RazorDirectiveTokenHelpers__() { + ((global::System.Action)(() => { + #nullable restore + #line 1 "test.cshtml" + var z = 1; + + #line default + #line hidden + #nullable disable + } + ))(); + } + #pragma warning restore 219 + #pragma warning disable 0414 + private static object __o = null; + #pragma warning restore 0414 + #pragma warning disable 1998 + public async override global::System.Threading.Tasks.Task ExecuteAsync() + { + #nullable restore + #line 2 "test.cshtml" + var x = + + #line default + #line hidden + #nullable disable + } + #pragma warning restore 1998 + } } + #pragma warning restore 1591 - await VerifyBasicInvariantsAndNoMultiLineTokens(testLspServer, results.Data).ConfigureAwait(false); - AssertEx.Equal(ConvertToReadableFormat(testLspServer.ClientCapabilities, expectedResults.Data), ConvertToReadableFormat(testLspServer.ClientCapabilities, results.Data)); - } + """; + await using var testLspServer = await CreateTestLspServerAsync( + markup, mutatingLspWorkspace, GetCapabilities(isVS)); + + var document = testLspServer.GetCurrentSolution().Projects.First().Documents.First(); + ImmutableArray spans = [ + new LinePositionSpan(new LinePosition(12, 0), new LinePosition(13, 0)), + new LinePositionSpan(new LinePosition(29, 0), new LinePosition(30, 0)), + ]; + + var options = ClassificationOptions.Default; + var results = await SemanticTokensHelpers.ComputeSemanticTokensDataAsync( + document, spans, isVS, options, CancellationToken.None); - [Theory, CombinatorialData] - public async Task TestGetSemanticTokensRanges_ComputesTokensWithMultipleRanges(bool mutatingLspWorkspace, bool isVS) + var expectedResults = new LSP.SemanticTokens(); + var tokenTypeToIndex = GetTokenTypeToIndex(testLspServer); + if (isVS) { - // Razor docs should be returning semantic + syntactic results. - var markup = -@"{|caret:|}// -#pragma warning disable 1591 -namespace Razor -{ - #line hidden - public class Template - { - #pragma warning disable 219 - private void __RazorDirectiveTokenHelpers__() { - ((global::System.Action)(() => { -#nullable restore -#line 1 ""test.cshtml"" -var z = 1; - -#line default -#line hidden -#nullable disable - } - ))(); + expectedResults.Data = + [ + // Line | Char | Len | Token type | Modifier + 12, 0, 3, tokenTypeToIndex[ClassificationTypeNames.Keyword], 0, // 'var' + 0, 4, 1, tokenTypeToIndex[ClassificationTypeNames.LocalName], 0, // 'z' + 0, 2, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '=' + 0, 2, 1, tokenTypeToIndex[SemanticTokenTypes.Number], 0, // '1' + 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // ';' + 17, 3, 3, tokenTypeToIndex[ClassificationTypeNames.Keyword], 0, // 'var' + 0, 4, 1, tokenTypeToIndex[ClassificationTypeNames.LocalName], 0, // 'x' + 0, 2, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '=' + ]; } - #pragma warning restore 219 - #pragma warning disable 0414 - private static object __o = null; - #pragma warning restore 0414 - #pragma warning disable 1998 - public async override global::System.Threading.Tasks.Task ExecuteAsync() + else { -#nullable restore -#line 2 ""test.cshtml"" - var x = + expectedResults.Data = + [ + // Line | Char | Len | Token type | Modifier + 12, 0, 3, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'var' + 0, 4, 1, tokenTypeToIndex[SemanticTokenTypes.Variable], 0, // 'z' + 0, 2, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '=' + 0, 2, 1, tokenTypeToIndex[SemanticTokenTypes.Number], 0, // '1' + 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // ';' + 17, 3, 3, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'var' + 0, 4, 1, tokenTypeToIndex[SemanticTokenTypes.Variable], 0, // 'x' + 0, 2, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '=' + ]; + } -#line default -#line hidden -#nullable disable + await VerifyBasicInvariantsAndNoMultiLineTokens(testLspServer, results).ConfigureAwait(false); + AssertEx.Equal(ConvertToReadableFormat(testLspServer.ClientCapabilities, expectedResults.Data), ConvertToReadableFormat(testLspServer.ClientCapabilities, results)); + } + + [Theory, CombinatorialData] + public async Task TestGetSemanticTokensRange_PartialDocAsync(bool mutatingLspWorkspace, bool isVS) + { + // Razor docs should be returning semantic + syntactic results. + var markup = + """ + {|caret:|}// Comment + static class C { } + + """; + await using var testLspServer = await CreateTestLspServerAsync( + markup, mutatingLspWorkspace, GetCapabilities(isVS)); + + var document = testLspServer.GetCurrentSolution().Projects.First().Documents.First(); + ImmutableArray spans = [new LinePositionSpan(new LinePosition(1, 0), new LinePosition(2, 0))]; + var options = ClassificationOptions.Default; + var results = await SemanticTokensHelpers.ComputeSemanticTokensDataAsync( + document, spans, isVS, options, CancellationToken.None); + + var expectedResults = new LSP.SemanticTokens(); + var tokenTypeToIndex = GetTokenTypeToIndex(testLspServer); + if (isVS) + { + expectedResults.Data = + [ + // Line | Char | Len | Token type | Modifier + 1, 0, 6, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'static' + 0, 7, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' + 0, 6, 1, tokenTypeToIndex[ClassificationTypeNames.ClassName], (int)TokenModifiers.Static, // 'C' + 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' + 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '}' + ]; } - #pragma warning restore 1998 + else + { + expectedResults.Data = + [ + // Line | Char | Len | Token type | Modifier + 1, 0, 6, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'static' + 0, 7, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' + 0, 6, 1, tokenTypeToIndex[SemanticTokenTypes.Class], (int)TokenModifiers.Static, // 'C' + 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' + 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '}' + ]; + } + + await VerifyBasicInvariantsAndNoMultiLineTokens(testLspServer, results).ConfigureAwait(false); + AssertEx.Equal(ConvertToReadableFormat(testLspServer.ClientCapabilities, expectedResults.Data), ConvertToReadableFormat(testLspServer.ClientCapabilities, results)); } -} -#pragma warning restore 1591 -"; - await using var testLspServer = await CreateTestLspServerAsync( - markup, mutatingLspWorkspace, GetCapabilities(isVS)); - - var document = testLspServer.GetCurrentSolution().Projects.First().Documents.First(); - ImmutableArray spans = [ - new LinePositionSpan(new LinePosition(12, 0), new LinePosition(13, 0)), - new LinePositionSpan(new LinePosition(29, 0), new LinePosition(30, 0)), + + [Theory, CombinatorialData] + public async Task TestGetSemanticTokensRange_MultiLineComment_IncludeSyntacticClassificationsAsync(bool mutatingLspWorkspace, bool isVS) + { + // Testing as a Razor doc so we get both syntactic + semantic results; otherwise the results would be empty. + var markup = + """ + {|caret:|}class C { /* one + + two + three */ } + + """; + await using var testLspServer = await CreateTestLspServerAsync( + markup, mutatingLspWorkspace, GetCapabilities(isVS)); + + var document = testLspServer.GetCurrentSolution().Projects.First().Documents.First(); + ImmutableArray spans = [new LinePositionSpan(new LinePosition(0, 0), new LinePosition(4, 0))]; + var options = ClassificationOptions.Default; + var results = await SemanticTokensHelpers.ComputeSemanticTokensDataAsync( + document, spans, isVS, options, CancellationToken.None); + + var expectedResults = new LSP.SemanticTokens(); + var tokenTypeToIndex = GetTokenTypeToIndex(testLspServer); + if (isVS) + { + expectedResults.Data = + [ + // Line | Char | Len | Token type | Modifier + 0, 0, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' + 0, 6, 1, tokenTypeToIndex[ClassificationTypeNames.ClassName], 0, // 'C' + 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' + 0, 2, 6, tokenTypeToIndex[SemanticTokenTypes.Comment], 0, // '/* one' + 2, 0, 3, tokenTypeToIndex[SemanticTokenTypes.Comment], 0, // 'two' + 1, 0, 8, tokenTypeToIndex[SemanticTokenTypes.Comment], 0, // 'three */' + 0, 9, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '}' + ]; + } + else + { + expectedResults.Data = + [ + // Line | Char | Len | Token type | Modifier + 0, 0, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' + 0, 6, 1, tokenTypeToIndex[SemanticTokenTypes.Class], 0, // 'C' + 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' + 0, 2, 6, tokenTypeToIndex[SemanticTokenTypes.Comment], 0, // '/* one' + 2, 0, 3, tokenTypeToIndex[SemanticTokenTypes.Comment], 0, // 'two' + 1, 0, 8, tokenTypeToIndex[SemanticTokenTypes.Comment], 0, // 'three */' + 0, 9, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '}' ]; + } - var options = ClassificationOptions.Default; - var results = await SemanticTokensHelpers.ComputeSemanticTokensDataAsync( - document, spans, isVS, options, CancellationToken.None); + await VerifyBasicInvariantsAndNoMultiLineTokens(testLspServer, results).ConfigureAwait(false); + AssertEx.Equal(ConvertToReadableFormat(testLspServer.ClientCapabilities, expectedResults.Data), ConvertToReadableFormat(testLspServer.ClientCapabilities, results)); + } - var expectedResults = new LSP.SemanticTokens(); - var tokenTypeToIndex = GetTokenTypeToIndex(testLspServer); - if (isVS) - { - expectedResults.Data = - [ - // Line | Char | Len | Token type | Modifier - 12, 0, 3, tokenTypeToIndex[ClassificationTypeNames.Keyword], 0, // 'var' - 0, 4, 1, tokenTypeToIndex[ClassificationTypeNames.LocalName], 0, // 'z' - 0, 2, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '=' - 0, 2, 1, tokenTypeToIndex[SemanticTokenTypes.Number], 0, // '1' - 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // ';' - 17, 3, 3, tokenTypeToIndex[ClassificationTypeNames.Keyword], 0, // 'var' - 0, 4, 1, tokenTypeToIndex[ClassificationTypeNames.LocalName], 0, // 'x' - 0, 2, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '=' - ]; - } - else + [Theory, CombinatorialData] + public async Task TestGetSemanticTokensRange_StringLiteral_IncludeSyntacticClassificationsAsync(bool mutatingLspWorkspace, bool isVS) + { + var markup = + """ + {|caret:|}class C { - expectedResults.Data = - [ - // Line | Char | Len | Token type | Modifier - 12, 0, 3, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'var' - 0, 4, 1, tokenTypeToIndex[SemanticTokenTypes.Variable], 0, // 'z' - 0, 2, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '=' - 0, 2, 1, tokenTypeToIndex[SemanticTokenTypes.Number], 0, // '1' - 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // ';' - 17, 3, 3, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'var' - 0, 4, 1, tokenTypeToIndex[SemanticTokenTypes.Variable], 0, // 'x' - 0, 2, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '=' - ]; + void M() + { + var x = @"one + two "" + three"; + } } - await VerifyBasicInvariantsAndNoMultiLineTokens(testLspServer, results).ConfigureAwait(false); - AssertEx.Equal(ConvertToReadableFormat(testLspServer.ClientCapabilities, expectedResults.Data), ConvertToReadableFormat(testLspServer.ClientCapabilities, results)); - } + """; - [Theory, CombinatorialData] - public async Task TestGetSemanticTokensRange_PartialDocAsync(bool mutatingLspWorkspace, bool isVS) - { - // Razor docs should be returning semantic + syntactic results. - var markup = -@"{|caret:|}// Comment -static class C { } -"; - await using var testLspServer = await CreateTestLspServerAsync( - markup, mutatingLspWorkspace, GetCapabilities(isVS)); - - var document = testLspServer.GetCurrentSolution().Projects.First().Documents.First(); - ImmutableArray spans = [new LinePositionSpan(new LinePosition(1, 0), new LinePosition(2, 0))]; - var options = ClassificationOptions.Default; - var results = await SemanticTokensHelpers.ComputeSemanticTokensDataAsync( - document, spans, isVS, options, CancellationToken.None); - - var expectedResults = new LSP.SemanticTokens(); - var tokenTypeToIndex = GetTokenTypeToIndex(testLspServer); - if (isVS) - { - expectedResults.Data = - [ - // Line | Char | Len | Token type | Modifier - 1, 0, 6, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'static' - 0, 7, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' - 0, 6, 1, tokenTypeToIndex[ClassificationTypeNames.ClassName], (int)TokenModifiers.Static, // 'C' - 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' - 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '}' - ]; - } - else - { - expectedResults.Data = - [ - // Line | Char | Len | Token type | Modifier - 1, 0, 6, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'static' - 0, 7, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' - 0, 6, 1, tokenTypeToIndex[SemanticTokenTypes.Class], (int)TokenModifiers.Static, // 'C' - 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' - 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '}' - ]; - } + await using var testLspServer = await CreateTestLspServerAsync( + markup, mutatingLspWorkspace, GetCapabilities(isVS)); - await VerifyBasicInvariantsAndNoMultiLineTokens(testLspServer, results).ConfigureAwait(false); - AssertEx.Equal(ConvertToReadableFormat(testLspServer.ClientCapabilities, expectedResults.Data), ConvertToReadableFormat(testLspServer.ClientCapabilities, results)); - } + var document = testLspServer.GetCurrentSolution().Projects.First().Documents.First(); + ImmutableArray spans = [new LinePositionSpan(new LinePosition(0, 0), new LinePosition(9, 0))]; + var options = ClassificationOptions.Default; + var results = await SemanticTokensHelpers.ComputeSemanticTokensDataAsync( + document, spans, isVS, options, CancellationToken.None); - [Theory, CombinatorialData] - public async Task TestGetSemanticTokensRange_MultiLineComment_IncludeSyntacticClassificationsAsync(bool mutatingLspWorkspace, bool isVS) + var expectedResults = new LSP.SemanticTokens(); + var tokenTypeToIndex = GetTokenTypeToIndex(testLspServer); + if (isVS) { - // Testing as a Razor doc so we get both syntactic + semantic results; otherwise the results would be empty. - var markup = -@"{|caret:|}class C { /* one - -two -three */ } -"; - await using var testLspServer = await CreateTestLspServerAsync( - markup, mutatingLspWorkspace, GetCapabilities(isVS)); - - var document = testLspServer.GetCurrentSolution().Projects.First().Documents.First(); - ImmutableArray spans = [new LinePositionSpan(new LinePosition(0, 0), new LinePosition(4, 0))]; - var options = ClassificationOptions.Default; - var results = await SemanticTokensHelpers.ComputeSemanticTokensDataAsync( - document, spans, isVS, options, CancellationToken.None); - - var expectedResults = new LSP.SemanticTokens(); - var tokenTypeToIndex = GetTokenTypeToIndex(testLspServer); - if (isVS) - { - expectedResults.Data = - [ - // Line | Char | Len | Token type | Modifier - 0, 0, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' - 0, 6, 1, tokenTypeToIndex[ClassificationTypeNames.ClassName], 0, // 'C' - 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' - 0, 2, 6, tokenTypeToIndex[SemanticTokenTypes.Comment], 0, // '/* one' - 2, 0, 3, tokenTypeToIndex[SemanticTokenTypes.Comment], 0, // 'two' - 1, 0, 8, tokenTypeToIndex[SemanticTokenTypes.Comment], 0, // 'three */' - 0, 9, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '}' - ]; - } - else - { - expectedResults.Data = - [ - // Line | Char | Len | Token type | Modifier - 0, 0, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' - 0, 6, 1, tokenTypeToIndex[SemanticTokenTypes.Class], 0, // 'C' - 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' - 0, 2, 6, tokenTypeToIndex[SemanticTokenTypes.Comment], 0, // '/* one' - 2, 0, 3, tokenTypeToIndex[SemanticTokenTypes.Comment], 0, // 'two' - 1, 0, 8, tokenTypeToIndex[SemanticTokenTypes.Comment], 0, // 'three */' - 0, 9, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '}' - ]; - } - - await VerifyBasicInvariantsAndNoMultiLineTokens(testLspServer, results).ConfigureAwait(false); - AssertEx.Equal(ConvertToReadableFormat(testLspServer.ClientCapabilities, expectedResults.Data), ConvertToReadableFormat(testLspServer.ClientCapabilities, results)); + expectedResults.Data = + [ + // Line | Char | Len | Token type | Modifier + 0, 0, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' + 0, 6, 1, tokenTypeToIndex[ClassificationTypeNames.ClassName], 0, // 'C' + 1, 0, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' + 1, 4, 4, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'void' + 0, 5, 1, tokenTypeToIndex[ClassificationTypeNames.MethodName], 0, // 'M' + 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '(' + 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // ')' + 1, 4, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' + 1, 8, 3, tokenTypeToIndex[ClassificationTypeNames.Keyword], 0, // 'var' + 0, 4, 1, tokenTypeToIndex[ClassificationTypeNames.LocalName], 0, // 'x' + 0, 2, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '=' + 0, 2, 5, tokenTypeToIndex[ClassificationTypeNames.VerbatimStringLiteral], 0, // '@"one' + 1, 0, 4, tokenTypeToIndex[ClassificationTypeNames.VerbatimStringLiteral], 0, // 'two ' + 0, 4, 2, tokenTypeToIndex[ClassificationTypeNames.StringEscapeCharacter], 0, // '""' + 1, 0, 6, tokenTypeToIndex[ClassificationTypeNames.VerbatimStringLiteral], 0, // 'three"' + 0, 6, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // ';' + 1, 4, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '}' + 1, 0, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '}' + ]; } - - [Theory, CombinatorialData] - public async Task TestGetSemanticTokensRange_StringLiteral_IncludeSyntacticClassificationsAsync(bool mutatingLspWorkspace, bool isVS) + else { - var markup = -@"{|caret:|}class C -{ - void M() - { - var x = @""one -two """" -three""; - } -} -"; + expectedResults.Data = + [ + // Line | Char | Len | Token type | Modifier + 0, 0, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' + 0, 6, 1, tokenTypeToIndex[SemanticTokenTypes.Class], 0, // 'C' + 1, 0, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // '{' + 1, 4, 4, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'void' + 0, 5, 1, tokenTypeToIndex[SemanticTokenTypes.Method], 0, // 'M' + 0, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // '(' + 0, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // ')' + 1, 4, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // '{' + 1, 8, 3, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'var' + 0, 4, 1, tokenTypeToIndex[SemanticTokenTypes.Variable], 0, // 'x' + 0, 2, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '=' + 0, 2, 5, tokenTypeToIndex[CustomLspSemanticTokenNames.StringVerbatim], 0, // '@"one' + 1, 0, 4, tokenTypeToIndex[CustomLspSemanticTokenNames.StringVerbatim], 0, // 'two ' + 0, 4, 2, tokenTypeToIndex[CustomLspSemanticTokenNames.StringEscapeCharacter], 0, // '""' + 1, 0, 6, tokenTypeToIndex[CustomLspSemanticTokenNames.StringVerbatim], 0, // 'three"' + 0, 6, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // ';' + 1, 4, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '}' + 1, 0, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '}' + ]; + } - await using var testLspServer = await CreateTestLspServerAsync( - markup, mutatingLspWorkspace, GetCapabilities(isVS)); + await VerifyBasicInvariantsAndNoMultiLineTokens(testLspServer, results).ConfigureAwait(false); + AssertEx.Equal(ConvertToReadableFormat(testLspServer.ClientCapabilities, expectedResults.Data), ConvertToReadableFormat(testLspServer.ClientCapabilities, results)); + } - var document = testLspServer.GetCurrentSolution().Projects.First().Documents.First(); - ImmutableArray spans = [new LinePositionSpan(new LinePosition(0, 0), new LinePosition(9, 0))]; - var options = ClassificationOptions.Default; - var results = await SemanticTokensHelpers.ComputeSemanticTokensDataAsync( - document, spans, isVS, options, CancellationToken.None); + [Theory, CombinatorialData] + public async Task TestGetSemanticTokensRange_Regex_IncludeSyntacticClassificationsAsync(bool mutatingLspWorkspace, bool isVS) + { + var markup = + """ + {|caret:|}using System.Text.RegularExpressions; - var expectedResults = new LSP.SemanticTokens(); - var tokenTypeToIndex = GetTokenTypeToIndex(testLspServer); - if (isVS) - { - expectedResults.Data = - [ - // Line | Char | Len | Token type | Modifier - 0, 0, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' - 0, 6, 1, tokenTypeToIndex[ClassificationTypeNames.ClassName], 0, // 'C' - 1, 0, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' - 1, 4, 4, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'void' - 0, 5, 1, tokenTypeToIndex[ClassificationTypeNames.MethodName], 0, // 'M' - 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '(' - 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // ')' - 1, 4, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' - 1, 8, 3, tokenTypeToIndex[ClassificationTypeNames.Keyword], 0, // 'var' - 0, 4, 1, tokenTypeToIndex[ClassificationTypeNames.LocalName], 0, // 'x' - 0, 2, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '=' - 0, 2, 5, tokenTypeToIndex[ClassificationTypeNames.VerbatimStringLiteral], 0, // '@"one' - 1, 0, 4, tokenTypeToIndex[ClassificationTypeNames.VerbatimStringLiteral], 0, // 'two ' - 0, 4, 2, tokenTypeToIndex[ClassificationTypeNames.StringEscapeCharacter], 0, // '""' - 1, 0, 6, tokenTypeToIndex[ClassificationTypeNames.VerbatimStringLiteral], 0, // 'three"' - 0, 6, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // ';' - 1, 4, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '}' - 1, 0, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '}' - ]; - } - else + class C { - expectedResults.Data = - [ - // Line | Char | Len | Token type | Modifier - 0, 0, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' - 0, 6, 1, tokenTypeToIndex[SemanticTokenTypes.Class], 0, // 'C' - 1, 0, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // '{' - 1, 4, 4, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'void' - 0, 5, 1, tokenTypeToIndex[SemanticTokenTypes.Method], 0, // 'M' - 0, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // '(' - 0, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // ')' - 1, 4, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // '{' - 1, 8, 3, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'var' - 0, 4, 1, tokenTypeToIndex[SemanticTokenTypes.Variable], 0, // 'x' - 0, 2, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '=' - 0, 2, 5, tokenTypeToIndex[CustomLspSemanticTokenNames.StringVerbatim], 0, // '@"one' - 1, 0, 4, tokenTypeToIndex[CustomLspSemanticTokenNames.StringVerbatim], 0, // 'two ' - 0, 4, 2, tokenTypeToIndex[CustomLspSemanticTokenNames.StringEscapeCharacter], 0, // '""' - 1, 0, 6, tokenTypeToIndex[CustomLspSemanticTokenNames.StringVerbatim], 0, // 'three"' - 0, 6, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // ';' - 1, 4, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '}' - 1, 0, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '}' - ]; + void M() + { + var x = new Regex("(abc)*"); + } } - await VerifyBasicInvariantsAndNoMultiLineTokens(testLspServer, results).ConfigureAwait(false); - AssertEx.Equal(ConvertToReadableFormat(testLspServer.ClientCapabilities, expectedResults.Data), ConvertToReadableFormat(testLspServer.ClientCapabilities, results)); - } + """; - [Theory, CombinatorialData] - public async Task TestGetSemanticTokensRange_Regex_IncludeSyntacticClassificationsAsync(bool mutatingLspWorkspace, bool isVS) + await using var testLspServer = await CreateTestLspServerAsync( + markup, mutatingLspWorkspace, GetCapabilities(isVS)); + + var document = testLspServer.GetCurrentSolution().Projects.First().Documents.First(); + ImmutableArray spans = [new LinePositionSpan(new LinePosition(0, 0), new LinePosition(9, 0))]; + var options = ClassificationOptions.Default; + var results = await SemanticTokensHelpers.ComputeSemanticTokensDataAsync( + document, spans, isVS, options, CancellationToken.None); + + var expectedResults = new LSP.SemanticTokens(); + var tokenTypeToIndex = GetTokenTypeToIndex(testLspServer); + if (isVS) { - var markup = -@"{|caret:|}using System.Text.RegularExpressions; + expectedResults.Data = + [ + // Line | Char | Len | Token type | Modifier + 0, 0, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'using' + 0, 6, 6, tokenTypeToIndex[ClassificationTypeNames.NamespaceName], 0, // 'System' + 0, 6, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '.' + 0, 1, 4, tokenTypeToIndex[ClassificationTypeNames.NamespaceName], 0, // 'Text' + 0, 4, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '.' + 0, 1, 18, tokenTypeToIndex[ClassificationTypeNames.NamespaceName], 0, // 'RegularExpressions' + 0, 18, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // ';' + 2, 0, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' + 0, 6, 1, tokenTypeToIndex[ClassificationTypeNames.ClassName], 0, // 'C' + 1, 0, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' + 1, 1, 4, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'void' + 0, 5, 1, tokenTypeToIndex[ClassificationTypeNames.MethodName], 0, // 'M' + 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '(' + 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // ')' + 1, 1, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' + 1, 2, 3, tokenTypeToIndex[ClassificationTypeNames.Keyword], 0, // 'var' + 0, 4, 1, tokenTypeToIndex[ClassificationTypeNames.LocalName], 0, // 'x' + 0, 2, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '=' + 0, 2, 3, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'new' + 0, 4, 5, tokenTypeToIndex[ClassificationTypeNames.ClassName], 0, // 'Regex' + 0, 5, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '(' + 0, 1, 1, tokenTypeToIndex[SemanticTokenTypes.String], 0, // '"' + 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.RegexGrouping], 0, // '(' + 0, 1, 3, tokenTypeToIndex[ClassificationTypeNames.RegexText], 0, // 'abc' + 0, 3, 1, tokenTypeToIndex[ClassificationTypeNames.RegexGrouping], 0, // ')' + 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.RegexQuantifier], 0, // '*' + 0, 1, 1, tokenTypeToIndex[SemanticTokenTypes.String], 0, // '"' + 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // ')' + 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // ';' + 1, 4, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // } + 1, 0, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // } + ]; + } + else + { + expectedResults.Data = + [ + // Line | Char | Len | Token type | Modifier + 0, 0, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'using' + 0, 6, 6, tokenTypeToIndex[SemanticTokenTypes.Namespace], 0, // 'System' + 0, 6, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '.' + 0, 1, 4, tokenTypeToIndex[SemanticTokenTypes.Namespace], 0, // 'Text' + 0, 4, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '.' + 0, 1, 18, tokenTypeToIndex[SemanticTokenTypes.Namespace], 0, // 'RegularExpressions' + 0, 18, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // ';' + 2, 0, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' + 0, 6, 1, tokenTypeToIndex[SemanticTokenTypes.Class], 0, // 'C' + 1, 0, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // '{' + 1, 1, 4, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'void' + 0, 5, 1, tokenTypeToIndex[SemanticTokenTypes.Method], 0, // 'M' + 0, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // '(' + 0, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // ')' + 1, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // '{' + 1, 2, 3, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'var' + 0, 4, 1, tokenTypeToIndex[SemanticTokenTypes.Variable], 0, // 'x' + 0, 2, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '=' + 0, 2, 3, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'new' + 0, 4, 5, tokenTypeToIndex[SemanticTokenTypes.Class], 0, // 'Regex' + 0, 5, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // '(' + 0, 1, 1, tokenTypeToIndex[SemanticTokenTypes.String], 0, // '"' + 0, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.RegexGrouping], 0, // '(' + 0, 1, 3, tokenTypeToIndex[CustomLspSemanticTokenNames.RegexText], 0, // 'abc' + 0, 3, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.RegexGrouping], 0, // ')' + 0, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.RegexQuantifier], 0, // '*' + 0, 1, 1, tokenTypeToIndex[SemanticTokenTypes.String], 0, // '"' + 0, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // ')' + 0, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // ';' + 1, 4, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // } + 1, 0, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // } + ]; + } -class C -{ - void M() - { - var x = new Regex(""(abc)*""); + await VerifyBasicInvariantsAndNoMultiLineTokens(testLspServer, results).ConfigureAwait(false); + AssertEx.Equal(ConvertToReadableFormat(testLspServer.ClientCapabilities, expectedResults.Data), ConvertToReadableFormat(testLspServer.ClientCapabilities, results)); } -} -"; - await using var testLspServer = await CreateTestLspServerAsync( - markup, mutatingLspWorkspace, GetCapabilities(isVS)); - - var document = testLspServer.GetCurrentSolution().Projects.First().Documents.First(); - ImmutableArray spans = [new LinePositionSpan(new LinePosition(0, 0), new LinePosition(9, 0))]; - var options = ClassificationOptions.Default; - var results = await SemanticTokensHelpers.ComputeSemanticTokensDataAsync( - document, spans, isVS, options, CancellationToken.None); + [Theory, CombinatorialData] + [WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1710519")] + public async Task TestGetSemanticTokensRange_RegexWithComment_IncludeSyntacticClassificationsAsync(bool mutatingLspWorkspace, bool isVS) + { + var markup = + """ + {|caret:|}using System.Text.RegularExpressions; - var expectedResults = new LSP.SemanticTokens(); - var tokenTypeToIndex = GetTokenTypeToIndex(testLspServer); - if (isVS) - { - expectedResults.Data = - [ - // Line | Char | Len | Token type | Modifier - 0, 0, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'using' - 0, 6, 6, tokenTypeToIndex[ClassificationTypeNames.NamespaceName], 0, // 'System' - 0, 6, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '.' - 0, 1, 4, tokenTypeToIndex[ClassificationTypeNames.NamespaceName], 0, // 'Text' - 0, 4, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '.' - 0, 1, 18, tokenTypeToIndex[ClassificationTypeNames.NamespaceName], 0, // 'RegularExpressions' - 0, 18, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // ';' - 2, 0, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' - 0, 6, 1, tokenTypeToIndex[ClassificationTypeNames.ClassName], 0, // 'C' - 1, 0, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' - 1, 1, 4, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'void' - 0, 5, 1, tokenTypeToIndex[ClassificationTypeNames.MethodName], 0, // 'M' - 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '(' - 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // ')' - 1, 1, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' - 1, 2, 3, tokenTypeToIndex[ClassificationTypeNames.Keyword], 0, // 'var' - 0, 4, 1, tokenTypeToIndex[ClassificationTypeNames.LocalName], 0, // 'x' - 0, 2, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '=' - 0, 2, 3, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'new' - 0, 4, 5, tokenTypeToIndex[ClassificationTypeNames.ClassName], 0, // 'Regex' - 0, 5, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '(' - 0, 1, 1, tokenTypeToIndex[SemanticTokenTypes.String], 0, // '"' - 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.RegexGrouping], 0, // '(' - 0, 1, 3, tokenTypeToIndex[ClassificationTypeNames.RegexText], 0, // 'abc' - 0, 3, 1, tokenTypeToIndex[ClassificationTypeNames.RegexGrouping], 0, // ')' - 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.RegexQuantifier], 0, // '*' - 0, 1, 1, tokenTypeToIndex[SemanticTokenTypes.String], 0, // '"' - 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // ')' - 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // ';' - 1, 4, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // } - 1, 0, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // } - ]; - } - else + class C { - expectedResults.Data = - [ - // Line | Char | Len | Token type | Modifier - 0, 0, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'using' - 0, 6, 6, tokenTypeToIndex[SemanticTokenTypes.Namespace], 0, // 'System' - 0, 6, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '.' - 0, 1, 4, tokenTypeToIndex[SemanticTokenTypes.Namespace], 0, // 'Text' - 0, 4, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '.' - 0, 1, 18, tokenTypeToIndex[SemanticTokenTypes.Namespace], 0, // 'RegularExpressions' - 0, 18, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // ';' - 2, 0, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' - 0, 6, 1, tokenTypeToIndex[SemanticTokenTypes.Class], 0, // 'C' - 1, 0, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // '{' - 1, 1, 4, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'void' - 0, 5, 1, tokenTypeToIndex[SemanticTokenTypes.Method], 0, // 'M' - 0, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // '(' - 0, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // ')' - 1, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // '{' - 1, 2, 3, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'var' - 0, 4, 1, tokenTypeToIndex[SemanticTokenTypes.Variable], 0, // 'x' - 0, 2, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '=' - 0, 2, 3, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'new' - 0, 4, 5, tokenTypeToIndex[SemanticTokenTypes.Class], 0, // 'Regex' - 0, 5, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // '(' - 0, 1, 1, tokenTypeToIndex[SemanticTokenTypes.String], 0, // '"' - 0, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.RegexGrouping], 0, // '(' - 0, 1, 3, tokenTypeToIndex[CustomLspSemanticTokenNames.RegexText], 0, // 'abc' - 0, 3, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.RegexGrouping], 0, // ')' - 0, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.RegexQuantifier], 0, // '*' - 0, 1, 1, tokenTypeToIndex[SemanticTokenTypes.String], 0, // '"' - 0, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // ')' - 0, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // ';' - 1, 4, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // } - 1, 0, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // } - ]; + void M() + { + var x = new Regex(@"(abc)* #comment + ", RegexOptions.IgnorePatternWhitespace); + } } - await VerifyBasicInvariantsAndNoMultiLineTokens(testLspServer, results).ConfigureAwait(false); - AssertEx.Equal(ConvertToReadableFormat(testLspServer.ClientCapabilities, expectedResults.Data), ConvertToReadableFormat(testLspServer.ClientCapabilities, results)); - } + """; - [Theory, CombinatorialData] - [WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1710519")] - public async Task TestGetSemanticTokensRange_RegexWithComment_IncludeSyntacticClassificationsAsync(bool mutatingLspWorkspace, bool isVS) - { - var markup = -@"{|caret:|}using System.Text.RegularExpressions; + await using var testLspServer = await CreateTestLspServerAsync( + markup, mutatingLspWorkspace, GetCapabilities(isVS)); -class C -{ - void M() - { - var x = new Regex(@""(abc)* #comment - "", RegexOptions.IgnorePatternWhitespace); - } -} -"; - - await using var testLspServer = await CreateTestLspServerAsync( - markup, mutatingLspWorkspace, GetCapabilities(isVS)); + var document = testLspServer.GetCurrentSolution().Projects.First().Documents.First(); + var text = await document.GetTextAsync(); + var options = ClassificationOptions.Default; + var results = await SemanticTokensHelpers.ComputeSemanticTokensDataAsync( + document, spans: [text.Lines.GetLinePositionSpan(new(0, text.Length))], isVS, options: options, cancellationToken: CancellationToken.None); - var document = testLspServer.GetCurrentSolution().Projects.First().Documents.First(); - var options = ClassificationOptions.Default; - var results = await SemanticTokensHelpers.ComputeSemanticTokensDataAsync( - document, spans: [], isVS, options: options, cancellationToken: CancellationToken.None); + var expectedResults = new LSP.SemanticTokens(); - var expectedResults = new LSP.SemanticTokens(); + var tokenTypeToIndex = GetTokenTypeToIndex(testLspServer); + if (isVS) + { + expectedResults.Data = + [ + // Line | Char | Len | Token type | Modifier + 0, 0, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'using' + 0, 6, 6, tokenTypeToIndex[ClassificationTypeNames.NamespaceName], 0, // 'System' + 0, 6, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '.' + 0, 1, 4, tokenTypeToIndex[ClassificationTypeNames.NamespaceName], 0, // 'Text' + 0, 4, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '.' + 0, 1, 18, tokenTypeToIndex[ClassificationTypeNames.NamespaceName], 0, // 'RegularExpressions' + 0, 18, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // ';' + 2, 0, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' + 0, 6, 1, tokenTypeToIndex[ClassificationTypeNames.ClassName], 0, // 'C' + 1, 0, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' + 1, 1, 4, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'void' + 0, 5, 1, tokenTypeToIndex[ClassificationTypeNames.MethodName], 0, // 'M' + 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '(' + 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // ')' + 1, 1, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' + 1, 2, 3, tokenTypeToIndex[ClassificationTypeNames.Keyword], 0, // 'var' + 0, 4, 1, tokenTypeToIndex[ClassificationTypeNames.LocalName], 0, // 'x' + 0, 2, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '=' + 0, 2, 3, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'new' + 0, 4, 5, tokenTypeToIndex[ClassificationTypeNames.ClassName], 0, // 'Regex' + 0, 5, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '(' + 0, 1, 2, tokenTypeToIndex[ClassificationTypeNames.VerbatimStringLiteral], 0, // '@"' + 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.RegexGrouping], 0, // '(' + 0, 1, 3, tokenTypeToIndex[ClassificationTypeNames.RegexText], 0, // 'abc' + 0, 3, 1, tokenTypeToIndex[ClassificationTypeNames.RegexGrouping], 0, // ')' + 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.RegexQuantifier], 0, // '*' + 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.VerbatimStringLiteral], 0, // ' ' + 0, 1, 9, tokenTypeToIndex[ClassificationTypeNames.RegexComment], 0, // '#comment' + 1, 0, 27, tokenTypeToIndex[ClassificationTypeNames.VerbatimStringLiteral], 0, // '"' + 0, 27, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // ',' + 0, 2, 12, tokenTypeToIndex[ClassificationTypeNames.EnumName], 0, // 'RegexOptions' + 0, 12, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '.' + 0, 1, 23, tokenTypeToIndex[ClassificationTypeNames.EnumMemberName], 0, // 'IgnorePatternWhitespace' + 0, 23, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // ')' + 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // ';' + 1, 4, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // } + 1, 0, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // } + ]; + } + else + { + expectedResults.Data = + [ + // Line | Char | Len | Token type | Modifier + 0, 0, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'using' + 0, 6, 6, tokenTypeToIndex[SemanticTokenTypes.Namespace], 0, // 'System' + 0, 6, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '.' + 0, 1, 4, tokenTypeToIndex[SemanticTokenTypes.Namespace], 0, // 'Text' + 0, 4, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '.' + 0, 1, 18, tokenTypeToIndex[SemanticTokenTypes.Namespace], 0, // 'RegularExpressions' + 0, 18, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // ';' + 2, 0, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' + 0, 6, 1, tokenTypeToIndex[SemanticTokenTypes.Class], 0, // 'C' + 1, 0, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // '{' + 1, 1, 4, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'void' + 0, 5, 1, tokenTypeToIndex[SemanticTokenTypes.Method], 0, // 'M' + 0, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // '(' + 0, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // ')' + 1, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // '{' + 1, 2, 3, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'var' + 0, 4, 1, tokenTypeToIndex[SemanticTokenTypes.Variable], 0, // 'x' + 0, 2, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '=' + 0, 2, 3, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'new' + 0, 4, 5, tokenTypeToIndex[SemanticTokenTypes.Class], 0, // 'Regex' + 0, 5, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // '(' + 0, 1, 2, tokenTypeToIndex[CustomLspSemanticTokenNames.StringVerbatim], 0, // '@"' + 0, 2, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.RegexGrouping], 0, // '(' + 0, 1, 3, tokenTypeToIndex[CustomLspSemanticTokenNames.RegexText], 0, // 'abc' + 0, 3, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.RegexGrouping], 0, // ')' + 0, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.RegexQuantifier], 0, // '*' + 0, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.StringVerbatim], 0, // ' ' + 0, 1, 9, tokenTypeToIndex[CustomLspSemanticTokenNames.RegexComment], 0, // '#comment' + 1, 0, 27, tokenTypeToIndex[CustomLspSemanticTokenNames.StringVerbatim], 0, // '"' + 0, 27, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // ',' + 0, 2, 12, tokenTypeToIndex[SemanticTokenTypes.Enum], 0, // 'RegexOptions' + 0, 12, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '.' + 0, 1, 23, tokenTypeToIndex[SemanticTokenTypes.EnumMember], 0, // 'IgnorePatternWhitespace' + 0, 23, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // ')' + 0, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // ';' + 1, 4, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // } + 1, 0, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // } + ]; + } - var tokenTypeToIndex = GetTokenTypeToIndex(testLspServer); - if (isVS) - { - expectedResults.Data = - [ - // Line | Char | Len | Token type | Modifier - 0, 0, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'using' - 0, 6, 6, tokenTypeToIndex[ClassificationTypeNames.NamespaceName], 0, // 'System' - 0, 6, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '.' - 0, 1, 4, tokenTypeToIndex[ClassificationTypeNames.NamespaceName], 0, // 'Text' - 0, 4, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '.' - 0, 1, 18, tokenTypeToIndex[ClassificationTypeNames.NamespaceName], 0, // 'RegularExpressions' - 0, 18, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // ';' - 2, 0, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' - 0, 6, 1, tokenTypeToIndex[ClassificationTypeNames.ClassName], 0, // 'C' - 1, 0, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' - 1, 1, 4, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'void' - 0, 5, 1, tokenTypeToIndex[ClassificationTypeNames.MethodName], 0, // 'M' - 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '(' - 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // ')' - 1, 1, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' - 1, 2, 3, tokenTypeToIndex[ClassificationTypeNames.Keyword], 0, // 'var' - 0, 4, 1, tokenTypeToIndex[ClassificationTypeNames.LocalName], 0, // 'x' - 0, 2, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '=' - 0, 2, 3, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'new' - 0, 4, 5, tokenTypeToIndex[ClassificationTypeNames.ClassName], 0, // 'Regex' - 0, 5, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '(' - 0, 1, 2, tokenTypeToIndex[ClassificationTypeNames.VerbatimStringLiteral], 0, // '@"' - 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.RegexGrouping], 0, // '(' - 0, 1, 3, tokenTypeToIndex[ClassificationTypeNames.RegexText], 0, // 'abc' - 0, 3, 1, tokenTypeToIndex[ClassificationTypeNames.RegexGrouping], 0, // ')' - 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.RegexQuantifier], 0, // '*' - 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.VerbatimStringLiteral], 0, // ' ' - 0, 1, 9, tokenTypeToIndex[ClassificationTypeNames.RegexComment], 0, // '#comment' - 1, 0, 27, tokenTypeToIndex[ClassificationTypeNames.VerbatimStringLiteral], 0, // '"' - 0, 27, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // ',' - 0, 2, 12, tokenTypeToIndex[ClassificationTypeNames.EnumName], 0, // 'RegexOptions' - 0, 12, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '.' - 0, 1, 23, tokenTypeToIndex[ClassificationTypeNames.EnumMemberName], 0, // 'IgnorePatternWhitespace' - 0, 23, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // ')' - 0, 1, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // ';' - 1, 4, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // } - 1, 0, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // } - ]; - } - else - { - expectedResults.Data = - [ - // Line | Char | Len | Token type | Modifier - 0, 0, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'using' - 0, 6, 6, tokenTypeToIndex[SemanticTokenTypes.Namespace], 0, // 'System' - 0, 6, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '.' - 0, 1, 4, tokenTypeToIndex[SemanticTokenTypes.Namespace], 0, // 'Text' - 0, 4, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '.' - 0, 1, 18, tokenTypeToIndex[SemanticTokenTypes.Namespace], 0, // 'RegularExpressions' - 0, 18, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // ';' - 2, 0, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' - 0, 6, 1, tokenTypeToIndex[SemanticTokenTypes.Class], 0, // 'C' - 1, 0, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // '{' - 1, 1, 4, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'void' - 0, 5, 1, tokenTypeToIndex[SemanticTokenTypes.Method], 0, // 'M' - 0, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // '(' - 0, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // ')' - 1, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // '{' - 1, 2, 3, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'var' - 0, 4, 1, tokenTypeToIndex[SemanticTokenTypes.Variable], 0, // 'x' - 0, 2, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '=' - 0, 2, 3, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'new' - 0, 4, 5, tokenTypeToIndex[SemanticTokenTypes.Class], 0, // 'Regex' - 0, 5, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // '(' - 0, 1, 2, tokenTypeToIndex[CustomLspSemanticTokenNames.StringVerbatim], 0, // '@"' - 0, 2, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.RegexGrouping], 0, // '(' - 0, 1, 3, tokenTypeToIndex[CustomLspSemanticTokenNames.RegexText], 0, // 'abc' - 0, 3, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.RegexGrouping], 0, // ')' - 0, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.RegexQuantifier], 0, // '*' - 0, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.StringVerbatim], 0, // ' ' - 0, 1, 9, tokenTypeToIndex[CustomLspSemanticTokenNames.RegexComment], 0, // '#comment' - 1, 0, 27, tokenTypeToIndex[CustomLspSemanticTokenNames.StringVerbatim], 0, // '"' - 0, 27, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // ',' - 0, 2, 12, tokenTypeToIndex[SemanticTokenTypes.Enum], 0, // 'RegexOptions' - 0, 12, 1, tokenTypeToIndex[SemanticTokenTypes.Operator], 0, // '.' - 0, 1, 23, tokenTypeToIndex[SemanticTokenTypes.EnumMember], 0, // 'IgnorePatternWhitespace' - 0, 23, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // ')' - 0, 1, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // ';' - 1, 4, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // } - 1, 0, 1, tokenTypeToIndex[CustomLspSemanticTokenNames.Punctuation], 0, // } - ]; - } + await VerifyBasicInvariantsAndNoMultiLineTokens(testLspServer, results).ConfigureAwait(false); + AssertEx.Equal(ConvertToReadableFormat(testLspServer.ClientCapabilities, expectedResults.Data), ConvertToReadableFormat(testLspServer.ClientCapabilities, results)); + } - await VerifyBasicInvariantsAndNoMultiLineTokens(testLspServer, results).ConfigureAwait(false); - AssertEx.Equal(ConvertToReadableFormat(testLspServer.ClientCapabilities, expectedResults.Data), ConvertToReadableFormat(testLspServer.ClientCapabilities, results)); - } + [Theory, CombinatorialData] + public void TestGetSemanticTokensRange_AssertCustomTokenTypes(bool isVS) + { + var capabilities = GetCapabilities(isVS); + var schema = SemanticTokensSchema.GetSchema(capabilities.HasVisualStudioLspCapability()); - [Theory, CombinatorialData] - public void TestGetSemanticTokensRange_AssertCustomTokenTypes(bool isVS) + var expectedNames = ClassificationTypeNames.AllTypeNames.Where(s => !ClassificationTypeNames.AdditiveTypeNames.Contains(s)); + foreach (var expectedClassificationName in expectedNames) { - var capabilities = GetCapabilities(isVS); - var schema = SemanticTokensSchema.GetSchema(capabilities.HasVisualStudioLspCapability()); + // Assert that the classification type name exists and is mapped to a semantic token name. + Assert.True(schema.TokenTypeMap.ContainsKey(expectedClassificationName), $"Missing token type for {expectedClassificationName}."); - var expectedNames = ClassificationTypeNames.AllTypeNames.Where(s => !ClassificationTypeNames.AdditiveTypeNames.Contains(s)); - foreach (var expectedClassificationName in expectedNames) - { - // Assert that the classification type name exists and is mapped to a semantic token name. - Assert.True(schema.TokenTypeMap.ContainsKey(expectedClassificationName), $"Missing token type for {expectedClassificationName}."); - - var tokenName = schema.TokenTypeMap[expectedClassificationName]; - Assert.True(schema.AllTokenTypes.Contains(tokenName)); - } + var tokenName = schema.TokenTypeMap[expectedClassificationName]; + Assert.True(schema.AllTokenTypes.Contains(tokenName)); } } } diff --git a/src/LanguageServer/ProtocolUnitTests/SemanticTokens/SemanticTokensRangesTests.cs b/src/LanguageServer/ProtocolUnitTests/SemanticTokens/SemanticTokensRangesTests.cs index 3b7b832625688..a2cea4ca9be85 100644 --- a/src/LanguageServer/ProtocolUnitTests/SemanticTokens/SemanticTokensRangesTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/SemanticTokens/SemanticTokensRangesTests.cs @@ -12,60 +12,57 @@ using Xunit.Abstractions; using LSP = Roslyn.LanguageServer.Protocol; -namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.SemanticTokens +namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.SemanticTokens; + +public sealed class SemanticTokensRangesTests(ITestOutputHelper testOutputHelper) : AbstractSemanticTokensTests(testOutputHelper) { - public class SemanticTokensRangesTests : AbstractSemanticTokensTests + [Theory, CombinatorialData] + public async Task TestGetSemanticTokensRanges_FullDocAsync(bool mutatingLspWorkspace, bool isVS) { - public SemanticTokensRangesTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) - { - } + var markup = + """ + {|caret:|}// Comment + static class C { } - [Theory, CombinatorialData] - public async Task TestGetSemanticTokensRanges_FullDocAsync(bool mutatingLspWorkspace, bool isVS) - { - var markup = -@"{|caret:|}// Comment -static class C { } -"; - await using var testLspServer = await CreateTestLspServerAsync( - markup, mutatingLspWorkspace, GetCapabilities(isVS)); + """; + await using var testLspServer = await CreateTestLspServerAsync( + markup, mutatingLspWorkspace, GetCapabilities(isVS)); - var ranges = new[] { new LSP.Range { Start = new Position(0, 0), End = new Position(2, 0) } }; - var results = await RunGetSemanticTokensRangesAsync(testLspServer, testLspServer.GetLocations("caret").First(), ranges); + var ranges = new[] { new LSP.Range { Start = new Position(0, 0), End = new Position(2, 0) } }; + var results = await RunGetSemanticTokensRangesAsync(testLspServer, testLspServer.GetLocations("caret").First(), ranges); - var expectedResults = new LSP.SemanticTokens(); - var tokenTypeToIndex = GetTokenTypeToIndex(testLspServer); - if (isVS) - { - expectedResults.Data = + var expectedResults = new LSP.SemanticTokens(); + var tokenTypeToIndex = GetTokenTypeToIndex(testLspServer); + if (isVS) + { + expectedResults.Data = #pragma warning disable format // Force explicit column spacing. - [ - // Line | Char | Len | Token type | Modifier - 0, 0, 10, tokenTypeToIndex[SemanticTokenTypes.Comment], 0, // '// Comment' - 1, 0, 6, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'static' - 0, 7, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' - 0, 6, 1, tokenTypeToIndex[ClassificationTypeNames.ClassName], (int)TokenModifiers.Static, // 'C' - 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' - 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '}' - ]; - } - else - { - expectedResults.Data = - [ - // Line | Char | Len | Token type | Modifier - 0, 0, 10, tokenTypeToIndex[SemanticTokenTypes.Comment], 0, // '// Comment' - 1, 0, 6, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'static' - 0, 7, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' - 0, 6, 1, tokenTypeToIndex[SemanticTokenTypes.Class], (int)TokenModifiers.Static, // 'C' - 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' - 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '}' - ]; - } + [ + // Line | Char | Len | Token type | Modifier + 0, 0, 10, tokenTypeToIndex[SemanticTokenTypes.Comment], 0, // '// Comment' + 1, 0, 6, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'static' + 0, 7, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' + 0, 6, 1, tokenTypeToIndex[ClassificationTypeNames.ClassName], (int)TokenModifiers.Static, // 'C' + 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' + 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '}' + ]; + } + else + { + expectedResults.Data = + [ + // Line | Char | Len | Token type | Modifier + 0, 0, 10, tokenTypeToIndex[SemanticTokenTypes.Comment], 0, // '// Comment' + 1, 0, 6, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'static' + 0, 7, 5, tokenTypeToIndex[SemanticTokenTypes.Keyword], 0, // 'class' + 0, 6, 1, tokenTypeToIndex[SemanticTokenTypes.Class], (int)TokenModifiers.Static, // 'C' + 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '{' + 0, 2, 1, tokenTypeToIndex[ClassificationTypeNames.Punctuation], 0, // '}' + ]; + } #pragma warning restore format - await VerifyBasicInvariantsAndNoMultiLineTokens(testLspServer, results.Data).ConfigureAwait(false); - AssertEx.Equal(ConvertToReadableFormat(testLspServer.ClientCapabilities, expectedResults.Data), ConvertToReadableFormat(testLspServer.ClientCapabilities, results.Data)); - } + await VerifyBasicInvariantsAndNoMultiLineTokens(testLspServer, results.Data).ConfigureAwait(false); + AssertEx.Equal(ConvertToReadableFormat(testLspServer.ClientCapabilities, expectedResults.Data), ConvertToReadableFormat(testLspServer.ClientCapabilities, results.Data)); } } diff --git a/src/LanguageServer/ProtocolUnitTests/SpellCheck/SpellCheckTests.cs b/src/LanguageServer/ProtocolUnitTests/SpellCheck/SpellCheckTests.cs index f9eaf873a3a5f..aad9886aeadb5 100644 --- a/src/LanguageServer/ProtocolUnitTests/SpellCheck/SpellCheckTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/SpellCheck/SpellCheckTests.cs @@ -9,6 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Microsoft.CodeAnalysis.LanguageServer.UnitTests.Diagnostics; using Microsoft.CodeAnalysis.Text; using Roslyn.LanguageServer.Protocol; using Roslyn.Test.Utilities; @@ -48,9 +49,7 @@ public async Task TestDocumentResultsForOpenFiles(bool mutatingLspWorkspace) }"; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); - // Calling GetTextBuffer will effectively open the file. var testDocument = testLspServer.TestWorkspace.Documents.Single(); - testDocument.GetTextBuffer(); var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); @@ -81,7 +80,6 @@ class {|Identifier:A{{v}}|} """)); await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); - // Calling GetTextBuffer will effectively open the file. var testDocument = testLspServer.TestWorkspace.Documents.Single(); var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); @@ -114,9 +112,6 @@ public async Task TestDocumentResultsForRemovedDocument(bool mutatingLspWorkspac await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); var workspace = testLspServer.TestWorkspace; - // Calling GetTextBuffer will effectively open the file. - workspace.Documents.Single().GetTextBuffer(); - var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); // Get the diagnostics for the solution containing the doc. @@ -153,9 +148,6 @@ public async Task TestNoChangeIfDocumentResultsCalledTwice(bool mutatingLspWorks }"; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); - // Calling GetTextBuffer will effectively open the file. - testLspServer.TestWorkspace.Documents.Single().GetTextBuffer(); - var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); await OpenDocumentAsync(testLspServer, document); @@ -189,9 +181,6 @@ public async Task TestDocumentResultChangedAfterEntityAdded(bool mutatingLspWork "; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); - // Calling GetTextBuffer will effectively open the file. - var buffer = testLspServer.TestWorkspace.Documents.Single().GetTextBuffer(); - var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); await OpenDocumentAsync(testLspServer, document); @@ -206,7 +195,7 @@ public async Task TestDocumentResultChangedAfterEntityAdded(bool mutatingLspWork Ranges = GetRanges(testLspServer.TestWorkspace.Documents.Single().AnnotatedSpans), }); - await InsertTextAsync(testLspServer, document, buffer.CurrentSnapshot.Length, "// comment"); + await InsertTextAsync(testLspServer, document, sourceText.Length, "// comment"); var (_, lspSolution) = await testLspServer.GetManager().GetLspSolutionInfoAsync(CancellationToken.None).ConfigureAwait(false); document = lspSolution!.Projects.Single().Documents.Single(); @@ -237,9 +226,6 @@ public async Task TestDocumentResultIdSameAfterIrrelevantEdit(bool mutatingLspWo }"; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); - // Calling GetTextBuffer will effectively open the file. - var buffer = testLspServer.TestWorkspace.Documents.Single().GetTextBuffer(); - var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); await OpenDocumentAsync(testLspServer, document); @@ -277,9 +263,6 @@ class {|Identifier:A|} }"; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); - // Calling GetTextBuffer will effectively open the file. - testLspServer.TestWorkspace.Documents.Single().GetTextBuffer(); - var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); await OpenDocumentAsync(testLspServer, document); @@ -304,9 +287,6 @@ public async Task TestStreamingDocumentDiagnostics(bool mutatingLspWorkspace) }"; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); - // Calling GetTextBuffer will effectively open the file. - testLspServer.TestWorkspace.Documents.Single().GetTextBuffer(); - var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); await OpenDocumentAsync(testLspServer, document); @@ -497,8 +477,7 @@ public async Task TestWorkspaceResultUpdatedAfterEdit(bool mutatingLspWorkspace) }); AssertEx.Empty(results[1].Ranges); - var buffer = testLspServer.TestWorkspace.Documents.First().GetTextBuffer(); - buffer.Insert(buffer.CurrentSnapshot.Length, "// comment"); + await PullDiagnosticTests.InsertInClosedDocumentAsync(testLspServer, document.Id, "// comment"); var results2 = await RunGetWorkspaceSpellCheckSpansAsync(testLspServer, previousResults: CreateParamsFromPreviousReports(results)); diff --git a/src/LanguageServer/ProtocolUnitTests/Symbols/WorkspaceSymbolsTests.cs b/src/LanguageServer/ProtocolUnitTests/Symbols/WorkspaceSymbolsTests.cs index 3a90b5d341ab6..213721f2f4ea1 100644 --- a/src/LanguageServer/ProtocolUnitTests/Symbols/WorkspaceSymbolsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Symbols/WorkspaceSymbolsTests.cs @@ -21,7 +21,7 @@ public class WorkspaceSymbolsTests(ITestOutputHelper testOutputHelper) : AbstractLanguageServerProtocolTests(testOutputHelper) { private static void AssertSetEquals(LSP.SymbolInformation[] expected, LSP.SymbolInformation[]? results) - => Assert.True(expected.ToHashSet().SetEquals(results)); + => Assert.True(expected.ToHashSet().SetEquals(results!)); private Task CreateTestLspServerAsync(string markup, bool mutatingLspWorkspace) => CreateTestLspServerAsync(markup, mutatingLspWorkspace, composition: Composition.AddParts(typeof(TestWorkspaceNavigateToSearchHostService))); diff --git a/src/LanguageServer/ProtocolUnitTests/TestConfigurableDocumentHandler.cs b/src/LanguageServer/ProtocolUnitTests/TestConfigurableDocumentHandler.cs index 30c853f44cc77..71e235bb5b8e3 100644 --- a/src/LanguageServer/ProtocolUnitTests/TestConfigurableDocumentHandler.cs +++ b/src/LanguageServer/ProtocolUnitTests/TestConfigurableDocumentHandler.cs @@ -11,7 +11,6 @@ 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; diff --git a/src/LanguageServer/ProtocolUnitTests/Workspaces/LspWorkspaceManagerTests.cs b/src/LanguageServer/ProtocolUnitTests/Workspaces/LspWorkspaceManagerTests.cs index 5866d332036e1..3c3c0c0ef7c6f 100644 --- a/src/LanguageServer/ProtocolUnitTests/Workspaces/LspWorkspaceManagerTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Workspaces/LspWorkspaceManagerTests.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; -using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; using Roslyn.Test.Utilities.TestGenerators; @@ -298,7 +297,7 @@ public async Task TestUsesRegisteredHostWorkspace(bool mutatingLspWorkspace) // Verify 1 workspace registered to start with. Assert.True(IsWorkspaceRegistered(testLspServer.TestWorkspace, testLspServer)); - using var testWorkspaceTwo = EditorTestWorkspace.Create( + using var testWorkspaceTwo = LspTestWorkspace.Create( XElement.Parse(secondWorkspaceXml), workspaceKind: "OtherWorkspaceKind", composition: testLspServer.TestWorkspace.Composition); @@ -512,14 +511,15 @@ public async Task TestSeparateWorkspaceManagerPerServerAsync(bool mutatingLspWor } [Theory, CombinatorialData] - public async Task TestDoesNotForkWhenDocumentTextBufferOpenedAsync(bool mutatingLspWorkspace) + public async Task TestDoesNotForkWhenDocumentOpenedInWorkspaceAsync(bool mutatingLspWorkspace) { var markup = "Text"; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); + var document = testLspServer.GetCurrentSolution().Projects.First().Documents.First(); var documentUri = testLspServer.GetCurrentSolution().Projects.First().Documents.First().GetURI(); - // Calling get text buffer opens the document in the workspace. - testLspServer.TestWorkspace.Documents.Single().GetTextBuffer(); + // Open document in the workspace. + await testLspServer.OpenDocumentInWorkspaceAsync(document.Id, openAllLinkedDocuments: false); await testLspServer.OpenDocumentAsync(documentUri, "Text"); diff --git a/src/LanguageServer/ProtocolUnitTests/Workspaces/SourceGeneratedDocumentTests.cs b/src/LanguageServer/ProtocolUnitTests/Workspaces/SourceGeneratedDocumentTests.cs index 1d6ae9f07598d..e62dca52af502 100644 --- a/src/LanguageServer/ProtocolUnitTests/Workspaces/SourceGeneratedDocumentTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Workspaces/SourceGeneratedDocumentTests.cs @@ -8,8 +8,6 @@ using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.LanguageServer.Handler; using Microsoft.CodeAnalysis.LanguageServer.Handler.SourceGenerators; -using Microsoft.CodeAnalysis.Shared.TestHooks; -using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; using Roslyn.Test.Utilities.TestGenerators; @@ -171,7 +169,7 @@ internal async Task TestReturnsGeneratedSourceWhenDocumentChanges(bool mutatingL // In automatic mode this should trigger generators to re-run. // In balanced mode generators should not re-run. await testLspServer.TestWorkspace.ChangeDocumentAsync(testLspServer.TestWorkspace.Documents.Single(d => !d.IsSourceGenerated).Id, SourceText.From("new text")); - await WaitForSourceGeneratorsAsync(testLspServer.TestWorkspace); + await testLspServer.WaitForSourceGeneratorsAsync(); // Ask for the source generated text again. var secondRequest = await testLspServer.ExecuteRequestAsync(SourceGeneratedDocumentGetTextHandler.MethodName, @@ -216,7 +214,7 @@ internal async Task TestReturnsGeneratedSourceWhenManuallyRefreshed(bool mutatin // Updating the execution version should trigger source generators to run in both automatic and balanced mode. testLspServer.TestWorkspace.EnqueueUpdateSourceGeneratorVersion(projectId: null, forceRegeneration: true); - await WaitForSourceGeneratorsAsync(testLspServer.TestWorkspace); + await testLspServer.WaitForSourceGeneratorsAsync(); var secondRequest = await testLspServer.ExecuteRequestAsync(SourceGeneratedDocumentGetTextHandler.MethodName, new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { Uri = sourceGeneratorDocumentUri }, ResultId: text.ResultId), CancellationToken.None); @@ -281,12 +279,6 @@ public async Task TestReturnsNullForRemovedOpenedGeneratedFile(bool mutatingLspW Assert.Null(secondRequest.Text); } - private static async Task WaitForSourceGeneratorsAsync(EditorTestWorkspace workspace) - { - var operations = workspace.ExportProvider.GetExportedValue(); - await operations.WaitAllAsync(workspace, [FeatureAttribute.Workspace, FeatureAttribute.SourceGenerators]); - } - private async Task CreateTestLspServerWithGeneratorAsync(bool mutatingLspWorkspace, string generatedDocumentText) { var testLspServer = await CreateTestLspServerAsync(string.Empty, mutatingLspWorkspace); diff --git a/src/NuGet/VS.ExternalAPIs.Roslyn.Package/VS.ExternalAPIs.Roslyn.Package.csproj b/src/NuGet/VS.ExternalAPIs.Roslyn.Package/VS.ExternalAPIs.Roslyn.Package.csproj index 92a958498c6cb..ad6db8f1feb82 100644 --- a/src/NuGet/VS.ExternalAPIs.Roslyn.Package/VS.ExternalAPIs.Roslyn.Package.csproj +++ b/src/NuGet/VS.ExternalAPIs.Roslyn.Package/VS.ExternalAPIs.Roslyn.Package.csproj @@ -39,12 +39,12 @@ - + - + diff --git a/src/Scripting/CSharpTest/ScriptTests.cs b/src/Scripting/CSharpTest/ScriptTests.cs index f78d4d5b7a29e..a04c40871cabc 100644 --- a/src/Scripting/CSharpTest/ScriptTests.cs +++ b/src/Scripting/CSharpTest/ScriptTests.cs @@ -1067,6 +1067,38 @@ public async Task SwitchPatternWithVar_WhenInvalidArm_ShouldReturnTheNameNotInCo Assert.True(exceptionThrown); } + [Fact] + public void Function_ReturningPartialType() + { + var script = CSharpScript.Create("class partial;", ScriptOptions.WithLanguageVersion(LanguageVersion.Preview)) + .ContinueWith("partial M() => new();"); + script.GetCompilation().VerifyDiagnostics( + // (1,9): error CS1520: Method must have a return type + // partial M() => new(); + Diagnostic(ErrorCode.ERR_MemberNeedsType, "M").WithLocation(1, 9), + // (1,9): error CS0759: No defining declaration found for implementing declaration of partial method 'M()' + // partial M() => new(); + Diagnostic(ErrorCode.ERR_PartialMethodMustHaveLatent, "M").WithArguments("M()").WithLocation(1, 9), + // (1,9): error CS0751: A partial member must be declared within a partial type + // partial M() => new(); + Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "M").WithLocation(1, 9), + // (1,16): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement + // partial M() => new(); + Diagnostic(ErrorCode.ERR_IllegalStatement, "new()").WithLocation(1, 16)); + } + + [Fact] + public async Task Function_ReturningPartialType_CSharp13() + { + var script = CSharpScript.Create("class partial;", ScriptOptions.WithLanguageVersion(LanguageVersion.CSharp13)) + .ContinueWith("partial M() => new();") + .ContinueWith("M()"); + script.GetCompilation().VerifyDiagnostics(); + + var result = await script.EvaluateAsync(); + Assert.Equal("partial", result.GetType().Name); + } + private class StreamOffsetResolver : SourceReferenceResolver { public override bool Equals(object other) => ReferenceEquals(this, other); diff --git a/src/Scripting/Core/Hosting/AssemblyLoader/MetadataShadowCopyProvider.cs b/src/Scripting/Core/Hosting/AssemblyLoader/MetadataShadowCopyProvider.cs index 4dbf0433b998d..77efeffc1033b 100644 --- a/src/Scripting/Core/Hosting/AssemblyLoader/MetadataShadowCopyProvider.cs +++ b/src/Scripting/Core/Hosting/AssemblyLoader/MetadataShadowCopyProvider.cs @@ -617,7 +617,7 @@ private static FileStream CopyFile(string originalPath, string shadowCopyPath, b StripReadOnlyAttributeFromFile(new FileInfo(shadowCopyPath)); return new FileStream(shadowCopyPath, FileMode.Open, FileAccess.Read, FileShare.Read); } - catch (Exception e) when (fileMayNotExist && (e is FileNotFoundException || e is DirectoryNotFoundException)) + catch (Exception e) when (fileMayNotExist && e is FileNotFoundException or DirectoryNotFoundException) { return null; } diff --git a/src/Setup/DevDivInsertionFiles/DevDivInsertionFiles.csproj b/src/Setup/DevDivInsertionFiles/DevDivInsertionFiles.csproj index a3fa69f565bc3..98dd67e1545b3 100644 --- a/src/Setup/DevDivInsertionFiles/DevDivInsertionFiles.csproj +++ b/src/Setup/DevDivInsertionFiles/DevDivInsertionFiles.csproj @@ -109,6 +109,7 @@ <_Dependency Remove="MessagePack"/> <_Dependency Remove="MessagePack.Annotations"/> <_Dependency Remove="Microsoft.Bcl.AsyncInterfaces"/> + <_Dependency Remove="Microsoft.Bcl.HashCode" /> <_Dependency Remove="Microsoft.Build"/> <_Dependency Remove="Microsoft.Build.Framework"/> <_Dependency Remove="Microsoft.Build.Tasks.Core"/> @@ -132,6 +133,7 @@ <_Dependency Remove="System.Configuration.ConfigurationManager"/> <_Dependency Remove="System.Diagnostics.DiagnosticSource"/> <_Dependency Remove="System.Drawing.Common"/> + <_Dependency Remove="System.Formats.Nrbf" /> <_Dependency Remove="System.IO.Packaging"/> <_Dependency Remove="System.IO.Pipelines"/> <_Dependency Remove="System.Memory"/> diff --git a/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.GenerationVerifier.cs b/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.GenerationVerifier.cs index 4814d40299b30..17cf4dbc1d53b 100644 --- a/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.GenerationVerifier.cs +++ b/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.GenerationVerifier.cs @@ -11,7 +11,6 @@ using System.Reflection.Metadata.Ecma335; using Microsoft.CodeAnalysis.Symbols; using Microsoft.CodeAnalysis.Test.Utilities; -using Roslyn.Utilities; using Roslyn.Test.Utilities; namespace Microsoft.CodeAnalysis.EditAndContinue.UnitTests diff --git a/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTestUtilities.cs b/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTestUtilities.cs index a1df0ee1beab5..3328f7876dc92 100644 --- a/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTestUtilities.cs +++ b/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTestUtilities.cs @@ -24,7 +24,7 @@ public static EmitBaseline CreateInitialBaseline(Compilation compilation, Module { return module.Module.GetMethodBodyOrThrow(methodHandle)?.LocalSignature ?? default; } - catch (Exception e) when (e is BadImageFormatException || e is IOException) + catch (Exception e) when (e is BadImageFormatException or IOException) { throw new InvalidDataException(e.Message, e); } diff --git a/src/Test/PdbUtilities/Reader/MockSymUnmanagedReader.cs b/src/Test/PdbUtilities/Reader/MockSymUnmanagedReader.cs index b158a7f9a477d..dfc3608111351 100644 --- a/src/Test/PdbUtilities/Reader/MockSymUnmanagedReader.cs +++ b/src/Test/PdbUtilities/Reader/MockSymUnmanagedReader.cs @@ -11,7 +11,7 @@ using System.Runtime.InteropServices.ComTypes; using DSR::Microsoft.DiaSymReader; using Microsoft.CodeAnalysis.PooledObjects; -using Roslyn.Utilities; +using Microsoft.CodeAnalysis; using Xunit; namespace Roslyn.Test.Utilities diff --git a/src/Test/PdbUtilities/Reader/SymReaderFactory.cs b/src/Test/PdbUtilities/Reader/SymReaderFactory.cs index d15171d69a9cd..f6523b0a5b211 100644 --- a/src/Test/PdbUtilities/Reader/SymReaderFactory.cs +++ b/src/Test/PdbUtilities/Reader/SymReaderFactory.cs @@ -9,7 +9,6 @@ using System; using System.Collections.Immutable; using System.IO; -using System.Linq; using System.Reflection.Metadata; using System.Reflection.PortableExecutable; using System.Runtime.InteropServices; diff --git a/src/Tools/BuildActionTelemetryTable/BuildActionTelemetryTable.csproj b/src/Tools/BuildActionTelemetryTable/BuildActionTelemetryTable.csproj index 783809b4edae9..45f578b7966f7 100644 --- a/src/Tools/BuildActionTelemetryTable/BuildActionTelemetryTable.csproj +++ b/src/Tools/BuildActionTelemetryTable/BuildActionTelemetryTable.csproj @@ -2,7 +2,7 @@ Exe - $(NetVS)-windows + $(NetRoslyn) false @@ -19,16 +19,17 @@ + + + + - - - - - + + diff --git a/src/Tools/BuildActionTelemetryTable/CodeActionDescriptions.cs b/src/Tools/BuildActionTelemetryTable/CodeActionDescriptions.cs new file mode 100644 index 0000000000000..e6c1c69979a34 --- /dev/null +++ b/src/Tools/BuildActionTelemetryTable/CodeActionDescriptions.cs @@ -0,0 +1,432 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using System.Collections.Generic; + +namespace BuildActionTelemetryTable; + +internal static class CodeActionDescriptions +{ + public static ImmutableDictionary CodeActionDescriptionMap { get; } = new Dictionary() + { + { "Microsoft.CodeAnalysis.AddConstructorParametersFromMembers.AddConstructorParametersFromMembersCodeRefactoringProvider", "Add Constructor Parameters From Members (Refactoring)" }, + { "Microsoft.CodeAnalysis.AddConstructorParametersFromMembers.AddConstructorParametersFromMembersCodeRefactoringProvider+AddConstructorParametersCodeAction", "Add Constructor Parameters From Members: Add Constructor Parameters (Refactoring)" }, + { "Microsoft.CodeAnalysis.AddImport.AbstractAddImportFeatureService`1+AssemblyReferenceCodeAction", "Add Import: Assembly Reference" }, + { "Microsoft.CodeAnalysis.AddImport.AbstractAddImportFeatureService`1+InstallWithPackageManagerCodeAction", "Add Import: Install With Package Manager" }, + { "Microsoft.CodeAnalysis.AddImport.AbstractAddImportFeatureService`1+MetadataSymbolReferenceCodeAction", "Add Import: Metadata Symbol Reference" }, + { "Microsoft.CodeAnalysis.AddImport.AbstractAddImportFeatureService`1+ProjectSymbolReferenceCodeAction", "Add Import: Project Symbol Reference" }, + { "Microsoft.CodeAnalysis.AddImport.InstallPackageAndAddImportCodeAction", "Add Import: Install Package And Add Import" }, + { "Microsoft.CodeAnalysis.AddMissingReference.AddMissingReferenceCodeAction", "Add Missing Reference" }, + { "Microsoft.CodeAnalysis.AddPackage.InstallPackageDirectlyCodeAction", "Add Package: Install Package Directly" }, + { "Microsoft.CodeAnalysis.AddPackage.InstallPackageParentCodeAction", "Add Package: Install Package Parent" }, + { "Microsoft.CodeAnalysis.AddPackage.InstallWithPackageManagerCodeAction", "Add Package: Install With Package Manager" }, + { "Microsoft.CodeAnalysis.AddPackage.ParentInstallPackageCodeAction", "Add Package: Parent Install Package" }, + { "Microsoft.CodeAnalysis.AddRequiredParentheses.AddRequiredParenthesesCodeFixProvider", "Add Required Parentheses" }, + { "Microsoft.CodeAnalysis.ChangeSignature.ChangeSignatureCodeAction", "Change Signature" }, + { "Microsoft.CodeAnalysis.ChangeSignature.ChangeSignatureCodeRefactoringProvider", "Change Signature (Refactoring)" }, + { "Microsoft.CodeAnalysis.CodeFixes.Configuration.ConfigureCodeStyle.ConfigureCodeStyleOptionCodeFixProvider+TopLevelConfigureCodeStyleOptionCodeAction", "Configure Code Style Option: Top Level Configure Code Style Option" }, + { "Microsoft.CodeAnalysis.CodeFixes.Configuration.ConfigureSeverity.ConfigureSeverityLevelCodeFixProvider+TopLevelBulkConfigureSeverityCodeAction", "Configure Severity Level: Top Level Bulk Configure Severity" }, + { "Microsoft.CodeAnalysis.CodeFixes.Configuration.ConfigureSeverity.ConfigureSeverityLevelCodeFixProvider+TopLevelConfigureSeverityCodeAction", "Configure Severity Level: Top Level Configure Severity" }, + { "Microsoft.CodeAnalysis.CodeFixes.FixMultipleCodeAction", "Fix Multiple" }, + { "Microsoft.CodeAnalysis.CodeFixes.NamingStyles.NamingStyleCodeFixProvider", "Naming Styles: Naming Style" }, + { "Microsoft.CodeAnalysis.CodeFixes.NamingStyles.NamingStyleCodeFixProvider+FixNameCodeAction", "Naming Style: Fix Name" }, + { "Microsoft.CodeAnalysis.CodeFixes.Suppression.AbstractSuppressionCodeFixProvider+GlobalSuppressMessageCodeAction", "Suppression: Global Suppress Message" }, + { "Microsoft.CodeAnalysis.CodeFixes.Suppression.AbstractSuppressionCodeFixProvider+GlobalSuppressMessageFixAllCodeAction", "Suppression: Global Suppress Message Fix All" }, + { "Microsoft.CodeAnalysis.CodeFixes.Suppression.AbstractSuppressionCodeFixProvider+GlobalSuppressMessageFixAllCodeAction+GlobalSuppressionSolutionChangeAction", "Global Suppress Message Fix All: Global Suppression Solution Change" }, + { "Microsoft.CodeAnalysis.CodeFixes.Suppression.AbstractSuppressionCodeFixProvider+LocalSuppressMessageCodeAction", "Suppression: Local Suppress Message" }, + { "Microsoft.CodeAnalysis.CodeFixes.Suppression.AbstractSuppressionCodeFixProvider+PragmaWarningCodeAction", "Suppression: Pragma Warning" }, + { "Microsoft.CodeAnalysis.CodeFixes.Suppression.AbstractSuppressionCodeFixProvider+RemoveSuppressionCodeAction+AttributeRemoveAction", "Remove Suppression: Attribute Remove" }, + { "Microsoft.CodeAnalysis.CodeFixes.Suppression.AbstractSuppressionCodeFixProvider+RemoveSuppressionCodeAction+PragmaRemoveAction", "Remove Suppression: Pragma Remove" }, + { "Microsoft.CodeAnalysis.CodeFixes.Suppression.TopLevelSuppressionCodeAction", "Suppression: Top Level Suppression" }, + { "Microsoft.CodeAnalysis.CodeFixes.Suppression.WrapperCodeFixProvider", "Suppression: Wrapper" }, + { "Microsoft.CodeAnalysis.CodeRefactorings.ExtractMethod.ExtractMethodCodeRefactoringProvider", "Extract Method (Refactoring)" }, + { "Microsoft.CodeAnalysis.CodeRefactorings.FixAllCodeRefactoringCodeAction", "Code Refactorings: Fix All Code Refactoring" }, + { "Microsoft.CodeAnalysis.CodeRefactorings.MoveType.AbstractMoveTypeService`4+MoveTypeCodeAction", "Move Type" }, + { "Microsoft.CodeAnalysis.CodeRefactorings.MoveType.MoveTypeCodeRefactoringProvider", "Move Type (Refactoring)" }, + { "Microsoft.CodeAnalysis.CodeRefactorings.PullMemberUp.AbstractPullMemberUpRefactoringProvider+PullMemberUpWithDialogCodeAction", "Pull Member Up: With Dialog (Refactoring)" }, + { "Microsoft.CodeAnalysis.CodeRefactorings.SyncNamespace.AbstractSyncNamespaceCodeRefactoringProvider`3+MoveFileCodeAction", "Sync Namespace: Move File (Refactoring)" }, + { "Microsoft.CodeAnalysis.CodeStyle.CSharpFormattingCodeFixProvider", "Formatting" }, + { "Microsoft.CodeAnalysis.CodeStyle.VisualBasicFormattingCodeFixProvider", "Formatting" }, + { "Microsoft.CodeAnalysis.ConvertToInterpolatedString.ConvertRegularStringToInterpolatedStringRefactoringProvider", "Convert To Interpolated String: Convert Regular String To Interpolated String (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.AddAnonymousTypeMemberName.CSharpAddAnonymousTypeMemberNameCodeFixProvider", "Add Anonymous Type Member Name" }, + { "Microsoft.CodeAnalysis.CSharp.AddDebuggerDisplay.CSharpAddDebuggerDisplayCodeRefactoringProvider", "Add Debugger Display (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.AddFileBanner.CSharpAddFileBannerCodeRefactoringProvider", "Add File Banner (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.AddImport.CSharpAddImportCodeFixProvider", "Add Import" }, + { "Microsoft.CodeAnalysis.CSharp.AddMissingReference.CSharpAddMissingReferenceCodeFixProvider", "Add Missing Reference" }, + { "Microsoft.CodeAnalysis.CSharp.AddObsoleteAttribute.CSharpAddObsoleteAttributeCodeFixProvider", "Add Obsolete Attribute" }, + { "Microsoft.CodeAnalysis.CSharp.AddOrRemoveAccessibilityModifiers.CSharpAddOrRemoveAccessibilityModifiersCodeFixProvider", "Add Accessibility Modifiers" }, + { "Microsoft.CodeAnalysis.CSharp.AddPackage.CSharpAddSpecificPackageCodeFixProvider", "Add Package: Add Specific Package" }, + { "Microsoft.CodeAnalysis.CSharp.AddParameter.CSharpAddParameterCodeFixProvider", "Add Parameter" }, + { "Microsoft.CodeAnalysis.CSharp.AliasAmbiguousType.CSharpAliasAmbiguousTypeCodeFixProvider", "Alias Ambiguous Type" }, + { "Microsoft.CodeAnalysis.CSharp.AssignOutParameters.AssignOutParametersAboveReturnCodeFixProvider", "Assign Out Parameters: Above Return" }, + { "Microsoft.CodeAnalysis.CSharp.AssignOutParameters.AssignOutParametersAtStartCodeFixProvider", "Assign Out Parameters: At Start" }, + { "Microsoft.CodeAnalysis.CSharp.CodeFixes.AddExplicitCast.CSharpAddExplicitCastCodeFixProvider", "Add Explicit Cast" }, + { "Microsoft.CodeAnalysis.CSharp.CodeFixes.AddInheritdoc.AddInheritdocCodeFixProvider", "Add Inheritdoc" }, + { "Microsoft.CodeAnalysis.CSharp.CodeFixes.ConvertToAsync.CSharpConvertToAsyncMethodCodeFixProvider", "Convert To Async: Method" }, + { "Microsoft.CodeAnalysis.CSharp.CodeFixes.DeclareAsNullable.CSharpDeclareAsNullableCodeFixProvider", "Declare As Nullable" }, + { "Microsoft.CodeAnalysis.CSharp.CodeFixes.FixIncorrectConstraint.CSharpFixIncorrectConstraintCodeFixProvider", "Fix Incorrect Constraint" }, + { "Microsoft.CodeAnalysis.CSharp.CodeFixes.FixReturnType.CSharpFixReturnTypeCodeFixProvider", "Fix Return Type" }, + { "Microsoft.CodeAnalysis.CSharp.CodeFixes.ForEachCast.CSharpForEachCastCodeFixProvider", "For Each Cast" }, + { "Microsoft.CodeAnalysis.CSharp.CodeFixes.FullyQualify.CSharpFullyQualifyCodeFixProvider", "Fully Qualify" }, + { "Microsoft.CodeAnalysis.CSharp.CodeFixes.GenerateDeconstructMethod.GenerateDeconstructMethodCodeFixProvider", "Generate Deconstruct Method" }, + { "Microsoft.CodeAnalysis.CSharp.CodeFixes.GenerateEnumMember.GenerateEnumMemberCodeFixProvider", "Generate Enum Member" }, + { "Microsoft.CodeAnalysis.CSharp.CodeFixes.GenerateMethod.GenerateConversionCodeFixProvider", "Generate Method: Generate Conversion" }, + { "Microsoft.CodeAnalysis.CSharp.CodeFixes.GenerateMethod.GenerateMethodCodeFixProvider", "Generate Method" }, + { "Microsoft.CodeAnalysis.CSharp.CodeFixes.GenerateType.GenerateTypeCodeFixProvider", "Generate Type" }, + { "Microsoft.CodeAnalysis.CSharp.CodeFixes.HideBase.HideBaseCodeFixProvider", "Hide Base" }, + { "Microsoft.CodeAnalysis.CSharp.CodeFixes.HideBase.HideBaseCodeFixProvider+AddNewKeywordAction", "Hide Base: Add New Keyword" }, + { "Microsoft.CodeAnalysis.CSharp.CodeFixes.Iterator.CSharpAddYieldCodeFixProvider", "Iterator: Add Yield" }, + { "Microsoft.CodeAnalysis.CSharp.CodeFixes.Iterator.CSharpChangeToIEnumerableCodeFixProvider", "Iterator: Change To IEnumerable" }, + { "Microsoft.CodeAnalysis.CSharp.CodeFixes.MakeMemberRequired.CSharpMakeMemberRequiredCodeFixProvider", "Make Member Required" }, + { "Microsoft.CodeAnalysis.CSharp.CodeFixes.MakeStatementAsynchronous.CSharpMakeStatementAsynchronousCodeFixProvider", "Make Statement Asynchronous" }, + { "Microsoft.CodeAnalysis.CSharp.CodeFixes.MatchFolderAndNamespace.CSharpChangeNamespaceToMatchFolderCodeFixProvider", "Match Folder And Namespace: Change Namespace To Match Folder" }, + { "Microsoft.CodeAnalysis.CSharp.CodeFixes.RemoveNewModifier.RemoveNewModifierCodeFixProvider", "Remove New Modifier" }, + { "Microsoft.CodeAnalysis.CSharp.CodeFixes.RemoveUnnecessaryNullableDirective.CSharpRemoveUnnecessaryNullableDirectiveCodeFixProvider", "Remove Unnecessary Nullable Directive" }, + { "Microsoft.CodeAnalysis.CSharp.CodeFixes.TransposeRecordKeyword.CSharpTransposeRecordKeywordCodeFixProvider", "Transpose Record Keyword" }, + { "Microsoft.CodeAnalysis.CSharp.CodeFixes.UseNameofInAttribute.CSharpUseNameofInAttributeCodeFixProvider", "Use Nameof In Attribute" }, + { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.AddAwait.CSharpAddAwaitCodeRefactoringProvider", "Add Await (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.AddMissingImports.CSharpAddMissingImportsRefactoringProvider", "Add Missing Imports (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.ConvertLocalFunctionToMethod.CSharpConvertLocalFunctionToMethodCodeRefactoringProvider", "Convert Local Function To Method (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.EnableNullable.EnableNullableCodeRefactoringProvider", "Enable Nullable (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.EnableNullable.EnableNullableCodeRefactoringProvider+CustomCodeAction", "Enable Nullable (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.EnableNullable.EnableNullableCodeRefactoringProvider+FixAllProvider+FixAllCodeAction", "Enable Nullable Fix All (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.ExtractClass.CSharpExtractClassCodeRefactoringProvider", "Extract Class (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.InlineMethod.CSharpInlineMethodRefactoringProvider", "Inline Method (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.InlineTemporary.CSharpInlineTemporaryCodeRefactoringProvider", "Inline Temporary (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.MoveStaticMembers.CSharpMoveStaticMembersRefactoringProvider", "Move Static Members (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.PullMemberUp.CSharpPullMemberUpCodeRefactoringProvider", "Pull Member Up (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.SyncNamespace.CSharpSyncNamespaceCodeRefactoringProvider", "Sync Namespace (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.UseExplicitType.UseExplicitTypeCodeRefactoringProvider", "Use Explicit Type (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.UseImplicitType.UseImplicitTypeCodeRefactoringProvider", "Use Implicit Type (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.UseRecursivePatterns.UseRecursivePatternsCodeRefactoringProvider", "Use Recursive Patterns (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.ConditionalExpressionInStringInterpolation.CSharpAddParenthesesAroundConditionalExpressionInInterpolatedStringCodeFixProvider", "Add Parentheses Around Conditional Expression In Interpolated String" }, + { "Microsoft.CodeAnalysis.CSharp.ConflictMarkerResolution.CSharpResolveConflictMarkerCodeFixProvider", "Conflict Marker Resolution: Resolve Conflict Marker" }, + { "Microsoft.CodeAnalysis.CSharp.ConvertAnonymousType.CSharpConvertAnonymousTypeToClassCodeRefactoringProvider", "Convert Anonymous Type: To Class (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.ConvertAnonymousType.CSharpConvertAnonymousTypeToTupleCodeRefactoringProvider", "Convert Anonymous Type: To Tuple (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.ConvertAutoPropertyToFullProperty.CSharpConvertAutoPropertyToFullPropertyCodeRefactoringProvider", "Convert Auto Property To Full Property (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.ConvertBetweenRegularAndVerbatimString.ConvertBetweenRegularAndVerbatimInterpolatedStringCodeRefactoringProvider", "Convert Between Regular And Verbatim String: Convert Between Regular And Verbatim Interpolated String (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.ConvertBetweenRegularAndVerbatimString.ConvertBetweenRegularAndVerbatimStringCodeRefactoringProvider", "Convert Between Regular And Verbatim String (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.ConvertCast.CSharpConvertDirectCastToTryCastCodeRefactoringProvider", "Convert Cast: Convert Direct Cast To Try Cast (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.ConvertCast.CSharpConvertTryCastToDirectCastCodeRefactoringProvider", "Convert Cast: Convert Try Cast To Direct Cast (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.ConvertForEachToFor.CSharpConvertForEachToForCodeRefactoringProvider", "Convert For Each To For (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.ConvertForToForEach.CSharpConvertForToForEachCodeRefactoringProvider", "Convert For To For Each (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.ConvertIfToSwitch.CSharpConvertIfToSwitchCodeRefactoringProvider", "Convert If To Switch (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.ConvertLinq.ConvertForEachToLinqQuery.CSharpConvertForEachToLinqQueryProvider", "Convert For Each To Linq Query" }, + { "Microsoft.CodeAnalysis.CSharp.ConvertLinq.CSharpConvertLinqQueryToForEachProvider", "Convert Linq: Query To For Each" }, + { "Microsoft.CodeAnalysis.CSharp.ConvertNamespace.ConvertNamespaceCodeFixProvider", "Convert Namespace" }, + { "Microsoft.CodeAnalysis.CSharp.ConvertNamespace.ConvertNamespaceCodeRefactoringProvider", "Convert Namespace (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.ConvertNumericLiteral.CSharpConvertNumericLiteralCodeRefactoringProvider", "Convert Numeric Literal (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.ConvertPrimaryToRegularConstructor.ConvertPrimaryToRegularConstructorCodeRefactoringProvider", "Convert Primary To Regular Constructor (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.ConvertProgram.ConvertToProgramMainCodeFixProvider", "Convert Program: Convert To Program Main" }, + { "Microsoft.CodeAnalysis.CSharp.ConvertProgram.ConvertToProgramMainCodeRefactoringProvider", "Convert Program: Convert To Program Main (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.ConvertProgram.ConvertToTopLevelStatementsCodeFixProvider", "Convert Program: Convert To Top Level Statements" }, + { "Microsoft.CodeAnalysis.CSharp.ConvertProgram.ConvertToTopLevelStatementsCodeRefactoringProvider", "Convert Program: Convert To Top Level Statements (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.ConvertSwitchStatementToExpression.ConvertSwitchStatementToExpressionCodeFixProvider", "Convert Switch Statement To Expression" }, + { "Microsoft.CodeAnalysis.CSharp.ConvertToInterpolatedString.CSharpConvertConcatenationToInterpolatedStringRefactoringProvider", "Convert To Interpolated String: Convert Concatenation To Interpolated String (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.ConvertToInterpolatedString.CSharpConvertPlaceholderToInterpolatedStringRefactoringProvider", "Convert To Interpolated String: Convert Placeholder To Interpolated String (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.ConvertToRawString.ConvertStringToRawStringCodeRefactoringProvider", "Convert String To Raw String (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.ConvertToRecord.CSharpConvertToRecordCodeFixProvider", "Convert To Record" }, + { "Microsoft.CodeAnalysis.CSharp.ConvertToRecord.CSharpConvertToRecordRefactoringProvider", "Convert To Record (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.ConvertTupleToStruct.CSharpConvertTupleToStructCodeRefactoringProvider", "Convert Tuple To Struct (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.ConvertTypeOfToNameOf.CSharpConvertTypeOfToNameOfCodeFixProvider", "Convert Type Of To Name Of" }, + { "Microsoft.CodeAnalysis.CSharp.Copilot.CSharpCopilotCodeFixProvider", "Copilot" }, + { "Microsoft.CodeAnalysis.CSharp.Copilot.CSharpCopilotCodeFixProvider+CopilotDismissChangesCodeAction", "Copilot: Dismiss Changes" }, + { "Microsoft.CodeAnalysis.CSharp.Copilot.CSharpCopilotCodeFixProvider+CopilotDocumentChangeCodeAction", "Copilot: Document Change" }, + { "Microsoft.CodeAnalysis.CSharp.Copilot.CSharpImplementNotImplementedExceptionFixProvider", "Implement with Copilot" }, + { "Microsoft.CodeAnalysis.CSharp.Diagnostics.AddBraces.CSharpAddBracesCodeFixProvider", "Add Braces" }, + { "Microsoft.CodeAnalysis.CSharp.DisambiguateSameVariable.CSharpDisambiguateSameVariableCodeFixProvider", "Disambiguate Same Variable" }, + { "Microsoft.CodeAnalysis.CSharp.DocumentationComments.CSharpAddDocCommentNodesCodeFixProvider", "Documentation Comments: Add DocComment Nodes" }, + { "Microsoft.CodeAnalysis.CSharp.DocumentationComments.CSharpRemoveDocCommentNodeCodeFixProvider", "Documentation Comments: Remove DocComment Node" }, + { "Microsoft.CodeAnalysis.CSharp.EmbeddedLanguages.CSharpJsonDetectionCodeFixProvider", "Embedded Languages: Json Detection" }, + { "Microsoft.CodeAnalysis.CSharp.FileHeaders.CSharpFileHeaderCodeFixProvider", "File Headers: File Header" }, + { "Microsoft.CodeAnalysis.CSharp.GenerateConstructor.GenerateConstructorCodeFixProvider", "Generate Constructor" }, + { "Microsoft.CodeAnalysis.CSharp.GenerateConstructors.CSharpGenerateConstructorsCodeRefactoringProvider", "Generate Constructors (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.GenerateDefaultConstructors.CSharpGenerateDefaultConstructorsCodeFixProvider", "Generate Default Constructors" }, + { "Microsoft.CodeAnalysis.CSharp.GenerateVariable.CSharpGenerateVariableCodeFixProvider", "Generate Variable" }, + { "Microsoft.CodeAnalysis.CSharp.ImplementAbstractClass.CSharpImplementAbstractClassCodeFixProvider", "Implement Abstract Class" }, + { "Microsoft.CodeAnalysis.CSharp.ImplementInterface.CSharpImplementExplicitlyCodeRefactoringProvider", "Implement Interface: Implement Explicitly (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.ImplementInterface.CSharpImplementImplicitlyCodeRefactoringProvider", "Implement Interface: Implement Implicitly (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.ImplementInterface.CSharpImplementInterfaceCodeFixProvider", "Implement Interface" }, + { "Microsoft.CodeAnalysis.CSharp.InitializeParameter.CSharpAddParameterCheckCodeRefactoringProvider", "Initialize Parameter: Add Parameter Check (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.InitializeParameter.CSharpInitializeMemberFromParameterCodeRefactoringProvider", "Initialize Parameter: Initialize Member From Parameter (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.InitializeParameter.CSharpInitializeMemberFromPrimaryConstructorParameterCodeRefactoringProvider", "Initialize Parameter: Initialize Member From Primary Constructor Parameter (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.InlineDeclaration.CSharpInlineDeclarationCodeFixProvider", "Inline Declaration" }, + { "Microsoft.CodeAnalysis.CSharp.IntroduceParameter.CSharpIntroduceParameterCodeRefactoringProvider", "Introduce Parameter (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.IntroduceUsingStatement.CSharpIntroduceUsingStatementCodeRefactoringProvider", "Introduce Using Statement (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.IntroduceVariable.CSharpIntroduceLocalForExpressionCodeRefactoringProvider", "Introduce Variable: Introduce Local For Expression (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.InvertConditional.CSharpInvertConditionalCodeRefactoringProvider", "Invert Conditional (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.InvertIf.CSharpInvertIfCodeRefactoringProvider", "Invert If (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.InvertLogical.CSharpInvertLogicalCodeRefactoringProvider", "Invert Logical (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.InvokeDelegateWithConditionalAccess.InvokeDelegateWithConditionalAccessCodeFixProvider", "Invoke Delegate With Conditional Access" }, + { "Microsoft.CodeAnalysis.CSharp.MakeAnonymousFunctionStatic.CSharpMakeAnonymousFunctionStaticCodeFixProvider", "Make Anonymous Function Static" }, + { "Microsoft.CodeAnalysis.CSharp.MakeFieldReadonly.CSharpMakeFieldReadonlyCodeFixProvider", "Make Field Readonly" }, + { "Microsoft.CodeAnalysis.CSharp.MakeLocalFunctionStatic.MakeLocalFunctionStaticCodeFixProvider", "Make Local Function Static" }, + { "Microsoft.CodeAnalysis.CSharp.MakeLocalFunctionStatic.MakeLocalFunctionStaticCodeRefactoringProvider", "Make Local Function Static (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.MakeLocalFunctionStatic.PassInCapturedVariablesAsArgumentsCodeFixProvider", "Make Local Function Static: Pass In Captured Variables As Arguments" }, + { "Microsoft.CodeAnalysis.CSharp.MakeMemberStatic.CSharpMakeMemberStaticCodeFixProvider", "Make Member Static" }, + { "Microsoft.CodeAnalysis.CSharp.MakeMethodAsynchronous.CSharpMakeMethodAsynchronousCodeFixProvider", "Make Method Asynchronous" }, + { "Microsoft.CodeAnalysis.CSharp.MakeMethodSynchronous.CSharpMakeMethodSynchronousCodeFixProvider", "Make Method Synchronous" }, + { "Microsoft.CodeAnalysis.CSharp.MakeRefStruct.MakeRefStructCodeFixProvider", "Make Ref Struct" }, + { "Microsoft.CodeAnalysis.CSharp.MakeStructFieldsWritable.CSharpMakeStructFieldsWritableCodeFixProvider", "Make Struct Fields Writable" }, + { "Microsoft.CodeAnalysis.CSharp.MakeStructMemberReadOnly.CSharpMakeStructMemberReadOnlyCodeFixProvider", "Make Struct Member Read Only" }, + { "Microsoft.CodeAnalysis.CSharp.MakeStructReadOnly.CSharpMakeStructReadOnlyCodeFixProvider", "Make Struct Read Only" }, + { "Microsoft.CodeAnalysis.CSharp.MakeTypeAbstract.CSharpMakeTypeAbstractCodeFixProvider", "Make Type Abstract" }, + { "Microsoft.CodeAnalysis.CSharp.MakeTypePartial.CSharpMakeTypePartialCodeFixProvider", "Make Type Partial" }, + { "Microsoft.CodeAnalysis.CSharp.MisplacedUsingDirectives.MisplacedUsingDirectivesCodeFixProvider", "Misplaced Using Directives" }, + { "Microsoft.CodeAnalysis.CSharp.MoveDeclarationNearReference.CSharpMoveDeclarationNearReferenceCodeRefactoringProvider", "Move Declaration Near Reference (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.NameTupleElement.CSharpNameTupleElementCodeRefactoringProvider", "Name Tuple Element (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.NewLines.ArrowExpressionClausePlacement.ArrowExpressionClausePlacementCodeFixProvider", "Arrow Expression Clause Placement" }, + { "Microsoft.CodeAnalysis.CSharp.NewLines.ConditionalExpressionPlacement.ConditionalExpressionPlacementCodeFixProvider", "Conditional Expression Placement" }, + { "Microsoft.CodeAnalysis.CSharp.NewLines.ConsecutiveBracePlacement.ConsecutiveBracePlacementCodeFixProvider", "Consecutive Brace Placement" }, + { "Microsoft.CodeAnalysis.CSharp.NewLines.ConstructorInitializerPlacement.ConstructorInitializerPlacementCodeFixProvider", "Constructor Initializer Placement" }, + { "Microsoft.CodeAnalysis.CSharp.NewLines.EmbeddedStatementPlacement.EmbeddedStatementPlacementCodeFixProvider", "Embedded Statement Placement" }, + { "Microsoft.CodeAnalysis.CSharp.OrderModifiers.CSharpOrderModifiersCodeFixProvider", "Order Modifiers" }, + { "Microsoft.CodeAnalysis.CSharp.PopulateSwitch.CSharpPopulateSwitchExpressionCodeFixProvider", "Populate Switch: Expression" }, + { "Microsoft.CodeAnalysis.CSharp.PopulateSwitch.CSharpPopulateSwitchStatementCodeFixProvider", "Populate Switch: Statement" }, + { "Microsoft.CodeAnalysis.CSharp.QualifyMemberAccess.CSharpQualifyMemberAccessCodeFixProvider", "Qualify Member Access" }, + { "Microsoft.CodeAnalysis.CSharp.RemoveAsyncModifier.CSharpRemoveAsyncModifierCodeFixProvider", "Remove Async Modifier" }, + { "Microsoft.CodeAnalysis.CSharp.RemoveConfusingSuppression.CSharpRemoveConfusingSuppressionCodeFixProvider", "Remove Confusing Suppression" }, + { "Microsoft.CodeAnalysis.CSharp.RemoveInKeyword.RemoveInKeywordCodeFixProvider", "Remove In Keyword" }, + { "Microsoft.CodeAnalysis.CSharp.RemoveUnnecessaryCast.CSharpRemoveUnnecessaryCastCodeFixProvider", "Remove Unnecessary Cast" }, + { "Microsoft.CodeAnalysis.CSharp.RemoveUnnecessaryDiscardDesignation.CSharpRemoveUnnecessaryDiscardDesignationCodeFixProvider", "Remove Unnecessary Discard Designation" }, + { "Microsoft.CodeAnalysis.CSharp.RemoveUnnecessaryImports.CSharpRemoveUnnecessaryImportsCodeFixProvider", "Remove unnecessary imports" }, + { "Microsoft.CodeAnalysis.CSharp.RemoveUnnecessaryLambdaExpression.CSharpRemoveUnnecessaryLambdaExpressionCodeFixProvider", "Remove Unnecessary Lambda Expression" }, + { "Microsoft.CodeAnalysis.CSharp.RemoveUnnecessaryParentheses.CSharpRemoveUnnecessaryParenthesesCodeFixProvider", "Remove Unnecessary Parentheses" }, + { "Microsoft.CodeAnalysis.CSharp.RemoveUnreachableCode.CSharpRemoveUnreachableCodeCodeFixProvider", "Remove Unreachable Code" }, + { "Microsoft.CodeAnalysis.CSharp.RemoveUnusedLocalFunction.CSharpRemoveUnusedLocalFunctionCodeFixProvider", "Remove Unused Local Function" }, + { "Microsoft.CodeAnalysis.CSharp.RemoveUnusedMembers.CSharpRemoveUnusedMembersCodeFixProvider", "Remove Unused Members" }, + { "Microsoft.CodeAnalysis.CSharp.RemoveUnusedParametersAndValues.CSharpRemoveUnusedValuesCodeFixProvider", "Remove Unused Parameters And Values: Remove Unused Values" }, + { "Microsoft.CodeAnalysis.CSharp.RemoveUnusedVariable.CSharpRemoveUnusedVariableCodeFixProvider", "Remove Unused Variable" }, + { "Microsoft.CodeAnalysis.CSharp.ReplaceConditionalWithStatements.CSharpReplaceConditionalWithStatementsCodeRefactoringProvider", "Replace Conditional With Statements (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.ReplaceDefaultLiteral.CSharpReplaceDefaultLiteralCodeFixProvider", "Replace Default Literal" }, + { "Microsoft.CodeAnalysis.CSharp.ReplaceDocCommentTextWithTag.CSharpReplaceDocCommentTextWithTagCodeRefactoringProvider", "Replace Doc Comment Text With Tag (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.ReverseForStatement.CSharpReverseForStatementCodeRefactoringProvider", "Reverse For Statement (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.SimplifyInterpolation.CSharpSimplifyInterpolationCodeFixProvider", "Simplify Interpolation" }, + { "Microsoft.CodeAnalysis.CSharp.SimplifyLinqExpression.CSharpSimplifyLinqTypeCheckAndCastCodeFixProvider", "Simplify Linq Expression: Simplify Linq Type Check And Cast" }, + { "Microsoft.CodeAnalysis.CSharp.SimplifyPropertyPattern.CSharpSimplifyPropertyPatternCodeFixProvider", "Simplify Property Pattern" }, + { "Microsoft.CodeAnalysis.CSharp.SimplifyThisOrMe.CSharpSimplifyThisOrMeCodeFixProvider", "Simplify This Or Me" }, + { "Microsoft.CodeAnalysis.CSharp.SimplifyTypeNames.SimplifyTypeNamesCodeFixProvider", "Simplify Type Names" }, + { "Microsoft.CodeAnalysis.CSharp.SpellCheck.CSharpSpellCheckCodeFixProvider", "Spell Check" }, + { "Microsoft.CodeAnalysis.CSharp.SplitOrMergeIfStatements.CSharpMergeConsecutiveIfStatementsCodeRefactoringProvider", "Split Or Merge If Statements: Merge Consecutive If Statements (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.SplitOrMergeIfStatements.CSharpMergeNestedIfStatementsCodeRefactoringProvider", "Split Or Merge If Statements: Merge Nested If Statements (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.SplitOrMergeIfStatements.CSharpSplitIntoConsecutiveIfStatementsCodeRefactoringProvider", "Split Or Merge If Statements: Split Into Consecutive If Statements (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.SplitOrMergeIfStatements.CSharpSplitIntoNestedIfStatementsCodeRefactoringProvider", "Split Or Merge If Statements: Split Into Nested If Statements (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.TypeStyle.UseExplicitTypeCodeFixProvider", "Use Explicit Type" }, + { "Microsoft.CodeAnalysis.CSharp.TypeStyle.UseImplicitTypeCodeFixProvider", "Use Implicit Type" }, + { "Microsoft.CodeAnalysis.CSharp.UnsealClass.CSharpUnsealClassCodeFixProvider", "Unseal Class" }, + { "Microsoft.CodeAnalysis.CSharp.UpdateProjectToAllowUnsafe.CSharpUpdateProjectToAllowUnsafeCodeFixProvider", "Update Project To Allow Unsafe" }, + { "Microsoft.CodeAnalysis.CSharp.UpgradeProject.CSharpUpgradeProjectCodeFixProvider", "Upgrade Project" }, + { "Microsoft.CodeAnalysis.CSharp.UseAutoProperty.CSharpUseAutoPropertyCodeFixProvider", "Use Auto Property" }, + { "Microsoft.CodeAnalysis.CSharp.UseCoalesceExpression.CSharpUseCoalesceExpressionForIfNullStatementCheckCodeFixProvider", "Use Coalesce Expression: For If Null Statement Check" }, + { "Microsoft.CodeAnalysis.CSharp.UseCollectionExpression.CSharpUseCollectionExpressionForArrayCodeFixProvider", "Use Collection Expression: For Array" }, + { "Microsoft.CodeAnalysis.CSharp.UseCollectionExpression.CSharpUseCollectionExpressionForBuilderCodeFixProvider", "Use Collection Expression: For Builder" }, + { "Microsoft.CodeAnalysis.CSharp.UseCollectionExpression.CSharpUseCollectionExpressionForCreateCodeFixProvider", "Use Collection Expression: For Create" }, + { "Microsoft.CodeAnalysis.CSharp.UseCollectionExpression.CSharpUseCollectionExpressionForEmptyCodeFixProvider", "Use Collection Expression: For Empty" }, + { "Microsoft.CodeAnalysis.CSharp.UseCollectionExpression.CSharpUseCollectionExpressionForFluentCodeFixProvider", "Use Collection Expression: For Fluent" }, + { "Microsoft.CodeAnalysis.CSharp.UseCollectionExpression.CSharpUseCollectionExpressionForNewCodeFixProvider", "Use Collection Expression: For New" }, + { "Microsoft.CodeAnalysis.CSharp.UseCollectionExpression.CSharpUseCollectionExpressionForStackAllocCodeFixProvider", "Use Collection Expression: For Stack Alloc" }, + { "Microsoft.CodeAnalysis.CSharp.UseCollectionInitializer.CSharpUseCollectionInitializerCodeFixProvider", "Use Collection Initializer" }, + { "Microsoft.CodeAnalysis.CSharp.UseCompoundAssignment.CSharpUseCompoundAssignmentCodeFixProvider", "Use Compound Assignment" }, + { "Microsoft.CodeAnalysis.CSharp.UseCompoundAssignment.CSharpUseCompoundCoalesceAssignmentCodeFixProvider", "Use Compound Assignment: Use Compound Coalesce Assignment" }, + { "Microsoft.CodeAnalysis.CSharp.UseConditionalExpression.CSharpUseConditionalExpressionForAssignmentCodeFixProvider", "Use Conditional Expression: For Assignment" }, + { "Microsoft.CodeAnalysis.CSharp.UseConditionalExpression.CSharpUseConditionalExpressionForReturnCodeFixProvider", "Use Conditional Expression: For Return" }, + { "Microsoft.CodeAnalysis.CSharp.UseDeconstruction.CSharpUseDeconstructionCodeFixProvider", "Use Deconstruction" }, + { "Microsoft.CodeAnalysis.CSharp.UseDefaultLiteral.CSharpUseDefaultLiteralCodeFixProvider", "Use Default Literal" }, + { "Microsoft.CodeAnalysis.CSharp.UseExplicitArrayInExpressionTree.CSharpUseExplicitArrayInExpressionTreeCodeFixProvider", "Use Explicit Array In Expression Tree" }, + { "Microsoft.CodeAnalysis.CSharp.UseExplicitTypeForConst.UseExplicitTypeForConstCodeFixProvider", "Use Explicit Type For Const" }, + { "Microsoft.CodeAnalysis.CSharp.UseExpressionBody.UseExpressionBodyCodeFixProvider", "Use Expression Body" }, + { "Microsoft.CodeAnalysis.CSharp.UseExpressionBody.UseExpressionBodyCodeRefactoringProvider", "Use Expression Body (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.UseExpressionBodyForLambda.UseExpressionBodyForLambdaCodeFixProvider", "Use Expression Body For Lambda" }, + { "Microsoft.CodeAnalysis.CSharp.UseExpressionBodyForLambda.UseExpressionBodyForLambdaCodeRefactoringProvider", "Use Expression Body For Lambda (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.UseImplicitlyTypedLambdaExpression.CSharpUseImplicitlyTypedLambdaExpressionCodeFixProvider", "Use Implicitly Typed Lambda Expression" }, + { "Microsoft.CodeAnalysis.CSharp.UseImplicitObjectCreation.CSharpUseImplicitObjectCreationCodeFixProvider", "Use Implicit Object Creation" }, + { "Microsoft.CodeAnalysis.CSharp.UseIndexOrRangeOperator.CSharpUseIndexOperatorCodeFixProvider", "Use Index Or Range Operator: Use Index Operator" }, + { "Microsoft.CodeAnalysis.CSharp.UseIndexOrRangeOperator.CSharpUseRangeOperatorCodeFixProvider", "Use Index Or Range Operator: Use Range Operator" }, + { "Microsoft.CodeAnalysis.CSharp.UseInferredMemberName.CSharpUseInferredMemberNameCodeFixProvider", "Use Inferred Member Name" }, + { "Microsoft.CodeAnalysis.CSharp.UseInterpolatedVerbatimString.CSharpUseInterpolatedVerbatimStringCodeFixProvider", "Use Interpolated Verbatim String" }, + { "Microsoft.CodeAnalysis.CSharp.UseIsNullCheck.CSharpUseIsNullCheckForCastAndEqualityOperatorCodeFixProvider", "Use Is Null Check: For Cast And Equality Operator" }, + { "Microsoft.CodeAnalysis.CSharp.UseIsNullCheck.CSharpUseIsNullCheckForReferenceEqualsCodeFixProvider", "Use Is Null Check: For Reference Equals" }, + { "Microsoft.CodeAnalysis.CSharp.UseIsNullCheck.CSharpUseNullCheckOverTypeCheckCodeFixProvider", "Use Is Null Check: Use Null Check Over Type Check" }, + { "Microsoft.CodeAnalysis.CSharp.UseLocalFunction.CSharpUseLocalFunctionCodeFixProvider", "Use Local Function" }, + { "Microsoft.CodeAnalysis.CSharp.UseNamedArguments.CSharpUseNamedArgumentsCodeRefactoringProvider", "Use Named Arguments (Refactoring)" }, + { "Microsoft.CodeAnalysis.CSharp.UseNullPropagation.CSharpUseNullPropagationCodeFixProvider", "Use Null Propagation" }, + { "Microsoft.CodeAnalysis.CSharp.UseObjectInitializer.CSharpUseObjectInitializerCodeFixProvider", "Use Object Initializer" }, + { "Microsoft.CodeAnalysis.CSharp.UsePatternCombinators.CSharpUsePatternCombinatorsCodeFixProvider", "Use Pattern Combinators" }, + { "Microsoft.CodeAnalysis.CSharp.UsePatternMatching.CSharpAsAndMemberAccessCodeFixProvider", "Use Pattern Matching: As And Member Access" }, + { "Microsoft.CodeAnalysis.CSharp.UsePatternMatching.CSharpAsAndNullCheckCodeFixProvider", "Use Pattern Matching: As And Null Check" }, + { "Microsoft.CodeAnalysis.CSharp.UsePatternMatching.CSharpIsAndCastCheckCodeFixProvider", "Use Pattern Matching: Is And Cast Check" }, + { "Microsoft.CodeAnalysis.CSharp.UsePatternMatching.CSharpIsAndCastCheckWithoutNameCodeFixProvider", "Use Pattern Matching: Is And Cast Check Without Name" }, + { "Microsoft.CodeAnalysis.CSharp.UsePatternMatching.CSharpUseNotPatternCodeFixProvider", "Use Pattern Matching: Use Not Pattern" }, + { "Microsoft.CodeAnalysis.CSharp.UsePrimaryConstructor.CSharpUsePrimaryConstructorCodeFixProvider", "Use Primary Constructor" }, + { "Microsoft.CodeAnalysis.CSharp.UseSimpleUsingStatement.UseSimpleUsingStatementCodeFixProvider", "Use Simple Using Statement" }, + { "Microsoft.CodeAnalysis.CSharp.UseSystemThreadingLock.CSharpUseSystemThreadingLockCodeFixProvider", "Use System.Threading.Lock" }, + { "Microsoft.CodeAnalysis.CSharp.UseThrowExpression.UseThrowExpressionCodeFixProvider", "Use Throw Expression" }, + { "Microsoft.CodeAnalysis.CSharp.UseTupleSwap.CSharpUseTupleSwapCodeFixProvider", "Use Tuple Swap" }, + { "Microsoft.CodeAnalysis.CSharp.UseUnboundGenericTypeInNameOf.CSharpUseUnboundGenericTypeInNameOfCodeFixProvider", "Use Unbound Generic Type In Name Of" }, + { "Microsoft.CodeAnalysis.CSharp.UseUtf8StringLiteral.UseUtf8StringLiteralCodeFixProvider", "Use UTF-8 String Literal" }, + { "Microsoft.CodeAnalysis.CSharp.Wrapping.CSharpWrappingCodeRefactoringProvider", "Wrapping (Refactoring)" }, + { "Microsoft.CodeAnalysis.Editor.Implementation.RenameTracking.RenameTrackingCodeRefactoringProvider", "Rename Tracking (Refactoring)" }, + { "Microsoft.CodeAnalysis.Editor.Implementation.RenameTracking.RenameTrackingTaggerProvider+RenameTrackingCodeAction", "Rename Tracking" }, + { "Microsoft.CodeAnalysis.EncapsulateField.EncapsulateFieldRefactoringProvider", "Encapsulate Field (Refactoring)" }, + { "Microsoft.CodeAnalysis.ExtractClass.ExtractClassWithDialogCodeAction", "Extract Class: With Dialog" }, + { "Microsoft.CodeAnalysis.ExtractInterface.ExtractInterfaceCodeAction", "Extract Interface" }, + { "Microsoft.CodeAnalysis.ExtractInterface.ExtractInterfaceCodeRefactoringProvider", "Extract Interface (Refactoring)" }, + { "Microsoft.CodeAnalysis.GenerateComparisonOperators.GenerateComparisonOperatorsCodeRefactoringProvider", "Generate Comparison Operators (Refactoring)" }, + { "Microsoft.CodeAnalysis.GenerateConstructors.AbstractGenerateConstructorsCodeRefactoringProvider+ConstructorDelegatingCodeAction", "Generate Constructors: Constructor Delegating (Refactoring)" }, + { "Microsoft.CodeAnalysis.GenerateConstructors.AbstractGenerateConstructorsCodeRefactoringProvider+FieldDelegatingCodeAction", "Generate Constructors: Field Delegating (Refactoring)" }, + { "Microsoft.CodeAnalysis.GenerateConstructors.AbstractGenerateConstructorsCodeRefactoringProvider+GenerateConstructorWithDialogCodeAction", "Generate Constructors: Generate Constructor With Dialog (Refactoring)" }, + { "Microsoft.CodeAnalysis.GenerateDefaultConstructors.AbstractGenerateDefaultConstructorsService`1+GenerateDefaultConstructorsCodeAction", "Generate Default Constructors" }, + { "Microsoft.CodeAnalysis.GenerateEqualsAndGetHashCodeFromMembers.GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider", "Generate Equals And Get Hash Code From Members (Refactoring)" }, + { "Microsoft.CodeAnalysis.GenerateEqualsAndGetHashCodeFromMembers.GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider+GenerateEqualsAndGetHashCodeAction", "Generate Equals And Get Hash Code From Members: Generate Equals And Get Hash (Refactoring)" }, + { "Microsoft.CodeAnalysis.GenerateEqualsAndGetHashCodeFromMembers.GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider+GenerateEqualsAndGetHashCodeWithDialogCodeAction", "Generate Equals And Get Hash Code From Members: Generate Equals And Get Hash Code With Dialog (Refactoring)" }, + { "Microsoft.CodeAnalysis.GenerateMember.GenerateEnumMember.AbstractGenerateEnumMemberService`3+GenerateEnumMemberCodeAction", "Generate Enum Member" }, + { "Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember.AbstractGenerateParameterizedMemberService`4+GenerateParameterizedMemberCodeAction", "Generate Parameterized Member" }, + { "Microsoft.CodeAnalysis.GenerateMember.GenerateVariable.AbstractGenerateVariableService`3+GenerateLocalCodeAction", "Generate Variable: Generate Local" }, + { "Microsoft.CodeAnalysis.GenerateMember.GenerateVariable.AbstractGenerateVariableService`3+GenerateParameterCodeAction", "Generate Variable: Generate Parameter" }, + { "Microsoft.CodeAnalysis.GenerateMember.GenerateVariable.AbstractGenerateVariableService`3+GenerateVariableCodeAction", "Generate Variable" }, + { "Microsoft.CodeAnalysis.GenerateOverrides.GenerateOverridesCodeRefactoringProvider", "Generate Overrides (Refactoring)" }, + { "Microsoft.CodeAnalysis.GenerateOverrides.GenerateOverridesCodeRefactoringProvider+GenerateOverridesWithDialogCodeAction", "Generate Overrides: With Dialog (Refactoring)" }, + { "Microsoft.CodeAnalysis.GenerateType.AbstractGenerateTypeService`6+GenerateTypeCodeAction", "Generate Type" }, + { "Microsoft.CodeAnalysis.GenerateType.AbstractGenerateTypeService`6+GenerateTypeCodeActionWithOption", "Generate Type: With Option" }, + { "Microsoft.CodeAnalysis.IntroduceVariable.AbstractIntroduceVariableService`6+IntroduceVariableCodeAction", "Introduce Variable" }, + { "Microsoft.CodeAnalysis.IntroduceVariable.IntroduceVariableCodeRefactoringProvider", "Introduce Variable (Refactoring)" }, + { "Microsoft.CodeAnalysis.LanguageServer.Handler.CodeActions.FixAllCodeAction", "Language Server: Fix All" }, + { "Microsoft.CodeAnalysis.MoveStaticMembers.MoveStaticMembersWithDialogCodeAction", "Move Static Members: With Dialog" }, + { "Microsoft.CodeAnalysis.MoveToNamespace.MoveToNamespaceCodeAction", "Move To Namespace" }, + { "Microsoft.CodeAnalysis.MoveToNamespace.MoveToNamespaceCodeActionProvider", "Move To Namespace" }, + { "Microsoft.CodeAnalysis.NewLines.ConsecutiveStatementPlacement.ConsecutiveStatementPlacementCodeFixProvider", "Consecutive Statement Placement" }, + { "Microsoft.CodeAnalysis.NewLines.MultipleBlankLines.MultipleBlankLinesCodeFixProvider", "Multiple Blank Lines" }, + { "Microsoft.CodeAnalysis.PreferFrameworkType.PreferFrameworkTypeCodeFixProvider", "Prefer Framework Type" }, + { "Microsoft.CodeAnalysis.RemoveRedundantEquality.RemoveRedundantEqualityCodeFixProvider", "Remove Redundant Equality" }, + { "Microsoft.CodeAnalysis.RemoveUnnecessarySuppressions.RemoveUnnecessaryAttributeSuppressionsCodeFixProvider", "Remove Unnecessary Suppressions: Remove Unnecessary Attribute Suppressions" }, + { "Microsoft.CodeAnalysis.RemoveUnnecessarySuppressions.RemoveUnnecessaryInlineSuppressionsCodeFixProvider", "Remove Unnecessary Suppressions: Remove Unnecessary Inline Suppressions" }, + { "Microsoft.CodeAnalysis.ReplaceMethodWithProperty.ReplaceMethodWithPropertyCodeRefactoringProvider", "Replace Method With Property (Refactoring)" }, + { "Microsoft.CodeAnalysis.ReplacePropertyWithMethods.ReplacePropertyWithMethodsCodeRefactoringProvider", "Replace Property With Methods (Refactoring)" }, + { "Microsoft.CodeAnalysis.SimplifyBooleanExpression.SimplifyConditionalCodeFixProvider", "Simplify Boolean Expression: Simplify Conditional" }, + { "Microsoft.CodeAnalysis.SimplifyLinqExpression.SimplifyLinqExpressionCodeFixProvider", "Simplify Linq Expression" }, + { "Microsoft.CodeAnalysis.UpdateLegacySuppressions.UpdateLegacySuppressionsCodeFixProvider", "Update Legacy Suppressions" }, + { "Microsoft.CodeAnalysis.UpgradeProject.ProjectOptionsChangeAction", "Upgrade Project: Project Options Change" }, + { "Microsoft.CodeAnalysis.UseCoalesceExpression.UseCoalesceExpressionForNullableTernaryConditionalCheckCodeFixProvider", "Use Coalesce Expression: For Nullable Ternary Conditional Check" }, + { "Microsoft.CodeAnalysis.UseCoalesceExpression.UseCoalesceExpressionForTernaryConditionalCheckCodeFixProvider", "Use Coalesce Expression: For Ternary Conditional Check" }, + { "Microsoft.CodeAnalysis.UseExplicitTupleName.UseExplicitTupleNameCodeFixProvider", "Use Explicit Tuple Name" }, + { "Microsoft.CodeAnalysis.UseSystemHashCode.UseSystemHashCodeCodeFixProvider", "Use System Hash Code" }, + { "Microsoft.CodeAnalysis.VisualBasic.AddAnonymousTypeMemberName.VisualBasicAddAnonymousTypeMemberNameCodeFixProvider", "Add Anonymous Type Member Name" }, + { "Microsoft.CodeAnalysis.VisualBasic.AddDebuggerDisplay.VisualBasicAddDebuggerDisplayCodeRefactoringProvider", "Add Debugger Display (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.AddFileBanner.VisualBasicAddFileBannerCodeRefactoringProvider", "Add File Banner (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.AddImport.VisualBasicAddImportCodeFixProvider", "Add Import" }, + { "Microsoft.CodeAnalysis.VisualBasic.AddMissingReference.VisualBasicAddMissingReferenceCodeFixProvider", "Add Missing Reference" }, + { "Microsoft.CodeAnalysis.VisualBasic.AddObsoleteAttribute.VisualBasicAddObsoleteAttributeCodeFixProvider", "Add Obsolete Attribute" }, + { "Microsoft.CodeAnalysis.VisualBasic.AddOrRemoveAccessibilityModifiers.VisualBasicAddOrRemoveAccessibilityModifiersCodeFixProvider", "Add Accessibility Modifiers" }, + { "Microsoft.CodeAnalysis.VisualBasic.AddPackage.VisualBasicAddSpecificPackageCodeFixProvider", "Add Package: Add Specific Package" }, + { "Microsoft.CodeAnalysis.VisualBasic.AddParameter.VisualBasicAddParameterCodeFixProvider", "Add Parameter" }, + { "Microsoft.CodeAnalysis.VisualBasic.AliasAmbiguousType.VisualBasicAliasAmbiguousTypeCodeFixProvider", "Alias Ambiguous Type" }, + { "Microsoft.CodeAnalysis.VisualBasic.CodeActions.RemoveStatementCodeAction", "Code Actions: Remove Statement" }, + { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.AddExplicitCast.VisualBasicAddExplicitCastCodeFixProvider", "Add Explicit Cast" }, + { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.ConvertToAsync.VisualBasicConvertToAsyncFunctionCodeFixProvider", "Convert To Async: Function" }, + { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.CorrectNextControlVariable.CorrectNextControlVariableCodeFixProvider", "Correct Next Control Variable" }, + { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.CorrectNextControlVariable.CorrectNextControlVariableCodeFixProvider+CorrectNextControlVariableCodeAction", "Correct Next Control Variable" }, + { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.FullyQualify.VisualBasicFullyQualifyCodeFixProvider", "Fully Qualify" }, + { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEndConstruct.GenerateEndConstructCodeFixProvider", "Generate End Construct" }, + { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEnumMember.GenerateEnumMemberCodeFixProvider", "Generate Enum Member" }, + { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEvent.GenerateEventCodeFixProvider", "Generate Event" }, + { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEvent.GenerateEventCodeFixProvider+GenerateEventCodeAction", "Generate Event" }, + { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateMethod.GenerateConversionCodeFixProvider", "Generate Method: Generate Conversion" }, + { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateMethod.GenerateParameterizedMemberCodeFixProvider", "Generate Method: Generate Parameterized Member" }, + { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateType.GenerateTypeCodeFixProvider", "Generate Type" }, + { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.IncorrectExitContinue.IncorrectExitContinueCodeFixProvider", "Incorrect Exit Continue" }, + { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.IncorrectExitContinue.IncorrectExitContinueCodeFixProvider+AddKeywordCodeAction", "Incorrect Exit Continue: Add Keyword" }, + { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.IncorrectExitContinue.IncorrectExitContinueCodeFixProvider+ReplaceKeywordCodeAction", "Incorrect Exit Continue: Replace Keyword" }, + { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.IncorrectExitContinue.IncorrectExitContinueCodeFixProvider+ReplaceTokenKeywordCodeAction", "Incorrect Exit Continue: Replace Token Keyword" }, + { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.IncorrectFunctionReturnType.IncorrectFunctionReturnTypeCodeFixProvider", "Incorrect Function Return Type" }, + { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.Iterator.VisualBasicChangeToYieldCodeFixProvider", "Iterator: Change To Yield" }, + { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.Iterator.VisualBasicConvertToIteratorCodeFixProvider", "Iterator: Convert To Iterator" }, + { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.MoveToTopOfFile.MoveToTopOfFileCodeFixProvider", "Move To Top Of File" }, + { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.MoveToTopOfFile.MoveToTopOfFileCodeFixProvider+MoveToLineCodeAction", "Move To Top Of File: Move To Line" }, + { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.OverloadBase.OverloadBaseCodeFixProvider", "Overload Base" }, + { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.OverloadBase.OverloadBaseCodeFixProvider+AddKeywordAction", "Overload Base: Add Keyword" }, + { "Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.AddAwait.VisualBasicAddAwaitCodeRefactoringProvider", "Add Await (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.InlineTemporary.VisualBasicInlineMethodRefactoringProvider", "Inline Temporary: Inline Method (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.InlineTemporary.VisualBasicInlineTemporaryCodeRefactoringProvider", "Inline Temporary (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.MoveStaticMembers.VisualBasicMoveStaticMembersRefactoringProvider", "Move Static Members (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.ConflictMarkerResolution.VisualBasicResolveConflictMarkerCodeFixProvider", "Conflict Marker Resolution: Resolve Conflict Marker" }, + { "Microsoft.CodeAnalysis.VisualBasic.ConvertAnonymousType.VisualBasicConvertAnonymousTypeToClassCodeRefactoringProvider", "Convert Anonymous Type: To Class (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.ConvertAnonymousTypeToTuple.VisualBasicConvertAnonymousTypeToTupleCodeRefactoringProvider", "Convert Anonymous Type To Tuple (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.ConvertAutoPropertyToFullProperty.VisualBasicConvertAutoPropertyToFullPropertyCodeRefactoringProvider", "Convert Auto Property To Full Property (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.ConvertCast.VisualBasicConvertDirectCastToTryCastCodeRefactoringProvider", "Convert Cast: Convert Direct Cast To Try Cast (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.ConvertConversionOperators.VisualBasicConvertTryCastToDirectCastCodeRefactoringProvider", "Convert Conversion Operators: Convert Try Cast To Direct Cast (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.ConvertForEachToFor.VisualBasicConvertForEachToForCodeRefactoringProvider", "Convert For Each To For (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.ConvertForToForEach.VisualBasicConvertForToForEachCodeRefactoringProvider", "Convert For To For Each (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.ConvertIfToSwitch.VisualBasicConvertIfToSwitchCodeRefactoringProvider", "Convert If To Switch (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.ConvertNumericLiteral.VisualBasicConvertNumericLiteralCodeRefactoringProvider", "Convert Numeric Literal (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.ConvertToInterpolatedString.VisualBasicConvertConcatenationToInterpolatedStringRefactoringProvider", "Convert To Interpolated String: Convert Concatenation To Interpolated String (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.ConvertToInterpolatedString.VisualBasicConvertPlaceholderToInterpolatedStringRefactoringProvider", "Convert To Interpolated String: Convert Placeholder To Interpolated String (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.ConvertTupleToStruct.VisualBasicConvertTupleToStructCodeRefactoringProvider", "Convert Tuple To Struct (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.ConvertTypeOfToNameOf.VisualBasicConvertGetTypeToNameOfCodeFixProvider", "Convert Type Of To Name Of: Convert Get Type To Name Of" }, + { "Microsoft.CodeAnalysis.VisualBasic.DocumentationComments.VisualBasicRemoveDocCommentNodeCodeFixProvider", "Documentation Comments: Remove Doc Comment Node" }, + { "Microsoft.CodeAnalysis.VisualBasic.Features.EmbeddedLanguages.VisualBasicJsonDetectionCodeFixProvider", "Embedded Languages: Json Detection" }, + { "Microsoft.CodeAnalysis.VisualBasic.FileHeaders.VisualBasicFileHeaderCodeFixProvider", "File Headers: File Header" }, + { "Microsoft.CodeAnalysis.VisualBasic.GenerateConstructor.GenerateConstructorCodeFixProvider", "Generate Constructor" }, + { "Microsoft.CodeAnalysis.VisualBasic.GenerateConstructors.VisualBasicGenerateConstructorsCodeRefactoringProvider", "Generate Constructors (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.GenerateDefaultConstructors.VisualBasicGenerateDefaultConstructorsCodeFixProvider", "Generate Default Constructors" }, + { "Microsoft.CodeAnalysis.VisualBasic.GenerateVariable.VisualBasicGenerateVariableCodeFixProvider", "Generate Variable" }, + { "Microsoft.CodeAnalysis.VisualBasic.ImplementAbstractClass.VisualBasicImplementAbstractClassCodeFixProvider", "Implement Abstract Class" }, + { "Microsoft.CodeAnalysis.VisualBasic.ImplementInterface.VisualBasicImplementInterfaceCodeFixProvider", "Implement Interface" }, + { "Microsoft.CodeAnalysis.VisualBasic.InitializeParameter.VisualBasicAddParameterCheckCodeRefactoringProvider", "Initialize Parameter: Add Parameter Check (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.InitializeParameter.VisualBasicInitializeMemberFromParameterCodeRefactoringProvider", "Initialize Parameter: Initialize Member From Parameter (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.IntroduceParameter.VisualBasicIntroduceParameterCodeRefactoringProvider", "Introduce Parameter (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.IntroduceUsingStatement.VisualBasicIntroduceUsingStatementCodeRefactoringProvider", "Introduce Using Statement (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable.VisualBasicIntroduceLocalForExpressionCodeRefactoringProvider", "Introduce Variable: Introduce Local For Expression (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.InvertConditional.VisualBasicInvertConditionalCodeRefactoringProvider", "Invert Conditional (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.InvertIf.VisualBasicInvertMultiLineIfCodeRefactoringProvider", "Invert If: Invert Multi Line If (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.InvertIf.VisualBasicInvertSingleLineIfCodeRefactoringProvider", "Invert If: Invert Single Line If (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.InvertLogical.VisualBasicInvertLogicalCodeRefactoringProvider", "Invert Logical (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.MakeFieldReadonly.VisualBasicMakeFieldReadonlyCodeFixProvider", "Make Field Readonly" }, + { "Microsoft.CodeAnalysis.VisualBasic.MakeMethodAsynchronous.VisualBasicMakeMethodAsynchronousCodeFixProvider", "Make Method Asynchronous" }, + { "Microsoft.CodeAnalysis.VisualBasic.MakeMethodSynchronous.VisualBasicMakeMethodSynchronousCodeFixProvider", "Make Method Synchronous" }, + { "Microsoft.CodeAnalysis.VisualBasic.MakeTypeAbstract.VisualBasicMakeTypeAbstractCodeFixProvider", "Make Type Abstract" }, + { "Microsoft.CodeAnalysis.VisualBasic.MakeTypePartial.VisualBasicMakeTypePartialCodeFixProvider", "Make Type Partial" }, + { "Microsoft.CodeAnalysis.VisualBasic.MoveDeclarationNearReference.VisualBasicMoveDeclarationNearReferenceCodeRefactoringProvider", "Move Declaration Near Reference (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.NameTupleElement.VisualBasicNameTupleElementCodeRefactoringProvider", "Name Tuple Element (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.OrderModifiers.VisualBasicOrderModifiersCodeFixProvider", "Order Modifiers" }, + { "Microsoft.CodeAnalysis.VisualBasic.PopulateSwitch.VisualBasicPopulateSwitchStatementCodeFixProvider", "Populate Switch: Statement" }, + { "Microsoft.CodeAnalysis.VisualBasic.QualifyMemberAccess.VisualBasicQualifyMemberAccessCodeFixProvider", "Qualify Member Access" }, + { "Microsoft.CodeAnalysis.VisualBasic.RemoveAsyncModifier.VisualBasicRemoveAsyncModifierCodeFixProvider", "Remove Async Modifier" }, + { "Microsoft.CodeAnalysis.VisualBasic.RemoveSharedFromModuleMembers.VisualBasicRemoveSharedFromModuleMembersCodeFixProvider", "Remove Shared From Module Members" }, + { "Microsoft.CodeAnalysis.VisualBasic.RemoveUnnecessaryByVal.VisualBasicRemoveUnnecessaryByValCodeFixProvider", "Remove Unnecessary By Val" }, + { "Microsoft.CodeAnalysis.VisualBasic.RemoveUnnecessaryCast.VisualBasicRemoveUnnecessaryCastCodeFixProvider", "Remove Unnecessary Cast" }, + { "Microsoft.CodeAnalysis.VisualBasic.RemoveUnnecessaryImports.VisualBasicRemoveUnnecessaryImportsCodeFixProvider", "Remove unnecessary imports" }, + { "Microsoft.CodeAnalysis.VisualBasic.RemoveUnnecessaryParentheses.VisualBasicRemoveUnnecessaryParenthesesCodeFixProvider", "Remove Unnecessary Parentheses" }, + { "Microsoft.CodeAnalysis.VisualBasic.RemoveUnusedMembers.VisualBasicRemoveUnusedMembersCodeFixProvider", "Remove Unused Members" }, + { "Microsoft.CodeAnalysis.VisualBasic.RemoveUnusedParametersAndValues.VisualBasicRemoveUnusedValuesCodeFixProvider", "Remove Unused Parameters And Values: Remove Unused Values" }, + { "Microsoft.CodeAnalysis.VisualBasic.RemoveUnusedVariable.VisualBasicRemoveUnusedVariableCodeFixProvider", "Remove Unused Variable" }, + { "Microsoft.CodeAnalysis.VisualBasic.ReplaceConditionalWithStatements.VisualBasicReplaceConditionalWithStatementsCodeRefactoringProvider", "Replace Conditional With Statements (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.ReplaceDocCommentTextWithTag.VisualBasicReplaceDocCommentTextWithTagCodeRefactoringProvider", "Replace Doc Comment Text With Tag (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.SimplifyInterpolation.VisualBasicSimplifyInterpolationCodeFixProvider", "Simplify Interpolation" }, + { "Microsoft.CodeAnalysis.VisualBasic.SimplifyObjectCreation.VisualBasicSimplifyObjectCreationCodeFixProvider", "Simplify Object Creation" }, + { "Microsoft.CodeAnalysis.VisualBasic.SimplifyThisOrMe.VisualBasicSimplifyThisOrMeCodeFixProvider", "Simplify This Or Me" }, + { "Microsoft.CodeAnalysis.VisualBasic.SimplifyTypeNames.SimplifyTypeNamesCodeFixProvider", "Simplify Type Names" }, + { "Microsoft.CodeAnalysis.VisualBasic.SpellCheck.VisualBasicSpellCheckCodeFixProvider", "Spell Check" }, + { "Microsoft.CodeAnalysis.VisualBasic.SplitOrMergeIfStatements.VisualBasicMergeConsecutiveIfStatementsCodeRefactoringProvider", "Split Or Merge If Statements: Merge Consecutive If Statements (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.SplitOrMergeIfStatements.VisualBasicMergeNestedIfStatementsCodeRefactoringProvider", "Split Or Merge If Statements: Merge Nested If Statements (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.SplitOrMergeIfStatements.VisualBasicSplitIntoConsecutiveIfStatementsCodeRefactoringProvider", "Split Or Merge If Statements: Split Into Consecutive If Statements (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.SplitOrMergeIfStatements.VisualBasicSplitIntoNestedIfStatementsCodeRefactoringProvider", "Split Or Merge If Statements: Split Into Nested If Statements (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.UnsealClass.VisualBasicUnsealClassCodeFixProvider", "Unseal Class" }, + { "Microsoft.CodeAnalysis.VisualBasic.UseAutoProperty.VisualBasicUseAutoPropertyCodeFixProvider", "Use Auto Property" }, + { "Microsoft.CodeAnalysis.VisualBasic.UseCoalesceExpression.VisualBasicUseCoalesceExpressionForIfNullStatementCheckCodeFixProvider", "Use Coalesce Expression: For If Null Statement Check" }, + { "Microsoft.CodeAnalysis.VisualBasic.UseCollectionInitializer.VisualBasicUseCollectionInitializerCodeFixProvider", "Use Collection Initializer" }, + { "Microsoft.CodeAnalysis.VisualBasic.UseCompoundAssignment.VisualBasicUseCompoundAssignmentCodeFixProvider", "Use Compound Assignment" }, + { "Microsoft.CodeAnalysis.VisualBasic.UseConditionalExpression.VisualBasicUseConditionalExpressionForAssignmentCodeFixProvider", "Use Conditional Expression: For Assignment" }, + { "Microsoft.CodeAnalysis.VisualBasic.UseConditionalExpression.VisualBasicUseConditionalExpressionForReturnCodeFixProvider", "Use Conditional Expression: For Return" }, + { "Microsoft.CodeAnalysis.VisualBasic.UseInferredMemberName.VisualBasicUseInferredMemberNameCodeFixProvider", "Use Inferred Member Name" }, + { "Microsoft.CodeAnalysis.VisualBasic.UseIsNotExpression.VisualBasicUseIsNotExpressionCodeFixProvider", "Use Is Not Expression" }, + { "Microsoft.CodeAnalysis.VisualBasic.UseIsNullCheck.VisualBasicUseIsNullCheckForReferenceEqualsCodeFixProvider", "Use Is Null Check: For Reference Equals" }, + { "Microsoft.CodeAnalysis.VisualBasic.UseNamedArguments.VisualBasicUseNamedArgumentsCodeRefactoringProvider", "Use Named Arguments (Refactoring)" }, + { "Microsoft.CodeAnalysis.VisualBasic.UseNullPropagation.VisualBasicUseNullPropagationCodeFixProvider", "Use Null Propagation" }, + { "Microsoft.CodeAnalysis.VisualBasic.UseObjectInitializer.VisualBasicUseObjectInitializerCodeFixProvider", "Use Object Initializer" }, + { "Microsoft.CodeAnalysis.VisualBasic.Wrapping.VisualBasicWrappingCodeRefactoringProvider", "Wrapping (Refactoring)" }, + { "Microsoft.CodeAnalysis.Wrapping.WrapItemsAction", "Wrapping: Wrap Items" }, + { "VisualBasicAddMissingImportsRefactoringProvider", "Add Missing Imports (Refactoring)" }, + }.ToImmutableDictionary(); +} diff --git a/src/Tools/BuildActionTelemetryTable/Program.cs b/src/Tools/BuildActionTelemetryTable/Program.cs index ed7802956b81f..d14eee81a71d5 100644 --- a/src/Tools/BuildActionTelemetryTable/Program.cs +++ b/src/Tools/BuildActionTelemetryTable/Program.cs @@ -15,685 +15,360 @@ using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Shared.Extensions; +using static BuildActionTelemetryTable.CodeActionDescriptions; -namespace BuildActionTelemetryTable +namespace BuildActionTelemetryTable; + +public static partial class Program { - public static class Program + private static readonly string s_executingPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!; + + private static ImmutableHashSet IgnoredCodeActions { get; } = new HashSet() { - private static readonly string s_executingPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!; + "Microsoft.CodeAnalysis.CodeActions.CodeAction+CodeActionWithNestedActions", + "Microsoft.CodeAnalysis.CodeActions.CodeAction+DocumentChangeAction", + "Microsoft.CodeAnalysis.CodeActions.CodeAction+NoChangeAction", + "Microsoft.CodeAnalysis.CodeActions.CodeAction+SolutionChangeAction", + "Microsoft.CodeAnalysis.CodeActions.CustomCodeActions+DocumentChangeAction", + "Microsoft.CodeAnalysis.CodeActions.CustomCodeActions+SolutionChangeAction", + "Microsoft.CodeAnalysis.CodeFixes.DocumentBasedFixAllProvider+PostProcessCodeAction", + }.ToImmutableHashSet(); + + public static void Main(string[] args) + { + Console.WriteLine("Loading assemblies and finding CodeActions ..."); - private static ImmutableHashSet IgnoredCodeActions { get; } = new HashSet() - { - "Microsoft.CodeAnalysis.CodeActions.CodeAction+CodeActionWithNestedActions", - "Microsoft.CodeAnalysis.CodeActions.CodeAction+DocumentChangeAction", - "Microsoft.CodeAnalysis.CodeActions.CodeAction+NoChangeAction", - "Microsoft.CodeAnalysis.CodeActions.CodeAction+SolutionChangeAction", - "Microsoft.CodeAnalysis.CodeActions.CustomCodeActions+DocumentChangeAction", - "Microsoft.CodeAnalysis.CodeActions.CustomCodeActions+SolutionChangeAction", - "Microsoft.CodeAnalysis.CodeFixes.DocumentBasedFixAllProvider+PostProcessCodeAction", - }.ToImmutableHashSet(); - - private static ImmutableDictionary CodeActionDescriptionMap { get; } = new Dictionary() + var assemblies = GetAssemblies(args); + var codeActionAndProviderTypes = GetCodeActionAndProviderTypes(assemblies); + + var telemetryInfos = GetTelemetryInfos(codeActionAndProviderTypes); + + if (!IsDescriptionMapComplete(telemetryInfos)) { - { "Microsoft.CodeAnalysis.AddConstructorParametersFromMembers.AddConstructorParametersFromMembersCodeRefactoringProvider", "Add Constructor Parameters From Members (Refactoring)" }, - { "Microsoft.CodeAnalysis.AddConstructorParametersFromMembers.AddConstructorParametersFromMembersCodeRefactoringProvider+AddConstructorParametersCodeAction", "Add Constructor Parameters From Members: Add Constructor Parameters (Refactoring)" }, - { "Microsoft.CodeAnalysis.AddImport.AbstractAddImportFeatureService`1+AssemblyReferenceCodeAction", "Add Import: Assembly Reference" }, - { "Microsoft.CodeAnalysis.AddImport.AbstractAddImportFeatureService`1+InstallPackageAndAddImportCodeAction", "Add Import: Install Package And Add Import" }, - { "Microsoft.CodeAnalysis.AddImport.AbstractAddImportFeatureService`1+InstallWithPackageManagerCodeAction", "Add Import: Install With Package Manager" }, - { "Microsoft.CodeAnalysis.AddImport.AbstractAddImportFeatureService`1+MetadataSymbolReferenceCodeAction", "Add Import: Metadata Symbol Reference" }, - { "Microsoft.CodeAnalysis.AddImport.AbstractAddImportFeatureService`1+ParentInstallPackageCodeAction", "Add Import: Parent Install Package" }, - { "Microsoft.CodeAnalysis.AddImport.AbstractAddImportFeatureService`1+ProjectSymbolReferenceCodeAction", "Add Import: Project Symbol Reference" }, - { "Microsoft.CodeAnalysis.AddMissingReference.AddMissingReferenceCodeAction", "Add Missing Reference" }, - { "Microsoft.CodeAnalysis.AddPackage.InstallPackageDirectlyCodeAction", "Add Package: Install Package Directly" }, - { "Microsoft.CodeAnalysis.AddPackage.InstallPackageParentCodeAction", "Add Package: Install Package Parent" }, - { "Microsoft.CodeAnalysis.AddPackage.InstallWithPackageManagerCodeAction", "Add Package: Install With Package Manager" }, - { "Microsoft.CodeAnalysis.AddRequiredParentheses.AddRequiredParenthesesCodeFixProvider", "Add Required Parentheses" }, - { "Microsoft.CodeAnalysis.ChangeSignature.ChangeSignatureCodeAction", "Change Signature" }, - { "Microsoft.CodeAnalysis.ChangeSignature.ChangeSignatureCodeRefactoringProvider", "Change Signature (Refactoring)" }, - { "Microsoft.CodeAnalysis.CodeFixes.Configuration.ConfigureCodeStyle.ConfigureCodeStyleOptionCodeFixProvider+TopLevelConfigureCodeStyleOptionCodeAction", "Configure Code Style Option: Top Level Configure Code Style Option" }, - { "Microsoft.CodeAnalysis.CodeFixes.Configuration.ConfigureSeverity.ConfigureSeverityLevelCodeFixProvider+TopLevelBulkConfigureSeverityCodeAction", "Configure Severity Level: Top Level Bulk Configure Severity" }, - { "Microsoft.CodeAnalysis.CodeFixes.Configuration.ConfigureSeverity.ConfigureSeverityLevelCodeFixProvider+TopLevelConfigureSeverityCodeAction", "Configure Severity Level: Top Level Configure Severity" }, - { "Microsoft.CodeAnalysis.CodeFixes.FixMultipleCodeAction", "Fix Multiple" }, - { "Microsoft.CodeAnalysis.CodeFixes.FullyQualify.AbstractFullyQualifyCodeFixProvider+GroupingCodeAction", "Fully Qualify: Grouping" }, - { "Microsoft.CodeAnalysis.CodeFixes.NamingStyles.NamingStyleCodeFixProvider", "Naming Styles: Naming Style" }, - { "Microsoft.CodeAnalysis.CodeFixes.NamingStyles.NamingStyleCodeFixProvider+FixNameCodeAction", "Naming Style: Fix Name" }, - { "Microsoft.CodeAnalysis.CodeFixes.Suppression.AbstractSuppressionCodeFixProvider+GlobalSuppressMessageCodeAction", "Suppression: Global Suppress Message" }, - { "Microsoft.CodeAnalysis.CodeFixes.Suppression.AbstractSuppressionCodeFixProvider+GlobalSuppressMessageFixAllCodeAction", "Suppression: Global Suppress Message Fix All" }, - { "Microsoft.CodeAnalysis.CodeFixes.Suppression.AbstractSuppressionCodeFixProvider+GlobalSuppressMessageFixAllCodeAction+GlobalSuppressionSolutionChangeAction", "Global Suppress Message Fix All: Global Suppression Solution Change" }, - { "Microsoft.CodeAnalysis.CodeFixes.Suppression.AbstractSuppressionCodeFixProvider+LocalSuppressMessageCodeAction", "Suppression: Local Suppress Message" }, - { "Microsoft.CodeAnalysis.CodeFixes.Suppression.AbstractSuppressionCodeFixProvider+PragmaWarningCodeAction", "Suppression: Pragma Warning" }, - { "Microsoft.CodeAnalysis.CodeFixes.Suppression.AbstractSuppressionCodeFixProvider+RemoveSuppressionCodeAction+AttributeRemoveAction", "Remove Suppression: Attribute Remove" }, - { "Microsoft.CodeAnalysis.CodeFixes.Suppression.AbstractSuppressionCodeFixProvider+RemoveSuppressionCodeAction+PragmaRemoveAction", "Remove Suppression: Pragma Remove" }, - { "Microsoft.CodeAnalysis.CodeFixes.Suppression.TopLevelSuppressionCodeAction", "Suppression: Top Level Suppression" }, - { "Microsoft.CodeAnalysis.CodeFixes.Suppression.WrapperCodeFixProvider", "Suppression: Wrapper" }, - { "Microsoft.CodeAnalysis.CodeFixesAndRefactorings.DocumentBasedFixAllProviderHelpers+PostProcessCodeAction", "Document Based Fix All: Post Process" }, - { "Microsoft.CodeAnalysis.CodeRefactorings.ExtractMethod.ExtractMethodCodeRefactoringProvider", "Extract Method (Refactoring)" }, - { "Microsoft.CodeAnalysis.CodeRefactorings.FixAllCodeRefactoringCodeAction", "Code Refactorings: Fix All Code Refactoring" }, - { "Microsoft.CodeAnalysis.CodeRefactorings.MoveType.AbstractMoveTypeService`5+MoveTypeCodeAction", "Move Type" }, - { "Microsoft.CodeAnalysis.CodeRefactorings.MoveType.MoveTypeCodeRefactoringProvider", "Move Type (Refactoring)" }, - { "Microsoft.CodeAnalysis.CodeRefactorings.PullMemberUp.AbstractPullMemberUpRefactoringProvider+PullMemberUpWithDialogCodeAction", "Pull Member Up: With Dialog (Refactoring)" }, - { "Microsoft.CodeAnalysis.CodeRefactorings.SyncNamespace.AbstractSyncNamespaceCodeRefactoringProvider`3+MoveFileCodeAction", "Sync Namespace: Move File (Refactoring)" }, - { "Microsoft.CodeAnalysis.CodeStyle.CSharpFormattingCodeFixProvider", "Formatting" }, - { "Microsoft.CodeAnalysis.CodeStyle.VisualBasicFormattingCodeFixProvider", "Formatting" }, - { "Microsoft.CodeAnalysis.ConvertToInterpolatedString.ConvertRegularStringToInterpolatedStringRefactoringProvider", "Convert To Interpolated String: Convert Regular String To Interpolated String (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.AddAccessibilityModifiers.CSharpAddAccessibilityModifiersCodeFixProvider", "Add Accessibility Modifiers" }, - { "Microsoft.CodeAnalysis.CSharp.AddAnonymousTypeMemberName.CSharpAddAnonymousTypeMemberNameCodeFixProvider", "Add Anonymous Type Member Name" }, - { "Microsoft.CodeAnalysis.CSharp.AddDebuggerDisplay.CSharpAddDebuggerDisplayCodeRefactoringProvider", "Add Debugger Display (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.AddFileBanner.CSharpAddFileBannerCodeRefactoringProvider", "Add File Banner (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.AddImport.CSharpAddImportCodeFixProvider", "Add Import" }, - { "Microsoft.CodeAnalysis.CSharp.AddMissingReference.CSharpAddMissingReferenceCodeFixProvider", "Add Missing Reference" }, - { "Microsoft.CodeAnalysis.CSharp.AddObsoleteAttribute.CSharpAddObsoleteAttributeCodeFixProvider", "Add Obsolete Attribute" }, - { "Microsoft.CodeAnalysis.CSharp.AddPackage.CSharpAddSpecificPackageCodeFixProvider", "Add Package: Add Specific Package" }, - { "Microsoft.CodeAnalysis.CSharp.AddParameter.CSharpAddParameterCodeFixProvider", "Add Parameter" }, - { "Microsoft.CodeAnalysis.CSharp.AliasAmbiguousType.CSharpAliasAmbiguousTypeCodeFixProvider", "Alias Ambiguous Type" }, - { "Microsoft.CodeAnalysis.CSharp.AssignOutParameters.AssignOutParametersAboveReturnCodeFixProvider", "Assign Out Parameters: Above Return" }, - { "Microsoft.CodeAnalysis.CSharp.AssignOutParameters.AssignOutParametersAtStartCodeFixProvider", "Assign Out Parameters: At Start" }, - { "Microsoft.CodeAnalysis.CSharp.CodeFixes.AddExplicitCast.CSharpAddExplicitCastCodeFixProvider", "Add Explicit Cast" }, - { "Microsoft.CodeAnalysis.CSharp.CodeFixes.AddInheritdoc.AddInheritdocCodeFixProvider", "Add Inheritdoc" }, - { "Microsoft.CodeAnalysis.CSharp.CodeFixes.ConditionalExpressionInStringInterpolation.CSharpAddParenthesesAroundConditionalExpressionInInterpolatedStringCodeFixProvider", "Conditional Expression In String Interpolation: Add Parentheses Around Conditional Expression In Interpolated String" }, - { "Microsoft.CodeAnalysis.CSharp.CodeFixes.ConvertToAsync.CSharpConvertToAsyncMethodCodeFixProvider", "Convert To Async: Method" }, - { "Microsoft.CodeAnalysis.CSharp.CodeFixes.DeclareAsNullable.CSharpDeclareAsNullableCodeFixProvider", "Declare As Nullable" }, - { "Microsoft.CodeAnalysis.CSharp.CodeFixes.FixIncorrectConstraint.CSharpFixIncorrectConstraintCodeFixProvider", "Fix Incorrect Constraint" }, - { "Microsoft.CodeAnalysis.CSharp.CodeFixes.FixReturnType.CSharpFixReturnTypeCodeFixProvider", "Fix Return Type" }, - { "Microsoft.CodeAnalysis.CSharp.CodeFixes.ForEachCast.CSharpForEachCastCodeFixProvider", "For Each Cast" }, - { "Microsoft.CodeAnalysis.CSharp.CodeFixes.FullyQualify.CSharpFullyQualifyCodeFixProvider", "Fully Qualify" }, - { "Microsoft.CodeAnalysis.CSharp.CodeFixes.GenerateDeconstructMethod.GenerateDeconstructMethodCodeFixProvider", "Generate Deconstruct Method" }, - { "Microsoft.CodeAnalysis.CSharp.CodeFixes.GenerateEnumMember.GenerateEnumMemberCodeFixProvider", "Generate Enum Member" }, - { "Microsoft.CodeAnalysis.CSharp.CodeFixes.GenerateMethod.GenerateConversionCodeFixProvider", "Generate Method: Generate Conversion" }, - { "Microsoft.CodeAnalysis.CSharp.CodeFixes.GenerateMethod.GenerateMethodCodeFixProvider", "Generate Method" }, - { "Microsoft.CodeAnalysis.CSharp.CodeFixes.GenerateType.GenerateTypeCodeFixProvider", "Generate Type" }, - { "Microsoft.CodeAnalysis.CSharp.CodeFixes.HideBase.HideBaseCodeFixProvider", "Hide Base" }, - { "Microsoft.CodeAnalysis.CSharp.CodeFixes.HideBase.HideBaseCodeFixProvider+AddNewKeywordAction", "Hide Base: Add New Keyword" }, - { "Microsoft.CodeAnalysis.CSharp.CodeFixes.Iterator.CSharpAddYieldCodeFixProvider", "Iterator: Add Yield" }, - { "Microsoft.CodeAnalysis.CSharp.CodeFixes.Iterator.CSharpChangeToIEnumerableCodeFixProvider", "Iterator: Change To IEnumerable" }, - { "Microsoft.CodeAnalysis.CSharp.CodeFixes.MakeStatementAsynchronous.CSharpMakeStatementAsynchronousCodeFixProvider", "Make Statement Asynchronous" }, - { "Microsoft.CodeAnalysis.CSharp.CodeFixes.MatchFolderAndNamespace.CSharpChangeNamespaceToMatchFolderCodeFixProvider", "Match Folder And Namespace: Change Namespace To Match Folder" }, - { "Microsoft.CodeAnalysis.CSharp.CodeFixes.RemoveInKeyword.RemoveInKeywordCodeFixProvider", "Remove In Keyword" }, - { "Microsoft.CodeAnalysis.CSharp.CodeFixes.RemoveNewModifier.RemoveNewModifierCodeFixProvider", "Remove New Modifier" }, - { "Microsoft.CodeAnalysis.CSharp.CodeFixes.TransposeRecordKeyword.CSharpTransposeRecordKeywordCodeFixProvider", "Transpose Record Keyword" }, - { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.AddAwait.CSharpAddAwaitCodeRefactoringProvider", "Add Await (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.AddMissingImports.CSharpAddMissingImportsRefactoringProvider", "Add Missing Imports (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.ConvertLocalFunctionToMethod.CSharpConvertLocalFunctionToMethodCodeRefactoringProvider", "Convert Local Function To Method (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.EnableNullable.EnableNullableCodeRefactoringProvider", "Enable Nullable (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.EnableNullable.EnableNullableCodeRefactoringProvider+CustomCodeAction", "Enable Nullable (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.ExtractClass.CSharpExtractClassCodeRefactoringProvider", "Extract Class (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.InlineMethod.CSharpInlineMethodRefactoringProvider", "Inline Method (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.InlineTemporary.CSharpInlineTemporaryCodeRefactoringProvider", "Inline Temporary (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.MoveStaticMembers.CSharpMoveStaticMembersRefactoringProvider", "Move Static Members (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.PullMemberUp.CSharpPullMemberUpCodeRefactoringProvider", "Pull Member Up (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.SyncNamespace.CSharpSyncNamespaceCodeRefactoringProvider", "Sync Namespace (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.UseExplicitType.UseExplicitTypeCodeRefactoringProvider", "Use Explicit Type (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.UseImplicitType.UseImplicitTypeCodeRefactoringProvider", "Use Implicit Type (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.CodeRefactorings.UseRecursivePatterns.UseRecursivePatternsCodeRefactoringProvider", "Use Recursive Patterns (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.ConflictMarkerResolution.CSharpResolveConflictMarkerCodeFixProvider", "Conflict Marker Resolution: Resolve Conflict Marker" }, - { "Microsoft.CodeAnalysis.CSharp.ConvertAnonymousType.CSharpConvertAnonymousTypeToClassCodeRefactoringProvider", "Convert Anonymous Type: To Class (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.ConvertAnonymousType.CSharpConvertAnonymousTypeToTupleCodeRefactoringProvider", "Convert Anonymous Type: To Tuple (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.ConvertAutoPropertyToFullProperty.CSharpConvertAutoPropertyToFullPropertyCodeRefactoringProvider", "Convert Auto Property To Full Property (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.ConvertBetweenRegularAndVerbatimString.ConvertBetweenRegularAndVerbatimInterpolatedStringCodeRefactoringProvider", "Convert Between Regular And Verbatim String: Convert Between Regular And Verbatim Interpolated String (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.ConvertBetweenRegularAndVerbatimString.ConvertBetweenRegularAndVerbatimStringCodeRefactoringProvider", "Convert Between Regular And Verbatim String (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.ConvertCast.CSharpConvertDirectCastToTryCastCodeRefactoringProvider", "Convert Cast: Convert Direct Cast To Try Cast (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.ConvertCast.CSharpConvertTryCastToDirectCastCodeRefactoringProvider", "Convert Cast: Convert Try Cast To Direct Cast (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.ConvertForEachToFor.CSharpConvertForEachToForCodeRefactoringProvider", "Convert For Each To For (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.ConvertForToForEach.CSharpConvertForToForEachCodeRefactoringProvider", "Convert For To For Each (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.ConvertIfToSwitch.CSharpConvertIfToSwitchCodeRefactoringProvider", "Convert If To Switch (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.ConvertLinq.ConvertForEachToLinqQuery.CSharpConvertForEachToLinqQueryProvider", "Convert For Each To Linq Query" }, - { "Microsoft.CodeAnalysis.CSharp.ConvertLinq.CSharpConvertLinqQueryToForEachProvider", "Convert Linq: Query To For Each" }, - { "Microsoft.CodeAnalysis.CSharp.ConvertNamespace.ConvertNamespaceCodeFixProvider", "Convert Namespace" }, - { "Microsoft.CodeAnalysis.CSharp.ConvertNamespace.ConvertNamespaceCodeRefactoringProvider", "Convert Namespace (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.ConvertNumericLiteral.CSharpConvertNumericLiteralCodeRefactoringProvider", "Convert Numeric Literal (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.ConvertProgram.ConvertToProgramMainCodeFixProvider", "Convert Program: Convert To Program Main" }, - { "Microsoft.CodeAnalysis.CSharp.ConvertProgram.ConvertToProgramMainCodeRefactoringProvider", "Convert Program: Convert To Program Main (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.ConvertProgram.ConvertToTopLevelStatementsCodeFixProvider", "Convert Program: Convert To Top Level Statements" }, - { "Microsoft.CodeAnalysis.CSharp.ConvertProgram.ConvertToTopLevelStatementsCodeRefactoringProvider", "Convert Program: Convert To Top Level Statements (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.ConvertSwitchStatementToExpression.ConvertSwitchStatementToExpressionCodeFixProvider", "Convert Switch Statement To Expression" }, - { "Microsoft.CodeAnalysis.CSharp.ConvertToInterpolatedString.CSharpConvertConcatenationToInterpolatedStringRefactoringProvider", "Convert To Interpolated String: Convert Concatenation To Interpolated String (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.ConvertToInterpolatedString.CSharpConvertPlaceholderToInterpolatedStringRefactoringProvider", "Convert To Interpolated String: Convert Placeholder To Interpolated String (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.ConvertToRawString.ConvertRegularStringToRawStringCodeRefactoringProvider", "Convert To Raw String: Convert Regular String To Raw String (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.ConvertTupleToStruct.CSharpConvertTupleToStructCodeRefactoringProvider", "Convert Tuple To Struct (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.ConvertTypeOfToNameOf.CSharpConvertTypeOfToNameOfCodeFixProvider", "Convert Type Of To Name Of" }, - { "Microsoft.CodeAnalysis.CSharp.Diagnostics.AddBraces.CSharpAddBracesCodeFixProvider", "Add Braces" }, - { "Microsoft.CodeAnalysis.CSharp.DisambiguateSameVariable.CSharpDisambiguateSameVariableCodeFixProvider", "Disambiguate Same Variable" }, - { "Microsoft.CodeAnalysis.CSharp.EmbeddedLanguages.CSharpJsonDetectionCodeFixProvider", "Embedded Languages: Json Detection" }, - { "Microsoft.CodeAnalysis.CSharp.FileHeaders.CSharpFileHeaderCodeFixProvider", "File Headers: File Header" }, - { "Microsoft.CodeAnalysis.CSharp.GenerateConstructor.GenerateConstructorCodeFixProvider", "Generate Constructor" }, - { "Microsoft.CodeAnalysis.CSharp.GenerateConstructorFromMembers.CSharpGenerateConstructorFromMembersCodeRefactoringProvider", "Generate Constructor From Members (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.GenerateDefaultConstructors.CSharpGenerateDefaultConstructorsCodeFixProvider", "Generate Default Constructors" }, - { "Microsoft.CodeAnalysis.CSharp.GenerateVariable.CSharpGenerateVariableCodeFixProvider", "Generate Variable" }, - { "Microsoft.CodeAnalysis.CSharp.ImplementAbstractClass.CSharpImplementAbstractClassCodeFixProvider", "Implement Abstract Class" }, - { "Microsoft.CodeAnalysis.CSharp.ImplementInterface.CSharpImplementExplicitlyCodeRefactoringProvider", "Implement Interface: Implement Explicitly (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.ImplementInterface.CSharpImplementImplicitlyCodeRefactoringProvider", "Implement Interface: Implement Implicitly (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.ImplementInterface.CSharpImplementInterfaceCodeFixProvider", "Implement Interface" }, - { "Microsoft.CodeAnalysis.CSharp.InitializeParameter.CSharpAddParameterCheckCodeRefactoringProvider", "Initialize Parameter: Add Parameter Check (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.InitializeParameter.CSharpInitializeMemberFromParameterCodeRefactoringProvider", "Initialize Parameter: Initialize Member From Parameter (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.InlineDeclaration.CSharpInlineDeclarationCodeFixProvider", "Inline Declaration" }, - { "Microsoft.CodeAnalysis.CSharp.IntroduceUsingStatement.CSharpIntroduceUsingStatementCodeRefactoringProvider", "Introduce Using Statement (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.IntroduceVariable.CSharpIntroduceLocalForExpressionCodeRefactoringProvider", "Introduce Variable: Introduce Local For Expression (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.IntroduceVariable.CSharpIntroduceParameterCodeRefactoringProvider", "Introduce Variable: Introduce Parameter (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.InvertConditional.CSharpInvertConditionalCodeRefactoringProvider", "Invert Conditional (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.InvertIf.CSharpInvertIfCodeRefactoringProvider", "Invert If (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.InvertLogical.CSharpInvertLogicalCodeRefactoringProvider", "Invert Logical (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.InvokeDelegateWithConditionalAccess.InvokeDelegateWithConditionalAccessCodeFixProvider", "Invoke Delegate With Conditional Access" }, - { "Microsoft.CodeAnalysis.CSharp.MakeFieldReadonly.CSharpMakeFieldReadonlyCodeFixProvider", "Make Field Readonly" }, - { "Microsoft.CodeAnalysis.CSharp.MakeLocalFunctionStatic.MakeLocalFunctionStaticCodeFixProvider", "Make Local Function Static" }, - { "Microsoft.CodeAnalysis.CSharp.MakeLocalFunctionStatic.MakeLocalFunctionStaticCodeRefactoringProvider", "Make Local Function Static (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.MakeLocalFunctionStatic.PassInCapturedVariablesAsArgumentsCodeFixProvider", "Make Local Function Static: Pass In Captured Variables As Arguments" }, - { "Microsoft.CodeAnalysis.CSharp.MakeMemberStatic.CSharpMakeMemberStaticCodeFixProvider", "Make Member Static" }, - { "Microsoft.CodeAnalysis.CSharp.MakeMethodAsynchronous.CSharpMakeMethodAsynchronousCodeFixProvider", "Make Method Asynchronous" }, - { "Microsoft.CodeAnalysis.CSharp.MakeMethodSynchronous.CSharpMakeMethodSynchronousCodeFixProvider", "Make Method Synchronous" }, - { "Microsoft.CodeAnalysis.CSharp.MakeRefStruct.MakeRefStructCodeFixProvider", "Make Ref Struct" }, - { "Microsoft.CodeAnalysis.CSharp.MakeStructFieldsWritable.CSharpMakeStructFieldsWritableCodeFixProvider", "Make Struct Fields Writable" }, - { "Microsoft.CodeAnalysis.CSharp.MakeTypeAbstract.CSharpMakeTypeAbstractCodeFixProvider", "Make Type Abstract" }, - { "Microsoft.CodeAnalysis.CSharp.MisplacedUsingDirectives.MisplacedUsingDirectivesCodeFixProvider", "Misplaced Using Directives" }, - { "Microsoft.CodeAnalysis.CSharp.MoveDeclarationNearReference.CSharpMoveDeclarationNearReferenceCodeRefactoringProvider", "Move Declaration Near Reference (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.NameTupleElement.CSharpNameTupleElementCodeRefactoringProvider", "Name Tuple Element (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.NewLines.ConsecutiveBracePlacement.ConsecutiveBracePlacementCodeFixProvider", "Consecutive Brace Placement" }, - { "Microsoft.CodeAnalysis.CSharp.NewLines.ConstructorInitializerPlacement.ConstructorInitializerPlacementCodeFixProvider", "Constructor Initializer Placement" }, - { "Microsoft.CodeAnalysis.CSharp.NewLines.EmbeddedStatementPlacement.EmbeddedStatementPlacementCodeFixProvider", "Embedded Statement Placement" }, - { "Microsoft.CodeAnalysis.CSharp.OrderModifiers.CSharpOrderModifiersCodeFixProvider", "Order Modifiers" }, - { "Microsoft.CodeAnalysis.CSharp.PopulateSwitch.CSharpPopulateSwitchExpressionCodeFixProvider", "Populate Switch: Expression" }, - { "Microsoft.CodeAnalysis.CSharp.PopulateSwitch.CSharpPopulateSwitchStatementCodeFixProvider", "Populate Switch: Statement" }, - { "Microsoft.CodeAnalysis.CSharp.QualifyMemberAccess.CSharpQualifyMemberAccessCodeFixProvider", "Qualify Member Access" }, - { "Microsoft.CodeAnalysis.CSharp.RemoveAsyncModifier.CSharpRemoveAsyncModifierCodeFixProvider", "Remove Async Modifier" }, - { "Microsoft.CodeAnalysis.CSharp.RemoveConfusingSuppression.CSharpRemoveConfusingSuppressionCodeFixProvider", "Remove Confusing Suppression" }, - { "Microsoft.CodeAnalysis.CSharp.RemoveUnnecessaryCast.CSharpRemoveUnnecessaryCastCodeFixProvider", "Remove Unnecessary Cast" }, - { "Microsoft.CodeAnalysis.CSharp.RemoveUnnecessaryDiscardDesignation.CSharpRemoveUnnecessaryDiscardDesignationCodeFixProvider", "Remove Unnecessary Discard Designation" }, - { "Microsoft.CodeAnalysis.CSharp.RemoveUnnecessaryImports.CSharpRemoveUnnecessaryImportsCodeFixProvider", "Remove unnecessary imports" }, - { "Microsoft.CodeAnalysis.CSharp.RemoveUnnecessaryLambdaExpression.CSharpRemoveUnnecessaryLambdaExpressionCodeFixProvider", "Remove Unnecessary Lambda Expression" }, - { "Microsoft.CodeAnalysis.CSharp.RemoveUnnecessaryParentheses.CSharpRemoveUnnecessaryParenthesesCodeFixProvider", "Remove Unnecessary Parentheses" }, - { "Microsoft.CodeAnalysis.CSharp.RemoveUnreachableCode.CSharpRemoveUnreachableCodeCodeFixProvider", "Remove Unreachable Code" }, - { "Microsoft.CodeAnalysis.CSharp.RemoveUnusedLocalFunction.CSharpRemoveUnusedLocalFunctionCodeFixProvider", "Remove Unused Local Function" }, - { "Microsoft.CodeAnalysis.CSharp.RemoveUnusedMembers.CSharpRemoveUnusedMembersCodeFixProvider", "Remove Unused Members" }, - { "Microsoft.CodeAnalysis.CSharp.RemoveUnusedParametersAndValues.CSharpRemoveUnusedValuesCodeFixProvider", "Remove Unused Parameters And Values: Remove Unused Values" }, - { "Microsoft.CodeAnalysis.CSharp.RemoveUnusedVariable.CSharpRemoveUnusedVariableCodeFixProvider", "Remove Unused Variable" }, - { "Microsoft.CodeAnalysis.CSharp.ReplaceConditionalWithStatements.CSharpReplaceConditionalWithStatementsCodeRefactoringProvider", "Replace Conditional With Statements (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.ReplaceDefaultLiteral.CSharpReplaceDefaultLiteralCodeFixProvider", "Replace Default Literal" }, - { "Microsoft.CodeAnalysis.CSharp.ReplaceDocCommentTextWithTag.CSharpReplaceDocCommentTextWithTagCodeRefactoringProvider", "Replace Doc Comment Text With Tag (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.ReverseForStatement.CSharpReverseForStatementCodeRefactoringProvider", "Reverse For Statement (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.SimplifyInterpolation.CSharpSimplifyInterpolationCodeFixProvider", "Simplify Interpolation" }, - { "Microsoft.CodeAnalysis.CSharp.SimplifyLinqExpression.CSharpSimplifyLinqExpressionCodeFixProvider", "Simplify Linq Expression" }, - { "Microsoft.CodeAnalysis.CSharp.SimplifyPropertyPattern.CSharpSimplifyPropertyPatternCodeFixProvider", "Simplify Property Pattern" }, - { "Microsoft.CodeAnalysis.CSharp.SimplifyThisOrMe.CSharpSimplifyThisOrMeCodeFixProvider", "Simplify This Or Me" }, - { "Microsoft.CodeAnalysis.CSharp.SimplifyTypeNames.SimplifyTypeNamesCodeFixProvider", "Simplify Type Names" }, - { "Microsoft.CodeAnalysis.CSharp.SpellCheck.CSharpSpellCheckCodeFixProvider", "Spell Check" }, - { "Microsoft.CodeAnalysis.CSharp.SplitOrMergeIfStatements.CSharpMergeConsecutiveIfStatementsCodeRefactoringProvider", "Split Or Merge If Statements: Merge Consecutive If Statements (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.SplitOrMergeIfStatements.CSharpMergeNestedIfStatementsCodeRefactoringProvider", "Split Or Merge If Statements: Merge Nested If Statements (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.SplitOrMergeIfStatements.CSharpSplitIntoConsecutiveIfStatementsCodeRefactoringProvider", "Split Or Merge If Statements: Split Into Consecutive If Statements (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.SplitOrMergeIfStatements.CSharpSplitIntoNestedIfStatementsCodeRefactoringProvider", "Split Or Merge If Statements: Split Into Nested If Statements (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.TypeStyle.UseExplicitTypeCodeFixProvider", "Use Explicit Type" }, - { "Microsoft.CodeAnalysis.CSharp.TypeStyle.UseImplicitTypeCodeFixProvider", "Use Implicit Type" }, - { "Microsoft.CodeAnalysis.CSharp.UnsealClass.CSharpUnsealClassCodeFixProvider", "Unseal Class" }, - { "Microsoft.CodeAnalysis.CSharp.UpdateProjectToAllowUnsafe.CSharpUpdateProjectToAllowUnsafeCodeFixProvider", "Update Project To Allow Unsafe" }, - { "Microsoft.CodeAnalysis.CSharp.UpgradeProject.CSharpUpgradeProjectCodeFixProvider", "Upgrade Project" }, - { "Microsoft.CodeAnalysis.CSharp.UseAutoProperty.CSharpUseAutoPropertyCodeFixProvider", "Use Auto Property" }, - { "Microsoft.CodeAnalysis.CSharp.UseCollectionInitializer.CSharpUseCollectionInitializerCodeFixProvider", "Use Collection Initializer" }, - { "Microsoft.CodeAnalysis.CSharp.UseCompoundAssignment.CSharpUseCompoundAssignmentCodeFixProvider", "Use Compound Assignment" }, - { "Microsoft.CodeAnalysis.CSharp.UseCompoundAssignment.CSharpUseCompoundCoalesceAssignmentCodeFixProvider", "Use Compound Assignment: Use Compound Coalesce Assignment" }, - { "Microsoft.CodeAnalysis.CSharp.UseConditionalExpression.CSharpUseConditionalExpressionForAssignmentCodeFixProvider", "Use Conditional Expression: For Assignment" }, - { "Microsoft.CodeAnalysis.CSharp.UseConditionalExpression.CSharpUseConditionalExpressionForReturnCodeFixProvider", "Use Conditional Expression: For Return" }, - { "Microsoft.CodeAnalysis.CSharp.UseDeconstruction.CSharpUseDeconstructionCodeFixProvider", "Use Deconstruction" }, - { "Microsoft.CodeAnalysis.CSharp.UseDefaultLiteral.CSharpUseDefaultLiteralCodeFixProvider", "Use Default Literal" }, - { "Microsoft.CodeAnalysis.CSharp.UseExplicitTypeForConst.UseExplicitTypeForConstCodeFixProvider", "Use Explicit Type For Const" }, - { "Microsoft.CodeAnalysis.CSharp.UseExpressionBody.UseExpressionBodyCodeFixProvider", "Use Expression Body" }, - { "Microsoft.CodeAnalysis.CSharp.UseExpressionBody.UseExpressionBodyCodeRefactoringProvider", "Use Expression Body (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.UseExpressionBodyForLambda.UseExpressionBodyForLambdaCodeFixProvider", "Use Expression Body For Lambda" }, - { "Microsoft.CodeAnalysis.CSharp.UseExpressionBodyForLambda.UseExpressionBodyForLambdaCodeRefactoringProvider", "Use Expression Body For Lambda (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.UseImplicitObjectCreation.CSharpUseImplicitObjectCreationCodeFixProvider", "Use Implicit Object Creation" }, - { "Microsoft.CodeAnalysis.CSharp.UseIndexOrRangeOperator.CSharpUseIndexOperatorCodeFixProvider", "Use Index Or Range Operator: Use Index Operator" }, - { "Microsoft.CodeAnalysis.CSharp.UseIndexOrRangeOperator.CSharpUseRangeOperatorCodeFixProvider", "Use Index Or Range Operator: Use Range Operator" }, - { "Microsoft.CodeAnalysis.CSharp.UseInferredMemberName.CSharpUseInferredMemberNameCodeFixProvider", "Use Inferred Member Name" }, - { "Microsoft.CodeAnalysis.CSharp.UseInterpolatedVerbatimString.CSharpUseInterpolatedVerbatimStringCodeFixProvider", "Use Interpolated Verbatim String" }, - { "Microsoft.CodeAnalysis.CSharp.UseIsNullCheck.CSharpUseIsNullCheckForCastAndEqualityOperatorCodeFixProvider", "Use Is Null Check: For Cast And Equality Operator" }, - { "Microsoft.CodeAnalysis.CSharp.UseIsNullCheck.CSharpUseIsNullCheckForReferenceEqualsCodeFixProvider", "Use Is Null Check: For Reference Equals" }, - { "Microsoft.CodeAnalysis.CSharp.UseIsNullCheck.CSharpUseNullCheckOverTypeCheckCodeFixProvider", "Use Is Null Check: Use Null Check Over Type Check" }, - { "Microsoft.CodeAnalysis.CSharp.UseLocalFunction.CSharpUseLocalFunctionCodeFixProvider", "Use Local Function" }, - { "Microsoft.CodeAnalysis.CSharp.UseNamedArguments.CSharpUseNamedArgumentsCodeRefactoringProvider", "Use Named Arguments (Refactoring)" }, - { "Microsoft.CodeAnalysis.CSharp.UseNullPropagation.CSharpUseNullPropagationCodeFixProvider", "Use Null Propagation" }, - { "Microsoft.CodeAnalysis.CSharp.UseObjectInitializer.CSharpUseObjectInitializerCodeFixProvider", "Use Object Initializer" }, - { "Microsoft.CodeAnalysis.CSharp.UsePatternCombinators.CSharpUsePatternCombinatorsCodeFixProvider", "Use Pattern Combinators" }, - { "Microsoft.CodeAnalysis.CSharp.UsePatternMatching.CSharpAsAndNullCheckCodeFixProvider", "Use Pattern Matching: As And Null Check" }, - { "Microsoft.CodeAnalysis.CSharp.UsePatternMatching.CSharpIsAndCastCheckCodeFixProvider", "Use Pattern Matching: Is And Cast Check" }, - { "Microsoft.CodeAnalysis.CSharp.UsePatternMatching.CSharpIsAndCastCheckWithoutNameCodeFixProvider", "Use Pattern Matching: Is And Cast Check Without Name" }, - { "Microsoft.CodeAnalysis.CSharp.UsePatternMatching.CSharpUseNotPatternCodeFixProvider", "Use Pattern Matching: Use Not Pattern" }, - { "Microsoft.CodeAnalysis.CSharp.UseSimpleUsingStatement.UseSimpleUsingStatementCodeFixProvider", "Use Simple Using Statement" }, - { "Microsoft.CodeAnalysis.CSharp.UseTupleSwap.CSharpUseTupleSwapCodeFixProvider", "Use Tuple Swap" }, - { "Microsoft.CodeAnalysis.CSharp.UseUtf8StringLiteral.UseUtf8StringLiteralCodeFixProvider", "Use UTF-8 String Literal" }, - { "Microsoft.CodeAnalysis.CSharp.Wrapping.CSharpWrappingCodeRefactoringProvider", "Wrapping (Refactoring)" }, - { "Microsoft.CodeAnalysis.DiagnosticComments.CodeFixes.CSharpAddDocCommentNodesCodeFixProvider", "Add Doc Comment Nodes" }, - { "Microsoft.CodeAnalysis.DiagnosticComments.CodeFixes.CSharpRemoveDocCommentNodeCodeFixProvider", "Remove Doc Comment Node" }, - { "Microsoft.CodeAnalysis.DiagnosticComments.CodeFixes.VisualBasicRemoveDocCommentNodeCodeFixProvider", "Remove Doc Comment Node" }, - { "Microsoft.CodeAnalysis.Editor.Implementation.RenameTracking.RenameTrackingCodeRefactoringProvider", "Rename Tracking (Refactoring)" }, - { "Microsoft.CodeAnalysis.Editor.Implementation.RenameTracking.RenameTrackingTaggerProvider+RenameTrackingCodeAction", "Rename Tracking" }, - { "Microsoft.CodeAnalysis.EncapsulateField.EncapsulateFieldRefactoringProvider", "Encapsulate Field (Refactoring)" }, - { "Microsoft.CodeAnalysis.ExtractClass.ExtractClassWithDialogCodeAction", "Extract Class: With Dialog" }, - { "Microsoft.CodeAnalysis.ExtractInterface.ExtractInterfaceCodeAction", "Extract Interface" }, - { "Microsoft.CodeAnalysis.ExtractInterface.ExtractInterfaceCodeRefactoringProvider", "Extract Interface (Refactoring)" }, - { "Microsoft.CodeAnalysis.GenerateComparisonOperators.GenerateComparisonOperatorsCodeRefactoringProvider", "Generate Comparison Operators (Refactoring)" }, - { "Microsoft.CodeAnalysis.GenerateConstructorFromMembers.AbstractGenerateConstructorFromMembersCodeRefactoringProvider+ConstructorDelegatingCodeAction", "Generate Constructor From Members: Constructor Delegating (Refactoring)" }, - { "Microsoft.CodeAnalysis.GenerateConstructorFromMembers.AbstractGenerateConstructorFromMembersCodeRefactoringProvider+FieldDelegatingCodeAction", "Generate Constructor From Members: Field Delegating (Refactoring)" }, - { "Microsoft.CodeAnalysis.GenerateConstructorFromMembers.AbstractGenerateConstructorFromMembersCodeRefactoringProvider+GenerateConstructorWithDialogCodeAction", "Generate Constructor From Members: Generate Constructor With Dialog (Refactoring)" }, - { "Microsoft.CodeAnalysis.GenerateDefaultConstructors.AbstractGenerateDefaultConstructorsService`1+CodeActionAll", "Generate Default Constructors: Code Action All" }, - { "Microsoft.CodeAnalysis.GenerateDefaultConstructors.AbstractGenerateDefaultConstructorsService`1+GenerateDefaultConstructorCodeAction", "Generate Default Constructors: Generate Default Constructor" }, - { "Microsoft.CodeAnalysis.GenerateDefaultConstructors.GenerateDefaultConstructorsCodeRefactoringProvider", "Generate Default Constructors (Refactoring)" }, - { "Microsoft.CodeAnalysis.GenerateEqualsAndGetHashCodeFromMembers.GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider", "Generate Equals And Get Hash Code From Members (Refactoring)" }, - { "Microsoft.CodeAnalysis.GenerateEqualsAndGetHashCodeFromMembers.GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider+GenerateEqualsAndGetHashCodeAction", "Generate Equals And Get Hash Code From Members: Generate Equals And Get Hash (Refactoring)" }, - { "Microsoft.CodeAnalysis.GenerateEqualsAndGetHashCodeFromMembers.GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider+GenerateEqualsAndGetHashCodeWithDialogCodeAction", "Generate Equals And Get Hash Code From Members: Generate Equals And Get Hash Code With Dialog (Refactoring)" }, - { "Microsoft.CodeAnalysis.GenerateMember.GenerateEnumMember.AbstractGenerateEnumMemberService`3+GenerateEnumMemberCodeAction", "Generate Enum Member" }, - { "Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember.AbstractGenerateParameterizedMemberService`4+GenerateParameterizedMemberCodeAction", "Generate Parameterized Member" }, - { "Microsoft.CodeAnalysis.GenerateMember.GenerateVariable.AbstractGenerateVariableService`3+GenerateLocalCodeAction", "Generate Variable: Generate Local" }, - { "Microsoft.CodeAnalysis.GenerateMember.GenerateVariable.AbstractGenerateVariableService`3+GenerateParameterCodeAction", "Generate Variable: Generate Parameter" }, - { "Microsoft.CodeAnalysis.GenerateMember.GenerateVariable.AbstractGenerateVariableService`3+GenerateVariableCodeAction", "Generate Variable" }, - { "Microsoft.CodeAnalysis.GenerateOverrides.GenerateOverridesCodeRefactoringProvider", "Generate Overrides (Refactoring)" }, - { "Microsoft.CodeAnalysis.GenerateOverrides.GenerateOverridesCodeRefactoringProvider+GenerateOverridesWithDialogCodeAction", "Generate Overrides: With Dialog (Refactoring)" }, - { "Microsoft.CodeAnalysis.GenerateType.AbstractGenerateTypeService`6+GenerateTypeCodeAction", "Generate Type" }, - { "Microsoft.CodeAnalysis.GenerateType.AbstractGenerateTypeService`6+GenerateTypeCodeActionWithOption", "Generate Type: With Option" }, - { "Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction", "Implement Interface" }, - { "Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceWithDisposePatternCodeAction", "Implement Interface: With Dispose Pattern" }, - { "Microsoft.CodeAnalysis.IntroduceVariable.AbstractIntroduceVariableService`6+IntroduceVariableAllOccurrenceCodeAction", "Introduce Variable: All Occurrence" }, - { "Microsoft.CodeAnalysis.IntroduceVariable.AbstractIntroduceVariableService`6+IntroduceVariableCodeAction", "Introduce Variable" }, - { "Microsoft.CodeAnalysis.IntroduceVariable.IntroduceVariableCodeRefactoringProvider", "Introduce Variable (Refactoring)" }, - { "Microsoft.CodeAnalysis.MoveStaticMembers.MoveStaticMembersWithDialogCodeAction", "Move Static Members: With Dialog" }, - { "Microsoft.CodeAnalysis.MoveToNamespace.AbstractMoveToNamespaceCodeAction+MoveItemsToNamespaceCodeAction", "Move To Namespace: Move Items To Namespace" }, - { "Microsoft.CodeAnalysis.MoveToNamespace.AbstractMoveToNamespaceCodeAction+MoveTypeToNamespaceCodeAction", "Move To Namespace: Move Type To Namespace" }, - { "Microsoft.CodeAnalysis.MoveToNamespace.MoveToNamespaceCodeActionProvider", "Move To Namespace" }, - { "Microsoft.CodeAnalysis.NewLines.ConsecutiveStatementPlacement.ConsecutiveStatementPlacementCodeFixProvider", "Consecutive Statement Placement" }, - { "Microsoft.CodeAnalysis.NewLines.MultipleBlankLines.MultipleBlankLinesCodeFixProvider", "Multiple Blank Lines" }, - { "Microsoft.CodeAnalysis.PreferFrameworkType.PreferFrameworkTypeCodeFixProvider", "Prefer Framework Type" }, - { "Microsoft.CodeAnalysis.RemoveRedundantEquality.RemoveRedundantEqualityCodeFixProvider", "Remove Redundant Equality" }, - { "Microsoft.CodeAnalysis.RemoveUnnecessarySuppressions.RemoveUnnecessaryAttributeSuppressionsCodeFixProvider", "Remove Unnecessary Suppressions: Remove Unnecessary Attribute Suppressions" }, - { "Microsoft.CodeAnalysis.RemoveUnnecessarySuppressions.RemoveUnnecessaryInlineSuppressionsCodeFixProvider", "Remove Unnecessary Suppressions: Remove Unnecessary Inline Suppressions" }, - { "Microsoft.CodeAnalysis.ReplaceMethodWithProperty.ReplaceMethodWithPropertyCodeRefactoringProvider", "Replace Method With Property (Refactoring)" }, - { "Microsoft.CodeAnalysis.ReplacePropertyWithMethods.ReplacePropertyWithMethodsCodeRefactoringProvider", "Replace Property With Methods (Refactoring)" }, - { "Microsoft.CodeAnalysis.SimplifyBooleanExpression.SimplifyConditionalCodeFixProvider", "Simplify Boolean Expression: Simplify Conditional" }, - { "Microsoft.CodeAnalysis.UpdateLegacySuppressions.UpdateLegacySuppressionsCodeFixProvider", "Update Legacy Suppressions" }, - { "Microsoft.CodeAnalysis.UpgradeProject.ProjectOptionsChangeAction", "Upgrade Project: Project Options Change" }, - { "Microsoft.CodeAnalysis.UseAutoProperty.AbstractUseAutoPropertyCodeFixProvider`5+UseAutoPropertyCodeAction", "Use Auto Property" }, - { "Microsoft.CodeAnalysis.UseCoalesceExpression.UseCoalesceExpressionCodeFixProvider", "Use Coalesce Expression" }, - { "Microsoft.CodeAnalysis.UseCoalesceExpression.UseCoalesceExpressionForNullableCodeFixProvider", "Use Coalesce Expression: For Nullable" }, - { "Microsoft.CodeAnalysis.UseExplicitTupleName.UseExplicitTupleNameCodeFixProvider", "Use Explicit Tuple Name" }, - { "Microsoft.CodeAnalysis.UseSystemHashCode.UseSystemHashCodeCodeFixProvider", "Use System Hash Code" }, - { "Microsoft.CodeAnalysis.UseThrowExpression.UseThrowExpressionCodeFixProvider", "Use Throw Expression" }, - { "Microsoft.CodeAnalysis.VisualBasic.AddAccessibilityModifiers.VisualBasicAddAccessibilityModifiersCodeFixProvider", "Add Accessibility Modifiers" }, - { "Microsoft.CodeAnalysis.VisualBasic.AddAnonymousTypeMemberName.VisualBasicAddAnonymousTypeMemberNameCodeFixProvider", "Add Anonymous Type Member Name" }, - { "Microsoft.CodeAnalysis.VisualBasic.AddDebuggerDisplay.VisualBasicAddDebuggerDisplayCodeRefactoringProvider", "Add Debugger Display (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.AddFileBanner.VisualBasicAddFileBannerCodeRefactoringProvider", "Add File Banner (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.AddImport.VisualBasicAddImportCodeFixProvider", "Add Import" }, - { "Microsoft.CodeAnalysis.VisualBasic.AddMissingReference.VisualBasicAddMissingReferenceCodeFixProvider", "Add Missing Reference" }, - { "Microsoft.CodeAnalysis.VisualBasic.AddObsoleteAttribute.VisualBasicAddObsoleteAttributeCodeFixProvider", "Add Obsolete Attribute" }, - { "Microsoft.CodeAnalysis.VisualBasic.AddPackage.VisualBasicAddSpecificPackageCodeFixProvider", "Add Package: Add Specific Package" }, - { "Microsoft.CodeAnalysis.VisualBasic.AddParameter.VisualBasicAddParameterCodeFixProvider", "Add Parameter" }, - { "Microsoft.CodeAnalysis.VisualBasic.AliasAmbiguousType.VisualBasicAliasAmbiguousTypeCodeFixProvider", "Alias Ambiguous Type" }, - { "Microsoft.CodeAnalysis.VisualBasic.CodeActions.RemoveStatementCodeAction", "Code Actions: Remove Statement" }, - { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.AddExplicitCast.VisualBasicAddExplicitCastCodeFixProvider", "Add Explicit Cast" }, - { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.ConvertToAsync.VisualBasicConvertToAsyncFunctionCodeFixProvider", "Convert To Async: Function" }, - { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.CorrectNextControlVariable.CorrectNextControlVariableCodeFixProvider", "Correct Next Control Variable" }, - { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.CorrectNextControlVariable.CorrectNextControlVariableCodeFixProvider+CorrectNextControlVariableCodeAction", "Correct Next Control Variable" }, - { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.FullyQualify.VisualBasicFullyQualifyCodeFixProvider", "Fully Qualify" }, - { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEndConstruct.GenerateEndConstructCodeFixProvider", "Generate End Construct" }, - { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEnumMember.GenerateEnumMemberCodeFixProvider", "Generate Enum Member" }, - { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEvent.GenerateEventCodeFixProvider", "Generate Event" }, - { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEvent.GenerateEventCodeFixProvider+GenerateEventCodeAction", "Generate Event" }, - { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateMethod.GenerateConversionCodeFixProvider", "Generate Method: Generate Conversion" }, - { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateMethod.GenerateParameterizedMemberCodeFixProvider", "Generate Method: Generate Parameterized Member" }, - { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateType.GenerateTypeCodeFixProvider", "Generate Type" }, - { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.IncorrectExitContinue.IncorrectExitContinueCodeFixProvider", "Incorrect Exit Continue" }, - { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.IncorrectExitContinue.IncorrectExitContinueCodeFixProvider+AddKeywordCodeAction", "Incorrect Exit Continue: Add Keyword" }, - { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.IncorrectExitContinue.IncorrectExitContinueCodeFixProvider+ReplaceKeywordCodeAction", "Incorrect Exit Continue: Replace Keyword" }, - { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.IncorrectExitContinue.IncorrectExitContinueCodeFixProvider+ReplaceTokenKeywordCodeAction", "Incorrect Exit Continue: Replace Token Keyword" }, - { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.IncorrectFunctionReturnType.IncorrectFunctionReturnTypeCodeFixProvider", "Incorrect Function Return Type" }, - { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.Iterator.VisualBasicChangeToYieldCodeFixProvider", "Iterator: Change To Yield" }, - { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.Iterator.VisualBasicConvertToIteratorCodeFixProvider", "Iterator: Convert To Iterator" }, - { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.MoveToTopOfFile.MoveToTopOfFileCodeFixProvider", "Move To Top Of File" }, - { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.MoveToTopOfFile.MoveToTopOfFileCodeFixProvider+MoveToLineCodeAction", "Move To Top Of File: Move To Line" }, - { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.OverloadBase.OverloadBaseCodeFixProvider", "Overload Base" }, - { "Microsoft.CodeAnalysis.VisualBasic.CodeFixes.OverloadBase.OverloadBaseCodeFixProvider+AddKeywordAction", "Overload Base: Add Keyword" }, - { "Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.AddAwait.VisualBasicAddAwaitCodeRefactoringProvider", "Add Await (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.InlineTemporary.VisualBasicInlineMethodRefactoringProvider", "Inline Temporary: Inline Method (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.InlineTemporary.VisualBasicInlineTemporaryCodeRefactoringProvider", "Inline Temporary (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.MoveStaticMembers.VisualBasicMoveStaticMembersRefactoringProvider", "Move Static Members (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.ConflictMarkerResolution.VisualBasicResolveConflictMarkerCodeFixProvider", "Conflict Marker Resolution: Resolve Conflict Marker" }, - { "Microsoft.CodeAnalysis.VisualBasic.ConvertAnonymousType.VisualBasicConvertAnonymousTypeToClassCodeRefactoringProvider", "Convert Anonymous Type: To Class (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.ConvertAnonymousTypeToTuple.VisualBasicConvertAnonymousTypeToTupleCodeRefactoringProvider", "Convert Anonymous Type To Tuple (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.ConvertAutoPropertyToFullProperty.VisualBasicConvertAutoPropertyToFullPropertyCodeRefactoringProvider", "Convert Auto Property To Full Property (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.ConvertCast.VisualBasicConvertDirectCastToTryCastCodeRefactoringProvider", "Convert Cast: Convert Direct Cast To Try Cast (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.ConvertConversionOperators.VisualBasicConvertTryCastToDirectCastCodeRefactoringProvider", "Convert Conversion Operators: Convert Try Cast To Direct Cast (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.ConvertForEachToFor.VisualBasicConvertForEachToForCodeRefactoringProvider", "Convert For Each To For (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.ConvertForToForEach.VisualBasicConvertForToForEachCodeRefactoringProvider", "Convert For To For Each (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.ConvertIfToSwitch.VisualBasicConvertIfToSwitchCodeRefactoringProvider", "Convert If To Switch (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.ConvertNumericLiteral.VisualBasicConvertNumericLiteralCodeRefactoringProvider", "Convert Numeric Literal (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.ConvertToInterpolatedString.VisualBasicConvertConcatenationToInterpolatedStringRefactoringProvider", "Convert To Interpolated String: Convert Concatenation To Interpolated String (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.ConvertToInterpolatedString.VisualBasicConvertPlaceholderToInterpolatedStringRefactoringProvider", "Convert To Interpolated String: Convert Placeholder To Interpolated String (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.ConvertTupleToStruct.VisualBasicConvertTupleToStructCodeRefactoringProvider", "Convert Tuple To Struct (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.ConvertTypeOfToNameOf.VisualBasicConvertGetTypeToNameOfCodeFixProvider", "Convert Type Of To Name Of: Convert Get Type To Name Of" }, - { "Microsoft.CodeAnalysis.VisualBasic.Features.EmbeddedLanguages.VisualBasicJsonDetectionCodeFixProvider", "Embedded Languages: Json Detection" }, - { "Microsoft.CodeAnalysis.VisualBasic.FileHeaders.VisualBasicFileHeaderCodeFixProvider", "File Headers: File Header" }, - { "Microsoft.CodeAnalysis.VisualBasic.GenerateConstructor.GenerateConstructorCodeFixProvider", "Generate Constructor" }, - { "Microsoft.CodeAnalysis.VisualBasic.GenerateConstructorFromMembers.VisualBasicGenerateConstructorFromMembersCodeRefactoringProvider", "Generate Constructor From Members (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.GenerateDefaultConstructors.VisualBasicGenerateDefaultConstructorsCodeFixProvider", "Generate Default Constructors" }, - { "Microsoft.CodeAnalysis.VisualBasic.GenerateVariable.VisualBasicGenerateVariableCodeFixProvider", "Generate Variable" }, - { "Microsoft.CodeAnalysis.VisualBasic.ImplementAbstractClass.VisualBasicImplementAbstractClassCodeFixProvider", "Implement Abstract Class" }, - { "Microsoft.CodeAnalysis.VisualBasic.ImplementInterface.VisualBasicImplementInterfaceCodeFixProvider", "Implement Interface" }, - { "Microsoft.CodeAnalysis.VisualBasic.InitializeParameter.VisualBasicAddParameterCheckCodeRefactoringProvider", "Initialize Parameter: Add Parameter Check (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.InitializeParameter.VisualBasicInitializeMemberFromParameterCodeRefactoringProvider", "Initialize Parameter: Initialize Member From Parameter (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.IntroduceUsingStatement.VisualBasicIntroduceUsingStatementCodeRefactoringProvider", "Introduce Using Statement (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable.VisualBasicIntroduceLocalForExpressionCodeRefactoringProvider", "Introduce Variable: Introduce Local For Expression (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable.VisualBasicIntroduceParameterCodeRefactoringProvider", "Introduce Variable: Introduce Parameter (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.InvertConditional.VisualBasicInvertConditionalCodeRefactoringProvider", "Invert Conditional (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.InvertIf.VisualBasicInvertMultiLineIfCodeRefactoringProvider", "Invert If: Invert Multi Line If (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.InvertIf.VisualBasicInvertSingleLineIfCodeRefactoringProvider", "Invert If: Invert Single Line If (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.InvertLogical.VisualBasicInvertLogicalCodeRefactoringProvider", "Invert Logical (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.MakeFieldReadonly.VisualBasicMakeFieldReadonlyCodeFixProvider", "Make Field Readonly" }, - { "Microsoft.CodeAnalysis.VisualBasic.MakeMethodAsynchronous.VisualBasicMakeMethodAsynchronousCodeFixProvider", "Make Method Asynchronous" }, - { "Microsoft.CodeAnalysis.VisualBasic.MakeMethodSynchronous.VisualBasicMakeMethodSynchronousCodeFixProvider", "Make Method Synchronous" }, - { "Microsoft.CodeAnalysis.VisualBasic.MakeTypeAbstract.VisualBasicMakeTypeAbstractCodeFixProvider", "Make Type Abstract" }, - { "Microsoft.CodeAnalysis.VisualBasic.MoveDeclarationNearReference.VisualBasicMoveDeclarationNearReferenceCodeRefactoringProvider", "Move Declaration Near Reference (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.NameTupleElement.VisualBasicNameTupleElementCodeRefactoringProvider", "Name Tuple Element (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.OrderModifiers.VisualBasicOrderModifiersCodeFixProvider", "Order Modifiers" }, - { "Microsoft.CodeAnalysis.VisualBasic.PopulateSwitch.VisualBasicPopulateSwitchStatementCodeFixProvider", "Populate Switch: Statement" }, - { "Microsoft.CodeAnalysis.VisualBasic.QualifyMemberAccess.VisualBasicQualifyMemberAccessCodeFixProvider", "Qualify Member Access" }, - { "Microsoft.CodeAnalysis.VisualBasic.RemoveAsyncModifier.VisualBasicRemoveAsyncModifierCodeFixProvider", "Remove Async Modifier" }, - { "Microsoft.CodeAnalysis.VisualBasic.RemoveSharedFromModuleMembers.VisualBasicRemoveSharedFromModuleMembersCodeFixProvider", "Remove Shared From Module Members" }, - { "Microsoft.CodeAnalysis.VisualBasic.RemoveUnnecessaryByVal.VisualBasicRemoveUnnecessaryByValCodeFixProvider", "Remove Unnecessary By Val" }, - { "Microsoft.CodeAnalysis.VisualBasic.RemoveUnnecessaryCast.VisualBasicRemoveUnnecessaryCastCodeFixProvider", "Remove Unnecessary Cast" }, - { "Microsoft.CodeAnalysis.VisualBasic.RemoveUnnecessaryImports.VisualBasicRemoveUnnecessaryImportsCodeFixProvider", "Remove unnecessary imports" }, - { "Microsoft.CodeAnalysis.VisualBasic.RemoveUnnecessaryParentheses.VisualBasicRemoveUnnecessaryParenthesesCodeFixProvider", "Remove Unnecessary Parentheses" }, - { "Microsoft.CodeAnalysis.VisualBasic.RemoveUnusedMembers.VisualBasicRemoveUnusedMembersCodeFixProvider", "Remove Unused Members" }, - { "Microsoft.CodeAnalysis.VisualBasic.RemoveUnusedParametersAndValues.VisualBasicRemoveUnusedValuesCodeFixProvider", "Remove Unused Parameters And Values: Remove Unused Values" }, - { "Microsoft.CodeAnalysis.VisualBasic.RemoveUnusedVariable.VisualBasicRemoveUnusedVariableCodeFixProvider", "Remove Unused Variable" }, - { "Microsoft.CodeAnalysis.VisualBasic.ReplaceConditionalWithStatements.VisualBasicReplaceConditionalWithStatementsCodeRefactoringProvider", "Replace Conditional With Statements (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.ReplaceDocCommentTextWithTag.VisualBasicReplaceDocCommentTextWithTagCodeRefactoringProvider", "Replace Doc Comment Text With Tag (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.SimplifyInterpolation.VisualBasicSimplifyInterpolationCodeFixProvider", "Simplify Interpolation" }, - { "Microsoft.CodeAnalysis.VisualBasic.SimplifyLinqExpression.SimplifyLinqExpressionCodeFixProvider", "Simplify Linq Expression" }, - { "Microsoft.CodeAnalysis.VisualBasic.SimplifyObjectCreation.VisualBasicSimplifyObjectCreationCodeFixProvider", "Simplify Object Creation" }, - { "Microsoft.CodeAnalysis.VisualBasic.SimplifyThisOrMe.VisualBasicSimplifyThisOrMeCodeFixProvider", "Simplify This Or Me" }, - { "Microsoft.CodeAnalysis.VisualBasic.SimplifyTypeNames.SimplifyTypeNamesCodeFixProvider", "Simplify Type Names" }, - { "Microsoft.CodeAnalysis.VisualBasic.SpellCheck.VisualBasicSpellCheckCodeFixProvider", "Spell Check" }, - { "Microsoft.CodeAnalysis.VisualBasic.SplitOrMergeIfStatements.VisualBasicMergeConsecutiveIfStatementsCodeRefactoringProvider", "Split Or Merge If Statements: Merge Consecutive If Statements (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.SplitOrMergeIfStatements.VisualBasicMergeNestedIfStatementsCodeRefactoringProvider", "Split Or Merge If Statements: Merge Nested If Statements (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.SplitOrMergeIfStatements.VisualBasicSplitIntoConsecutiveIfStatementsCodeRefactoringProvider", "Split Or Merge If Statements: Split Into Consecutive If Statements (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.SplitOrMergeIfStatements.VisualBasicSplitIntoNestedIfStatementsCodeRefactoringProvider", "Split Or Merge If Statements: Split Into Nested If Statements (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.UnsealClass.VisualBasicUnsealClassCodeFixProvider", "Unseal Class" }, - { "Microsoft.CodeAnalysis.VisualBasic.UseAutoProperty.VisualBasicUseAutoPropertyCodeFixProvider", "Use Auto Property" }, - { "Microsoft.CodeAnalysis.VisualBasic.UseCollectionInitializer.VisualBasicUseCollectionInitializerCodeFixProvider", "Use Collection Initializer" }, - { "Microsoft.CodeAnalysis.VisualBasic.UseCompoundAssignment.VisualBasicUseCompoundAssignmentCodeFixProvider", "Use Compound Assignment" }, - { "Microsoft.CodeAnalysis.VisualBasic.UseConditionalExpression.VisualBasicUseConditionalExpressionForAssignmentCodeFixProvider", "Use Conditional Expression: For Assignment" }, - { "Microsoft.CodeAnalysis.VisualBasic.UseConditionalExpression.VisualBasicUseConditionalExpressionForReturnCodeFixProvider", "Use Conditional Expression: For Return" }, - { "Microsoft.CodeAnalysis.VisualBasic.UseInferredMemberName.VisualBasicUseInferredMemberNameCodeFixProvider", "Use Inferred Member Name" }, - { "Microsoft.CodeAnalysis.VisualBasic.UseIsNotExpression.VisualBasicUseIsNotExpressionCodeFixProvider", "Use Is Not Expression" }, - { "Microsoft.CodeAnalysis.VisualBasic.UseIsNullCheck.VisualBasicUseIsNullCheckForReferenceEqualsCodeFixProvider", "Use Is Null Check: For Reference Equals" }, - { "Microsoft.CodeAnalysis.VisualBasic.UseNamedArguments.VisualBasicUseNamedArgumentsCodeRefactoringProvider", "Use Named Arguments (Refactoring)" }, - { "Microsoft.CodeAnalysis.VisualBasic.UseNullPropagation.VisualBasicUseNullPropagationCodeFixProvider", "Use Null Propagation" }, - { "Microsoft.CodeAnalysis.VisualBasic.UseObjectInitializer.VisualBasicUseObjectInitializerCodeFixProvider", "Use Object Initializer" }, - { "Microsoft.CodeAnalysis.VisualBasic.Wrapping.VisualBasicWrappingCodeRefactoringProvider", "Wrapping (Refactoring)" }, - { "Microsoft.CodeAnalysis.Wrapping.WrapItemsAction", "Wrapping: Wrap Items" }, - { "VisualBasicAddMissingImportsRefactoringProvider", "Add Missing Imports (Refactoring)" }, - }.ToImmutableDictionary(); - - public static void Main(string[] args) + WriteCodeActionDescriptionMap(telemetryInfos); + + Console.WriteLine("Please update the CodeActionDescriptions.cs file and re-run the tool."); + } + else { - Console.WriteLine("Loading assemblies and finding CodeActions ..."); + WriteKustoDatatable(codeActionAndProviderTypes, telemetryInfos); + } - var assemblies = GetAssemblies(args); - var codeActionAndProviderTypes = GetCodeActionAndProviderTypes(assemblies); + Console.WriteLine("Complete."); + static void WriteKustoDatatable(ImmutableArray codeActionAndProviderTypes, ImmutableArray<(string TypeName, string Hash)> telemetryInfos) + { Console.WriteLine($"Generating Kusto datatable of {codeActionAndProviderTypes.Length} CodeAction and provider hashes ..."); - var telemetryInfos = GetTelemetryInfos(codeActionAndProviderTypes); - var datatable = GenerateKustoDatatable(telemetryInfos); // GenerateCodeActionsDescriptionMap(telemetryInfos); + var datatable = GenerateKustoDatatable(telemetryInfos); var filepath = Path.GetFullPath("ActionTable.txt"); Console.WriteLine($"Writing datatable to {filepath} ..."); File.WriteAllText(filepath, datatable); - - Console.WriteLine("Complete."); } - internal static ImmutableArray GetAssemblies(string[] paths) + static void WriteCodeActionDescriptionMap(ImmutableArray<(string TypeName, string Hash)> telemetryInfos) { - if (paths.Length == 0) - { - // By default inspect the Roslyn assemblies - paths = Directory.EnumerateFiles(s_executingPath, "Microsoft.CodeAnalysis*.dll") - .ToArray(); - } + Console.WriteLine($"Generating new CodeAction Description Map ..."); - var currentDirectory = new Uri(Environment.CurrentDirectory + "\\"); - return paths.Select(path => - { - Console.WriteLine($"Loading assembly from {GetRelativePath(path, currentDirectory)}."); - return Assembly.LoadFrom(path); - }).ToImmutableArray(); + var descriptionMap = GenerateCodeActionsDescriptionMap(telemetryInfos); - static string GetRelativePath(string path, Uri baseUri) - { - var rootedPath = Path.IsPathRooted(path) - ? path - : Path.GetFullPath(path); - var relativePath = baseUri.MakeRelativeUri(new Uri(rootedPath)); - return relativePath.ToString(); - } + var filepath = Path.GetFullPath("CodeActionDescriptions.Review.cs"); + + Console.WriteLine($"Writing code file to {filepath} ..."); + + File.WriteAllText(filepath, descriptionMap); } + } - internal static ImmutableArray GetCodeActionAndProviderTypes(IEnumerable assemblies) + internal static ImmutableArray GetAssemblies(string[] paths) + { + if (paths.Length == 0) { - var types = assemblies.SelectMany( - assembly => assembly.GetTypes().Where( - type => !type.GetTypeInfo().IsInterface && !type.GetTypeInfo().IsAbstract)); - - return types - .Where(t => isCodeActionType(t) || isCodeActionProviderType(t)) - .ToImmutableArray(); + // By default inspect the Roslyn assemblies + paths = [.. Directory.EnumerateFiles(s_executingPath, "Microsoft.CodeAnalysis*.dll")]; + } - static bool isCodeActionType(Type t) => typeof(CodeAction).IsAssignableFrom(t); + var currentDirectory = new Uri(Environment.CurrentDirectory + "\\"); + return [.. paths.Select(path => + { + Console.WriteLine($"Loading assembly from {GetRelativePath(path, currentDirectory)}."); + return Assembly.LoadFrom(path); + })]; - static bool isCodeActionProviderType(Type t) => typeof(CodeFixProvider).IsAssignableFrom(t) - || typeof(CodeRefactoringProvider).IsAssignableFrom(t); + static string GetRelativePath(string path, Uri baseUri) + { + var rootedPath = Path.IsPathRooted(path) + ? path + : Path.GetFullPath(path); + var relativePath = baseUri.MakeRelativeUri(new Uri(rootedPath)); + return relativePath.ToString(); } + } + + internal static ImmutableArray GetCodeActionAndProviderTypes(IEnumerable assemblies) + { + var types = assemblies.SelectMany( + assembly => assembly.GetTypes().Where( + type => !type.GetTypeInfo().IsInterface && !type.GetTypeInfo().IsAbstract)); + + return [.. types.Where(t => IsCodeActionType(t) || IsCodeActionProviderType(t))]; - internal static ImmutableArray<(string TypeName, string Hash)> GetTelemetryInfos(ImmutableArray codeActionAndProviderTypes) + static bool IsCodeActionType(Type t) => typeof(CodeAction).IsAssignableFrom(t); + + static bool IsCodeActionProviderType(Type t) => typeof(CodeFixProvider).IsAssignableFrom(t) + || typeof(CodeRefactoringProvider).IsAssignableFrom(t); + } + + internal static ImmutableArray<(string TypeName, string Hash)> GetTelemetryInfos(ImmutableArray codeActionAndProviderTypes) + { + return [.. codeActionAndProviderTypes + .Distinct(FullNameTypeComparer.Instance) + .Select(GetTelemetryInfo) + .OrderBy(info => info.TypeName)]; + + static (string TypeName, string Hash) GetTelemetryInfo(Type type) { - return codeActionAndProviderTypes - .Distinct(FullNameTypeComparer.Instance) - .Select(GetTelemetryInfo) - .OrderBy(info => info.TypeName) - .ToImmutableArray(); + // Generate dev17 telemetry hash + var telemetryId = type.GetTelemetryId().ToString(); + var fnvHash = telemetryId.Substring(19); + + return (type.FullName!, fnvHash); + } + } + + internal static bool IsDescriptionMapComplete(ImmutableArray<(string TypeName, string Hash)> telemetryInfos) + { + var missingDescriptions = new List(); - static (string TypeName, string Hash) GetTelemetryInfo(Type type) + foreach (var (actionTypeName, _) in telemetryInfos) + { + if (IgnoredCodeActions.Contains(actionTypeName)) { - // Generate dev17 telemetry hash - var telemetryId = type.GetTelemetryId().ToString(); - var fnvHash = telemetryId.Substring(19); + continue; + } - return (type.FullName!, fnvHash); + if (!CodeActionDescriptionMap.TryGetValue(actionTypeName, out var description)) + { + missingDescriptions.Add(actionTypeName); } } - internal static string GenerateKustoDatatable(ImmutableArray<(string TypeName, string Hash)> telemetryInfos) + if (missingDescriptions.Count == 0) { - var missingDescriptions = new List(); + return true; + } - var table = new StringBuilder(); + Console.WriteLine($"The following Actions are new and need their description reviewed:{Environment.NewLine}{string.Join(Environment.NewLine, missingDescriptions)}"); - table.AppendLine("let actions = datatable(Description: string, ActionName: string, FnvHash: string)"); - table.AppendLine("["); + return false; + } - foreach (var (actionTypeName, fnvHash) in telemetryInfos) - { - if (IgnoredCodeActions.Contains(actionTypeName)) - { - continue; - } + internal static string GenerateKustoDatatable(ImmutableArray<(string TypeName, string Hash)> telemetryInfos) + { + var table = new StringBuilder(); - if (!CodeActionDescriptionMap.TryGetValue(actionTypeName, out var description)) - { - description = "**MISSING**"; - missingDescriptions.Add(actionTypeName); - } + table.AppendLine("let actions = datatable(Description: string, ActionName: string, FnvHash: string)"); + table.AppendLine("["); - table.AppendLine(@$" ""{description}"", ""{actionTypeName}"", ""{fnvHash}"","); + foreach (var (actionTypeName, fnvHash) in telemetryInfos) + { + if (IgnoredCodeActions.Contains(actionTypeName)) + { + continue; } - table.Append("];"); - - if (missingDescriptions.Count > 0) + if (!CodeActionDescriptionMap.TryGetValue(actionTypeName, out var description)) { - Console.WriteLine($"Descriptions were missing for the following type names:{Environment.NewLine}{string.Join(Environment.NewLine, missingDescriptions)}"); + description = $"**NEEDS REVIEW** {GenerateCodeActionDescription(actionTypeName)}"; } - return table.ToString(); + table.AppendLine(@$" ""{description}"", ""{actionTypeName}"", ""{fnvHash}"","); } - // NOTE: This method is unused but still present in case we want to auto-generate and refresh the "CodeActionsDescriptionMap". - internal static string GenerateCodeActionsDescriptionMap(ImmutableArray<(string TypeName, string Hash)> telemetryInfos) - { - var builder = new StringBuilder(); + table.Append("];"); - builder.AppendLine("{"); - - // Regex to split where letter capitalization changes. Try not to split up interface names such as IEnumerable. - var regex = new Regex(@" - (?<=[I])(?=[A-Z]) & - (?<=[A-Z])(?=[A-Z][a-z]) | - (?<=[^A-Z])(?=[A-Z]) | - (?<=[A-Za-z])(?=[^A-Za-z])", RegexOptions.IgnorePatternWhitespace); + return table.ToString(); + } - // Prefixes and suffixes to trim out. - var prefixStrings = new[] - { - "Abstract", - "CSharp", - "VisualBasic", - "CodeFixes", - "CodeStyle", - "TypeStyle", - }; - - var suffixStrings = new[] - { - "CodeFixProvider", - "CodeRefactoringProvider", - "RefactoringProvider", - "TaggerProvider", - "CustomCodeAction", - "CodeAction", - "CodeActionWithOption", - "CodeActionProvider", - "Action", - "FeatureService", - "Service", - "ProviderHelpers", - "Provider", - }; - - foreach (var (actionOrProviderTypeName, _) in telemetryInfos) + internal static string GenerateCodeActionsDescriptionMap(ImmutableArray<(string TypeName, string Hash)> telemetryInfos) + { + var builder = new StringBuilder(); + + builder.AppendLine("// Licensed to the .NET Foundation under one or more agreements."); + builder.AppendLine("// The .NET Foundation licenses this file to you under the MIT license."); + builder.AppendLine("// See the LICENSE file in the project root for more information."); + builder.AppendLine(); + builder.AppendLine("using System.Collections.Immutable;"); + builder.AppendLine("using System.Collections.Generic;"); + builder.AppendLine(); + builder.AppendLine("namespace BuildActionTelemetryTable;"); + builder.AppendLine(); + builder.AppendLine("internal static class CodeActionDescriptions"); + builder.AppendLine("{"); + + builder.AppendLine(" public static ImmutableDictionary CodeActionDescriptionMap { get; } = new Dictionary()"); + builder.AppendLine(" {"); + + foreach (var (actionOrProviderTypeName, _) in telemetryInfos) + { + if (IgnoredCodeActions.Contains(actionOrProviderTypeName)) { - if (IgnoredCodeActions.Contains(actionOrProviderTypeName)) - { - continue; - } - - // We create the description string from the namespace and type name after omitting the well-known prefixes and suffixes. - var descriptionParts = actionOrProviderTypeName.Replace('.', '+').Split('+'); + continue; + } - // When there is deep nesting, construct the descriptions from the inner two names. - var startIndex = Math.Max(0, descriptionParts.Length - 2); + if (!CodeActionDescriptionMap.TryGetValue(actionOrProviderTypeName, out var description)) + { + description = $"**NEEDS REVIEW** {GenerateCodeActionDescription(actionOrProviderTypeName)}"; + } - var description = string.Empty; - var isRefactoring = false; + builder.AppendLine(@$" {{ ""{actionOrProviderTypeName}"", ""{description}"" }},"); + } - for (int index = startIndex; index < descriptionParts.Length; index++) - { - var part = descriptionParts[index]; + builder.AppendLine(" }.ToImmutableDictionary();"); + builder.AppendLine("}"); - // Remove TypeParameter count - if (part.Contains('`')) - { - part = part.Split('`')[0]; - } + return builder.ToString(); + } - foreach (var prefix in prefixStrings) - { - if (part.StartsWith(prefix)) - { - part = part.Substring(prefix.Length); - break; - } - } + private static string GenerateCodeActionDescription(string actionOrProviderTypeName) + { + // Regex to split where letter capitalization changes. Try not to split up interface names such as IEnumerable. + var regex = ChangeOfCaseRegex(); - foreach (var suffix in suffixStrings) - { - if (part.EndsWith(suffix)) - { - part = part.Substring(0, part.LastIndexOf(suffix)); - - if (suffix == "CodeActionWithOption") - { - part += "WithOption"; - } - else if (suffix == "CodeRefactoringProvider" || suffix == "RefactoringProvider") - { - isRefactoring = true; - } - - break; - } - } + // Prefixes and suffixes to trim out. + var prefixStrings = new[] + { + "Abstract", + "CSharp", + "VisualBasic", + "CodeFixes", + "CodeStyle", + "TypeStyle", + }; + + var suffixStrings = new[] + { + "CodeFixProvider", + "CodeRefactoringProvider", + "RefactoringProvider", + "TaggerProvider", + "CustomCodeAction", + "CodeAction", + "CodeActionWithOption", + "CodeActionProvider", + "Action", + "FeatureService", + "Service", + "ProviderHelpers", + "Provider", + }; + + // We create the description string from the namespace and type name after omitting the well-known prefixes and suffixes. + var descriptionParts = actionOrProviderTypeName.Replace('.', '+').Split('+'); + + // When there is deep nesting, construct the descriptions from the inner two names. + var startIndex = Math.Max(0, descriptionParts.Length - 2); + + var description = string.Empty; + var isRefactoring = false; + + for (var index = startIndex; index < descriptionParts.Length; index++) + { + var part = descriptionParts[index]; - if (part.Length == 0) - { - continue; - } + // Remove TypeParameter count + if (part.Contains('`')) + { + part = part.Split('`')[0]; + } - // Split type name into words - part = regex.Replace(part, " "); + foreach (var prefix in prefixStrings) + { + if (part.StartsWith(prefix)) + { + part = part.Substring(prefix.Length); + break; + } + } - if (description.Length == 0) - { - description = part; - continue; - } + foreach (var suffix in suffixStrings) + { + if (part.EndsWith(suffix)) + { + part = part.Substring(0, part.LastIndexOf(suffix)); - if (description == part) + if (suffix == "CodeActionWithOption") { - // Don't repeat the containing type name. - continue; + part += "WithOption"; } - - if (part.StartsWith(description)) + else if (suffix == "CodeRefactoringProvider" || suffix == "RefactoringProvider") { - // Don't repeat the containing type name. - part = part.Substring(description.Length).TrimStart(); + isRefactoring = true; } - description = $"{description}: {part}"; + break; } + } - if (isRefactoring) - { - // Ensure we differentiate refactorings from similar named fixes. - description += " (Refactoring)"; - } + if (part.Length == 0) + { + continue; + } + + // Split type name into words + part = regex.Replace(part, " "); + + if (description.Length == 0) + { + description = part; + continue; + } - builder.AppendLine(@$" {{ ""{actionOrProviderTypeName}"", ""{description}"" }},"); + if (description == part) + { + // Don't repeat the containing type name. + continue; } - builder.Append('}'); + if (part.StartsWith(description)) + { + // Don't repeat the containing type name. + part = part.Substring(description.Length).TrimStart(); + } - return builder.ToString(); + description = $"{description}: {part}"; } - private class FullNameTypeComparer : IEqualityComparer + if (isRefactoring) { - public static FullNameTypeComparer Instance { get; } = new FullNameTypeComparer(); + // Ensure we differentiate refactorings from similar named fixes. + description += " (Refactoring)"; + } + + return description; + } - public bool Equals(Type? x, Type? y) - => Equals(x?.FullName, y?.FullName); + private class FullNameTypeComparer : IEqualityComparer + { + public static FullNameTypeComparer Instance { get; } = new FullNameTypeComparer(); - public int GetHashCode([DisallowNull] Type obj) - { - return obj.FullName!.GetHashCode(); - } + public bool Equals(Type? x, Type? y) + => Equals(x?.FullName, y?.FullName); + + public int GetHashCode([DisallowNull] Type obj) + { + return obj.FullName!.GetHashCode(); } } + + [GeneratedRegex(""" + (?<=[I])(?=[A-Z]) & + (?<=[A-Z])(?=[A-Z][a-z]) | + (?<=[^A-Z])(?=[A-Z]) | + (?<=[A-Za-z])(?=[^A-Za-z]) + """, RegexOptions.IgnorePatternWhitespace)] + private static partial Regex ChangeOfCaseRegex(); } diff --git a/src/Tools/ExternalAccess/Razor/Cohost/IRazorCohostClientLanguageServerManager.cs b/src/Tools/ExternalAccess/Razor/Cohost/IRazorCohostClientLanguageServerManager.cs deleted file mode 100644 index 40f56f01e0c85..0000000000000 --- a/src/Tools/ExternalAccess/Razor/Cohost/IRazorCohostClientLanguageServerManager.cs +++ /dev/null @@ -1,19 +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.LanguageServer; - -namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost -{ - internal interface IRazorCohostClientLanguageServerManager : ILspService - { - ValueTask SendNotificationAsync(string methodName, CancellationToken cancellationToken); - ValueTask SendNotificationAsync(string methodName, TParams @params, CancellationToken cancellationToken); - ValueTask SendRequestAsync(string methodName, CancellationToken cancellationToken); - Task SendRequestAsync(string methodName, TParams @params, CancellationToken cancellationToken); - ValueTask SendRequestAsync(string methodName, TParams @params, CancellationToken cancellationToken); - } -} diff --git a/src/Tools/ExternalAccess/Razor/ChecksumWrapper.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/ChecksumWrapper.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/ChecksumWrapper.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/ChecksumWrapper.cs diff --git a/src/Tools/ExternalAccess/Razor/Cohost/AbstractRazorCohostDocumentRequestHandler.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/AbstractRazorCohostDocumentRequestHandler.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Cohost/AbstractRazorCohostDocumentRequestHandler.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/AbstractRazorCohostDocumentRequestHandler.cs diff --git a/src/Tools/ExternalAccess/Razor/Cohost/AbstractRazorLspService.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/AbstractRazorLspService.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Cohost/AbstractRazorLspService.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/AbstractRazorLspService.cs diff --git a/src/Tools/ExternalAccess/Razor/Cohost/AbstractRazorRequestHandler.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/AbstractRazorRequestHandler.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Cohost/AbstractRazorRequestHandler.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/AbstractRazorRequestHandler.cs diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Constants.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Constants.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Cohost/Constants.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Constants.cs diff --git a/src/Tools/ExternalAccess/Razor/Cohost/ExportCohostLspServiceFactoryAttribute.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/ExportCohostLspServiceFactoryAttribute.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Cohost/ExportCohostLspServiceFactoryAttribute.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/ExportCohostLspServiceFactoryAttribute.cs diff --git a/src/Tools/ExternalAccess/Razor/Cohost/ExportCohostStatelessLspServiceAttribute.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/ExportCohostStatelessLspServiceAttribute.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Cohost/ExportCohostStatelessLspServiceAttribute.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/ExportCohostStatelessLspServiceAttribute.cs diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/CodeActions.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/CodeActions.cs similarity index 99% rename from src/Tools/ExternalAccess/Razor/Cohost/Handlers/CodeActions.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/CodeActions.cs index 1fe5e62b48853..a245ee3da8b32 100644 --- a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/CodeActions.cs +++ b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/CodeActions.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.LanguageServer.Handler; using Microsoft.CodeAnalysis.LanguageServer.Handler.CodeActions; using Roslyn.LanguageServer.Protocol; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost.Handlers; diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/Completion.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/Completion.cs similarity index 98% rename from src/Tools/ExternalAccess/Razor/Cohost/Handlers/Completion.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/Completion.cs index 873ee420ca5ae..6498b9ca8adce 100644 --- a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/Completion.cs +++ b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/Completion.cs @@ -24,7 +24,7 @@ internal static class Completion private static CompletionListCache GetCache() => s_completionListCache ??= InterlockedOperations.Initialize(ref s_completionListCache, () => new()); - public static async Task GetCompletionListAsync( + public static async Task GetCompletionListAsync( Document document, LinePosition linePosition, LSP.CompletionContext? completionContext, diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/Diagnostics.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/Diagnostics.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Cohost/Handlers/Diagnostics.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/Diagnostics.cs diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/DocumentHighlights.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/DocumentHighlights.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Cohost/Handlers/DocumentHighlights.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/DocumentHighlights.cs diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/DocumentSpellCheck.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/DocumentSpellCheck.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Cohost/Handlers/DocumentSpellCheck.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/DocumentSpellCheck.cs diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/DocumentSymbols.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/DocumentSymbols.cs similarity index 98% rename from src/Tools/ExternalAccess/Razor/Cohost/Handlers/DocumentSymbols.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/DocumentSymbols.cs index dfc26d5ecce9e..24a871204fa66 100644 --- a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/DocumentSymbols.cs +++ b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/DocumentSymbols.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.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.LanguageServer.Handler; diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/FindAllReferences.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/FindAllReferences.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Cohost/Handlers/FindAllReferences.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/FindAllReferences.cs diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/FoldingRanges.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/FoldingRanges.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Cohost/Handlers/FoldingRanges.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/FoldingRanges.cs diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/GoToDefinition.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/GoToDefinition.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Cohost/Handlers/GoToDefinition.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/GoToDefinition.cs diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/GoToImplementation.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/GoToImplementation.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Cohost/Handlers/GoToImplementation.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/GoToImplementation.cs diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/Hover.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/Hover.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Cohost/Handlers/Hover.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/Hover.cs diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/InlayHints.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/InlayHints.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Cohost/Handlers/InlayHints.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/InlayHints.cs diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/OnAutoInsert.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/OnAutoInsert.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Cohost/Handlers/OnAutoInsert.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/OnAutoInsert.cs diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/Rename.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/Rename.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Cohost/Handlers/Rename.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/Rename.cs diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/SemanticTokensRange.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/SemanticTokensRange.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Cohost/Handlers/SemanticTokensRange.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/SemanticTokensRange.cs diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/SignatureHelp.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/SignatureHelp.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Cohost/Handlers/SignatureHelp.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/SignatureHelp.cs diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/ValidateBreakableRange.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/ValidateBreakableRange.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Cohost/Handlers/ValidateBreakableRange.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/Handlers/ValidateBreakableRange.cs diff --git a/src/Tools/ExternalAccess/Razor/Cohost/IRazorCohostDynamicRegistrationService.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/IRazorCohostDynamicRegistrationService.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Cohost/IRazorCohostDynamicRegistrationService.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/IRazorCohostDynamicRegistrationService.cs diff --git a/src/Tools/ExternalAccess/Razor/Cohost/IRazorCustomMessageTarget.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/IRazorCustomMessageTarget.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Cohost/IRazorCustomMessageTarget.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/IRazorCustomMessageTarget.cs diff --git a/src/Tools/ExternalAccess/Razor/Cohost/IRazorSemanticTokensRefreshQueue.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/IRazorSemanticTokensRefreshQueue.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Cohost/IRazorSemanticTokensRefreshQueue.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/IRazorSemanticTokensRefreshQueue.cs diff --git a/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/RazorClientLanguageServerManagerFactory.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/RazorClientLanguageServerManagerFactory.cs new file mode 100644 index 0000000000000..add71370018ba --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/RazorClientLanguageServerManagerFactory.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; +using System.Composition; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.LanguageServer; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost; + +[Shared] +[ExportCohostLspServiceFactory(typeof(IRazorClientLanguageServerManager))] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal class RazorClientLanguageServerManagerFactory() : ILspServiceFactory +{ + public ILspService CreateILspService(LspServices lspServices, WellKnownLspServerKinds serverKind) + { + var notificationManager = lspServices.GetRequiredService(); + + return new RazorClientLanguageServerManager(notificationManager); + } +} diff --git a/src/Tools/ExternalAccess/Razor/Cohost/RazorCohostClientLanguageServerManagerFactory.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/RazorCohostClientLanguageServerManagerFactory.cs similarity index 91% rename from src/Tools/ExternalAccess/Razor/Cohost/RazorCohostClientLanguageServerManagerFactory.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/RazorCohostClientLanguageServerManagerFactory.cs index 2a06fa9b68cbd..67480de030be4 100644 --- a/src/Tools/ExternalAccess/Razor/Cohost/RazorCohostClientLanguageServerManagerFactory.cs +++ b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/RazorCohostClientLanguageServerManagerFactory.cs @@ -19,6 +19,6 @@ public ILspService CreateILspService(LspServices lspServices, WellKnownLspServer { var notificationManager = lspServices.GetRequiredService(); - return new RazorCohostClientLanguageServerManager(notificationManager); + return new RazorClientLanguageServerManager(notificationManager); } } diff --git a/src/Tools/ExternalAccess/Razor/Cohost/RazorCohostRequestContext.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/RazorCohostRequestContext.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Cohost/RazorCohostRequestContext.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/RazorCohostRequestContext.cs diff --git a/src/Tools/ExternalAccess/Razor/Cohost/RazorDynamicRegistrationServiceFactory.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/RazorDynamicRegistrationServiceFactory.cs similarity index 86% rename from src/Tools/ExternalAccess/Razor/Cohost/RazorDynamicRegistrationServiceFactory.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/RazorDynamicRegistrationServiceFactory.cs index 3b12143b2c23a..398ab41cf682b 100644 --- a/src/Tools/ExternalAccess/Razor/Cohost/RazorDynamicRegistrationServiceFactory.cs +++ b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/RazorDynamicRegistrationServiceFactory.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServer; using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Microsoft.VisualStudio.Threading; using Roslyn.LanguageServer.Protocol; using Roslyn.Utilities; @@ -66,23 +67,25 @@ public Task OnInitializedAsync(ClientCapabilities clientCapabilities, RequestCon void InitializeRazor() { - this.InitializeRazor(clientCapabilities, context, _disposalTokenSource.Token); + this.InitializeRazorAsync(clientCapabilities, context, _disposalTokenSource.Token).ReportNonFatalErrorAsync(); } } - private void InitializeRazor(ClientCapabilities clientCapabilities, RequestContext context, CancellationToken cancellationToken) + private async Task InitializeRazorAsync(ClientCapabilities clientCapabilities, RequestContext context, CancellationToken cancellationToken) { // The LSP server will dispose us when the server exits, but VS could decide to activate us later. // If a new instance of the server is created, a new instance of this class will be created and the // UIContext will already be active, so this method will be immediately called on the new instance. if (cancellationToken.IsCancellationRequested) return; + await TaskScheduler.Default.SwitchTo(alwaysYield: true); + // We use a string to pass capabilities to/from Razor to avoid version issues with the Protocol DLL var serializedClientCapabilities = JsonSerializer.Serialize(clientCapabilities, ProtocolConversions.LspJsonSerializerOptions); - var razorCohostClientLanguageServerManager = new RazorCohostClientLanguageServerManager(clientLanguageServerManager!); + var razorCohostClientLanguageServerManager = new RazorClientLanguageServerManager(clientLanguageServerManager!); var requestContext = new RazorCohostRequestContext(context); - dynamicRegistrationService!.Value.RegisterAsync(serializedClientCapabilities, requestContext, cancellationToken).ReportNonFatalErrorAsync(); + await dynamicRegistrationService!.Value.RegisterAsync(serializedClientCapabilities, requestContext, cancellationToken).ConfigureAwait(false); } } } diff --git a/src/Tools/ExternalAccess/Razor/Cohost/RazorMethodAttribute.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/RazorMethodAttribute.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Cohost/RazorMethodAttribute.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/RazorMethodAttribute.cs diff --git a/src/Tools/ExternalAccess/Razor/Cohost/RazorSemanticTokensRefreshQueueWrapper.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/RazorSemanticTokensRefreshQueueWrapper.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Cohost/RazorSemanticTokensRefreshQueueWrapper.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Cohost/RazorSemanticTokensRefreshQueueWrapper.cs diff --git a/src/Tools/ExternalAccess/Razor/IMefHostServicesExtensions.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/IMefHostServicesExtensions.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/IMefHostServicesExtensions.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/IMefHostServicesExtensions.cs diff --git a/src/Tools/ExternalAccess/Razor/IRazorAsynchronousOperationListenerProviderAccessor.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/IRazorAsynchronousOperationListenerProviderAccessor.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/IRazorAsynchronousOperationListenerProviderAccessor.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/IRazorAsynchronousOperationListenerProviderAccessor.cs diff --git a/src/Tools/ExternalAccess/Razor/IRazorCSharpInterceptionMiddleLayer.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/IRazorCSharpInterceptionMiddleLayer.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/IRazorCSharpInterceptionMiddleLayer.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/IRazorCSharpInterceptionMiddleLayer.cs diff --git a/src/Tools/ExternalAccess/Razor/IRazorLanguageServerTarget.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/IRazorLanguageServerTarget.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/IRazorLanguageServerTarget.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/IRazorLanguageServerTarget.cs diff --git a/src/Tools/ExternalAccess/Razor/IRazorSpanMappingService.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/IRazorSpanMappingService.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/IRazorSpanMappingService.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/IRazorSpanMappingService.cs diff --git a/src/Tools/ExternalAccess/Razor/ITextBufferExtensions.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/ITextBufferExtensions.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/ITextBufferExtensions.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/ITextBufferExtensions.cs diff --git a/src/Tools/ExternalAccess/Razor/EditorFeatures/InternalAPI.Shipped.txt b/src/Tools/ExternalAccess/Razor/EditorFeatures/InternalAPI.Shipped.txt new file mode 100644 index 0000000000000..7dc5c58110bfa --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/EditorFeatures/InternalAPI.Shipped.txt @@ -0,0 +1 @@ +#nullable enable diff --git a/src/Tools/ExternalAccess/Razor/InternalAPI.Unshipped.txt b/src/Tools/ExternalAccess/Razor/EditorFeatures/InternalAPI.Unshipped.txt similarity index 100% rename from src/Tools/ExternalAccess/Razor/InternalAPI.Unshipped.txt rename to src/Tools/ExternalAccess/Razor/EditorFeatures/InternalAPI.Unshipped.txt diff --git a/src/Tools/ExternalAccess/Razor/Microsoft.CodeAnalysis.ExternalAccess.Razor.csproj b/src/Tools/ExternalAccess/Razor/EditorFeatures/Microsoft.CodeAnalysis.ExternalAccess.Razor.csproj similarity index 75% rename from src/Tools/ExternalAccess/Razor/Microsoft.CodeAnalysis.ExternalAccess.Razor.csproj rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Microsoft.CodeAnalysis.ExternalAccess.Razor.csproj index 6164b50074dd8..68ae9daf38674 100644 --- a/src/Tools/ExternalAccess/Razor/Microsoft.CodeAnalysis.ExternalAccess.Razor.csproj +++ b/src/Tools/ExternalAccess/Razor/EditorFeatures/Microsoft.CodeAnalysis.ExternalAccess.Razor.csproj @@ -15,7 +15,7 @@ - + @@ -41,11 +41,11 @@ - - - - - + + + + + @@ -59,4 +59,6 @@ + + diff --git a/src/Tools/ExternalAccess/Razor/EditorFeatures/PublicAPI.Shipped.txt b/src/Tools/ExternalAccess/Razor/EditorFeatures/PublicAPI.Shipped.txt new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/Tools/ExternalAccess/Razor/EditorFeatures/PublicAPI.Unshipped.txt b/src/Tools/ExternalAccess/Razor/EditorFeatures/PublicAPI.Unshipped.txt new file mode 100644 index 0000000000000..815c92006af70 --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/EditorFeatures/PublicAPI.Unshipped.txt @@ -0,0 +1 @@ +#nullable enable \ No newline at end of file diff --git a/src/Tools/ExternalAccess/Razor/EditorFeatures/RazorAnalyzerAssemblyResolver.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/RazorAnalyzerAssemblyResolver.cs new file mode 100644 index 0000000000000..0da8eb54508b8 --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/EditorFeatures/RazorAnalyzerAssemblyResolver.cs @@ -0,0 +1,94 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +#if NET + +using System; +using System.Collections.Immutable; +using System.Composition; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.Loader; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.VisualStudio.Composition; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor +{ + [Export(typeof(IAnalyzerAssemblyResolver)), Shared] + [method: ImportingConstructor] + [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + internal sealed class RazorAnalyzerAssemblyResolver() : IAnalyzerAssemblyResolver + { + public const string RazorCompilerAssemblyName = "Microsoft.CodeAnalysis.Razor.Compiler"; + public const string RazorUtilsAssemblyName = "Microsoft.AspNetCore.Razor.Utilities.Shared"; + public const string ObjectPoolAssemblyName = "Microsoft.Extensions.ObjectPool"; + + internal static readonly ImmutableArray RazorAssemblyNames = [RazorCompilerAssemblyName, RazorUtilsAssemblyName, ObjectPoolAssemblyName]; + + public Assembly? Resolve(AnalyzerAssemblyLoader loader, AssemblyName assemblyName, AssemblyLoadContext directoryContext, string directory) => + ResolveCore(loader.CompilerLoadContext, assemblyName, directory); + + public static Assembly? ResolveRazorAssembly(AssemblyName assemblyName, string rootDirectory) => + ResolveCore( + AssemblyLoadContext.GetLoadContext(typeof(Microsoft.CodeAnalysis.Compilation).Assembly)!, + assemblyName, + rootDirectory); + + /// + /// This will resolve the razor generator assembly specified by in the specified + /// . + /// + internal static Assembly? ResolveCore(AssemblyLoadContext compilerLoadContext, AssemblyName assemblyName, string directory) + { + if (assemblyName.Name is not (RazorCompilerAssemblyName or RazorUtilsAssemblyName or ObjectPoolAssemblyName)) + { + return null; + } + + var assembly = compilerLoadContext.Assemblies.FirstOrDefault(a => a.GetName().Name == assemblyName.Name); + if (assembly is not null) + { + return assembly; + } + + var assemblyFileName = $"{assemblyName.Name}.dll"; + var assemblyPath = Path.Combine(directory, assemblyFileName); + if (File.Exists(assemblyPath)) + { + // https://github.com/dotnet/roslyn/issues/76868 + // + // There is a subtle race condition in this logic as another thread could load the assembly in between + // the above calls and this one. Short term will just catch and grab the loaded assembly but longer + // term need to think about creating a dedicated AssemblyLoadContext for the razor assemblies + // which avoids this race condition. + try + { + assembly = compilerLoadContext.LoadFromAssemblyPath(assemblyPath); + } + catch + { + assembly = compilerLoadContext.Assemblies.Single(a => a.GetName().Name == assemblyName.Name); + } + } + else + { + // There are assemblies in the razor sdk generator directory that do not exist in the VS installation. That + // means when the paths are redirected, it's possible that the assembly is not found. In that case, we should + // load the assembly from the VS installation by querying through the compiler context. + try + { + assembly = compilerLoadContext.LoadFromAssemblyName(assemblyName); + } + catch (FileNotFoundException) + { + assembly = null; + } + } + + return assembly; + } + } +} +#endif diff --git a/src/Tools/ExternalAccess/Razor/RazorAsynchronousOperationListenerProviderAccessor.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/RazorAsynchronousOperationListenerProviderAccessor.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/RazorAsynchronousOperationListenerProviderAccessor.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/RazorAsynchronousOperationListenerProviderAccessor.cs diff --git a/src/Tools/ExternalAccess/Razor/RazorAsynchronousOperationListenerWrapper.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/RazorAsynchronousOperationListenerWrapper.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/RazorAsynchronousOperationListenerWrapper.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/RazorAsynchronousOperationListenerWrapper.cs diff --git a/src/Tools/ExternalAccess/Razor/RazorAutoFormattingOptions.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/RazorAutoFormattingOptions.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/RazorAutoFormattingOptions.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/RazorAutoFormattingOptions.cs diff --git a/src/Tools/ExternalAccess/Razor/RazorBreakpointSpans.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/RazorBreakpointSpans.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/RazorBreakpointSpans.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/RazorBreakpointSpans.cs diff --git a/src/Tools/ExternalAccess/Razor/RazorCSharpFormattingInteractionService.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/RazorCSharpFormattingInteractionService.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/RazorCSharpFormattingInteractionService.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/RazorCSharpFormattingInteractionService.cs diff --git a/src/Tools/ExternalAccess/Razor/RazorCSharpInterceptionMiddleLayer.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/RazorCSharpInterceptionMiddleLayer.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/RazorCSharpInterceptionMiddleLayer.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/RazorCSharpInterceptionMiddleLayer.cs diff --git a/src/Tools/ExternalAccess/Razor/RazorCSharpProximityExpressionResolverService.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/RazorCSharpProximityExpressionResolverService.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/RazorCSharpProximityExpressionResolverService.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/RazorCSharpProximityExpressionResolverService.cs diff --git a/src/Tools/ExternalAccess/Razor/RazorClassifierAccessor.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/RazorClassifierAccessor.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/RazorClassifierAccessor.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/RazorClassifierAccessor.cs diff --git a/src/Tools/ExternalAccess/Razor/RazorDynamicFileInfoProviderWrapper.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/RazorDynamicFileInfoProviderWrapper.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/RazorDynamicFileInfoProviderWrapper.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/RazorDynamicFileInfoProviderWrapper.cs diff --git a/src/Tools/ExternalAccess/Razor/RazorGlobalOptions.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/RazorGlobalOptions.cs similarity index 97% rename from src/Tools/ExternalAccess/Razor/RazorGlobalOptions.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/RazorGlobalOptions.cs index 39fc16ce1217f..f84d58518281b 100644 --- a/src/Tools/ExternalAccess/Razor/RazorGlobalOptions.cs +++ b/src/Tools/ExternalAccess/Razor/EditorFeatures/RazorGlobalOptions.cs @@ -4,14 +4,11 @@ using System; using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Formatting; -using System.Linq; using System.Collections.Immutable; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.Razor { diff --git a/src/Tools/ExternalAccess/Razor/RazorIndentationOptions.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/RazorIndentationOptions.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/RazorIndentationOptions.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/RazorIndentationOptions.cs diff --git a/src/Tools/ExternalAccess/Razor/RazorLanguageServerTargetWrapper.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/RazorLanguageServerTargetWrapper.cs similarity index 90% rename from src/Tools/ExternalAccess/Razor/RazorLanguageServerTargetWrapper.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/RazorLanguageServerTargetWrapper.cs index 5f384df2ed102..0107a9ee3a3f3 100644 --- a/src/Tools/ExternalAccess/Razor/RazorLanguageServerTargetWrapper.cs +++ b/src/Tools/ExternalAccess/Razor/EditorFeatures/RazorLanguageServerTargetWrapper.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.Threading.Tasks; using Microsoft.CommonLanguageServerProtocol.Framework; -using Microsoft.CodeAnalysis.LanguageServer; using Microsoft.CodeAnalysis.LanguageServer.Handler; namespace Microsoft.CodeAnalysis.ExternalAccess.Razor diff --git a/src/Tools/ExternalAccess/Razor/RazorPredefinedCodeFixProviderNames.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/RazorPredefinedCodeFixProviderNames.cs similarity index 99% rename from src/Tools/ExternalAccess/Razor/RazorPredefinedCodeFixProviderNames.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/RazorPredefinedCodeFixProviderNames.cs index 34bd12e2e12f1..991e600c2e763 100644 --- a/src/Tools/ExternalAccess/Razor/RazorPredefinedCodeFixProviderNames.cs +++ b/src/Tools/ExternalAccess/Razor/EditorFeatures/RazorPredefinedCodeFixProviderNames.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.Razor { internal static class RazorPredefinedCodeFixProviderNames { - public static string AddAccessibilityModifiers => PredefinedCodeFixProviderNames.AddAccessibilityModifiers; + public static string AddAccessibilityModifiers => PredefinedCodeFixProviderNames.AddOrRemoveAccessibilityModifiers; public static string AddAnonymousTypeMemberName => PredefinedCodeFixProviderNames.AddAnonymousTypeMemberName; public static string AddAsync => PredefinedCodeFixProviderNames.AddAsync; public static string AddBraces => PredefinedCodeFixProviderNames.AddBraces; diff --git a/src/Tools/ExternalAccess/Razor/RazorPredefinedCodeRefactoringProviderNames.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/RazorPredefinedCodeRefactoringProviderNames.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/RazorPredefinedCodeRefactoringProviderNames.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/RazorPredefinedCodeRefactoringProviderNames.cs diff --git a/src/Tools/ExternalAccess/Razor/RazorProjectExtensions.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/RazorProjectExtensions.cs similarity index 98% rename from src/Tools/ExternalAccess/Razor/RazorProjectExtensions.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/RazorProjectExtensions.cs index 25ec3e65f3f4d..6fb24a0a756e1 100644 --- a/src/Tools/ExternalAccess/Razor/RazorProjectExtensions.cs +++ b/src/Tools/ExternalAccess/Razor/EditorFeatures/RazorProjectExtensions.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; diff --git a/src/Tools/ExternalAccess/Razor/RazorSemanticTokensAccessor.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/RazorSemanticTokensAccessor.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/RazorSemanticTokensAccessor.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/RazorSemanticTokensAccessor.cs diff --git a/src/Tools/ExternalAccess/Razor/EditorFeatures/RazorUri.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/RazorUri.cs new file mode 100644 index 0000000000000..98fc55b7e25c4 --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/EditorFeatures/RazorUri.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 Microsoft.CodeAnalysis.LanguageServer; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor; + +internal static class RazorUri +{ + public static Uri CreateAbsoluteUri(string absolutePath) + => ProtocolConversions.CreateAbsoluteUri(absolutePath); + + public static string GetDocumentFilePathFromUri(Uri uri) + => ProtocolConversions.GetDocumentFilePathFromUri(uri); + + public static bool IsGeneratedDocumentUri(Uri generatedDocumentUri) + => generatedDocumentUri.Scheme == SourceGeneratedDocumentUri.Scheme; + + public static string GetHintNameFromGeneratedDocumentUri(Solution solution, Uri generatedDocumentUri) + { + Contract.ThrowIfFalse(IsGeneratedDocumentUri(generatedDocumentUri)); + + if (SourceGeneratedDocumentUri.DeserializeIdentity(solution, generatedDocumentUri) is not { } identity) + { + throw new InvalidOperationException($"Could not deserialize Uri into a source generated Uri: {generatedDocumentUri}"); + } + + return identity.HintName; + } +} diff --git a/src/Tools/ExternalAccess/Razor/Remote/JsonSerializableDocumentId.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Remote/JsonSerializableDocumentId.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Remote/JsonSerializableDocumentId.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Remote/JsonSerializableDocumentId.cs diff --git a/src/Tools/ExternalAccess/Razor/Remote/JsonSerializableRazorPinnedSolutionInfoWrapper.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Remote/JsonSerializableRazorPinnedSolutionInfoWrapper.cs similarity index 98% rename from src/Tools/ExternalAccess/Razor/Remote/JsonSerializableRazorPinnedSolutionInfoWrapper.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Remote/JsonSerializableRazorPinnedSolutionInfoWrapper.cs index 33c57d04c581b..a248fd113208a 100644 --- a/src/Tools/ExternalAccess/Razor/Remote/JsonSerializableRazorPinnedSolutionInfoWrapper.cs +++ b/src/Tools/ExternalAccess/Razor/EditorFeatures/Remote/JsonSerializableRazorPinnedSolutionInfoWrapper.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.Text.Json.Serialization; namespace Microsoft.CodeAnalysis.ExternalAccess.Razor diff --git a/src/Tools/ExternalAccess/Razor/Remote/RazorPinnedSolutionInfoWrapper.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Remote/RazorPinnedSolutionInfoWrapper.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Remote/RazorPinnedSolutionInfoWrapper.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Remote/RazorPinnedSolutionInfoWrapper.cs diff --git a/src/Tools/ExternalAccess/Razor/Remote/RazorRemoteCallbackWrapper.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Remote/RazorRemoteCallbackWrapper.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Remote/RazorRemoteCallbackWrapper.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Remote/RazorRemoteCallbackWrapper.cs diff --git a/src/Tools/ExternalAccess/Razor/Remote/RazorRemoteHostClient.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Remote/RazorRemoteHostClient.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Remote/RazorRemoteHostClient.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Remote/RazorRemoteHostClient.cs diff --git a/src/Tools/ExternalAccess/Razor/Remote/RazorRemoteServiceCallbackDispatcher.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Remote/RazorRemoteServiceCallbackDispatcher.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Remote/RazorRemoteServiceCallbackDispatcher.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Remote/RazorRemoteServiceCallbackDispatcher.cs diff --git a/src/Tools/ExternalAccess/Razor/Remote/RazorRemoteServiceCallbackDispatcherRegistry.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Remote/RazorRemoteServiceCallbackDispatcherRegistry.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Remote/RazorRemoteServiceCallbackDispatcherRegistry.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Remote/RazorRemoteServiceCallbackDispatcherRegistry.cs diff --git a/src/Tools/ExternalAccess/Razor/Remote/RazorRemoteServiceCallbackIdWrapper.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Remote/RazorRemoteServiceCallbackIdWrapper.cs similarity index 98% rename from src/Tools/ExternalAccess/Razor/Remote/RazorRemoteServiceCallbackIdWrapper.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Remote/RazorRemoteServiceCallbackIdWrapper.cs index 907a1e16677de..4ef451dbe7671 100644 --- a/src/Tools/ExternalAccess/Razor/Remote/RazorRemoteServiceCallbackIdWrapper.cs +++ b/src/Tools/ExternalAccess/Razor/EditorFeatures/Remote/RazorRemoteServiceCallbackIdWrapper.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.Runtime.Serialization; using Microsoft.CodeAnalysis.Remote; diff --git a/src/Tools/ExternalAccess/Razor/Remote/RazorRemoteServiceConnectionWrapper.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Remote/RazorRemoteServiceConnectionWrapper.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Remote/RazorRemoteServiceConnectionWrapper.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Remote/RazorRemoteServiceConnectionWrapper.cs diff --git a/src/Tools/ExternalAccess/Razor/Remote/RazorServiceDescriptorsWrapper.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Remote/RazorServiceDescriptorsWrapper.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Remote/RazorServiceDescriptorsWrapper.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Remote/RazorServiceDescriptorsWrapper.cs diff --git a/src/Tools/ExternalAccess/Razor/SolutionExtensions.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/SolutionExtensions.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/SolutionExtensions.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/SolutionExtensions.cs diff --git a/src/Tools/ExternalAccess/Razor/Testing/AbstractRazorLanguageServerFactoryWrapper.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Testing/AbstractRazorLanguageServerFactoryWrapper.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Testing/AbstractRazorLanguageServerFactoryWrapper.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Testing/AbstractRazorLanguageServerFactoryWrapper.cs diff --git a/src/Tools/ExternalAccess/Razor/Testing/IRazorTestCapabilitiesProvider.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Testing/IRazorTestCapabilitiesProvider.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Testing/IRazorTestCapabilitiesProvider.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Testing/IRazorTestCapabilitiesProvider.cs diff --git a/src/Tools/ExternalAccess/Razor/Testing/RazorTestAnalyzerLoader.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Testing/RazorTestAnalyzerLoader.cs similarity index 94% rename from src/Tools/ExternalAccess/Razor/Testing/RazorTestAnalyzerLoader.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Testing/RazorTestAnalyzerLoader.cs index 03b807c66d944..3bfd57f29a11e 100644 --- a/src/Tools/ExternalAccess/Razor/Testing/RazorTestAnalyzerLoader.cs +++ b/src/Tools/ExternalAccess/Razor/EditorFeatures/Testing/RazorTestAnalyzerLoader.cs @@ -27,6 +27,6 @@ public void InitializeDiagnosticsServices(Workspace workspace) public static IAnalyzerAssemblyLoader CreateAnalyzerAssemblyLoader() { - return new DefaultAnalyzerAssemblyLoader(); + return new AnalyzerAssemblyLoader(); } } diff --git a/src/Tools/ExternalAccess/Razor/Testing/RazorTestLanguageServerFactory.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Testing/RazorTestLanguageServerFactory.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Testing/RazorTestLanguageServerFactory.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Testing/RazorTestLanguageServerFactory.cs diff --git a/src/Tools/ExternalAccess/Razor/Testing/RazorTestWorkspaceRegistrationService.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Testing/RazorTestWorkspaceRegistrationService.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Testing/RazorTestWorkspaceRegistrationService.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Testing/RazorTestWorkspaceRegistrationService.cs diff --git a/src/Tools/ExternalAccess/Razor/Testing/TestSolutionStore.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/Testing/TestSolutionStore.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/Testing/TestSolutionStore.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/Testing/TestSolutionStore.cs diff --git a/src/Tools/ExternalAccess/Razor/TextDocumentExtensions.cs b/src/Tools/ExternalAccess/Razor/EditorFeatures/TextDocumentExtensions.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/TextDocumentExtensions.cs rename to src/Tools/ExternalAccess/Razor/EditorFeatures/TextDocumentExtensions.cs diff --git a/src/Tools/ExternalAccess/Razor/Features/AbstractRazorLspService.cs b/src/Tools/ExternalAccess/Razor/Features/AbstractRazorLspService.cs new file mode 100644 index 0000000000000..45cb8623674ea --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Features/AbstractRazorLspService.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.LanguageServer; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Features; + +internal abstract class AbstractRazorLspService : ILspService +{ +} diff --git a/src/Tools/ExternalAccess/Razor/Features/AbstractRazorLspServiceFactory.cs b/src/Tools/ExternalAccess/Razor/Features/AbstractRazorLspServiceFactory.cs new file mode 100644 index 0000000000000..2dbc3f73b5140 --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Features/AbstractRazorLspServiceFactory.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.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis.LanguageServer; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Features; + +internal abstract class AbstractRazorLspServiceFactory : ILspServiceFactory +{ + public ILspService CreateILspService(LspServices lspServices, WellKnownLspServerKinds serverKind) + { + return CreateService(new RazorLspServices(lspServices)); + } + + protected abstract AbstractRazorLspService CreateService(IRazorLspServices lspServices); + + private sealed class RazorLspServices(LspServices lspServices) : IRazorLspServices + { + public void Dispose() + { + } + + public T GetRequiredService() where T : notnull => lspServices.GetRequiredService(); + public IEnumerable GetRequiredServices() => lspServices.GetRequiredServices(); + public T? GetService() where T : notnull => lspServices.GetService(); + public bool TryGetService(Type type, [NotNullWhen(true)] out object? service) => lspServices.TryGetService(type, out service); + } +} diff --git a/src/Tools/ExternalAccess/Razor/Features/AbstractRazorNotificationHandler.cs b/src/Tools/ExternalAccess/Razor/Features/AbstractRazorNotificationHandler.cs new file mode 100644 index 0000000000000..60d8ca67dc4a6 --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Features/AbstractRazorNotificationHandler.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 Microsoft.CodeAnalysis.LanguageServer.Handler; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Features; + +internal abstract class AbstractRazorNotificationHandler : ILspServiceNotificationHandler +{ + public abstract bool MutatesSolutionState { get; } + public abstract bool RequiresLSPSolution { get; } + + public Task HandleNotificationAsync(TRequestType request, RequestContext requestContext, CancellationToken cancellationToken) + { + var razorRequestContext = new RazorRequestContext(requestContext); + return HandleNotificationAsync(request, razorRequestContext, cancellationToken); + } + + protected abstract Task HandleNotificationAsync(TRequestType request, RazorRequestContext razorRequestContext, CancellationToken cancellationToken); +} diff --git a/src/Tools/ExternalAccess/Razor/Features/AbstractRazorRequestHandler.cs b/src/Tools/ExternalAccess/Razor/Features/AbstractRazorRequestHandler.cs new file mode 100644 index 0000000000000..d465bd4ad7fed --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Features/AbstractRazorRequestHandler.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 Microsoft.CodeAnalysis.LanguageServer.Handler; +using Microsoft.CommonLanguageServerProtocol.Framework; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Features; + +internal abstract class AbstractRazorRequestHandler : ILspServiceRequestHandler +{ + bool IMethodHandler.MutatesSolutionState => MutatesSolutionState; + + bool ISolutionRequiredHandler.RequiresLSPSolution => RequiresLSPSolution; + + Task IRequestHandler.HandleRequestAsync(TRequestType request, RequestContext context, CancellationToken cancellationToken) + { + var razorRequestContext = new RazorRequestContext(context); + return HandleRequestAsync(request, razorRequestContext, cancellationToken); + } + + protected abstract bool MutatesSolutionState { get; } + + protected abstract bool RequiresLSPSolution { get; } + + protected abstract Task HandleRequestAsync(TRequestType request, RazorRequestContext context, CancellationToken cancellationToken); +} diff --git a/src/Tools/ExternalAccess/Razor/Features/ExportRazorLspServiceFactoryAttribute.cs b/src/Tools/ExternalAccess/Razor/Features/ExportRazorLspServiceFactoryAttribute.cs new file mode 100644 index 0000000000000..9ab9d67ca0292 --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Features/ExportRazorLspServiceFactoryAttribute.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Composition; +using Microsoft.CodeAnalysis.LanguageServer; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Features; + +[AttributeUsage(AttributeTargets.Class), MetadataAttribute] +internal class ExportRazorLspServiceFactoryAttribute(Type handlerType) : ExportLspServiceFactoryAttribute(handlerType, ProtocolConstants.RoslynLspLanguagesContract, WellKnownLspServerKinds.Any); diff --git a/src/Tools/ExternalAccess/Razor/Features/ExportRazorStatelessLspServiceAttribute.cs b/src/Tools/ExternalAccess/Razor/Features/ExportRazorStatelessLspServiceAttribute.cs new file mode 100644 index 0000000000000..6761c3cc296bc --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Features/ExportRazorStatelessLspServiceAttribute.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Composition; +using Microsoft.CodeAnalysis.LanguageServer; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Features; + +[AttributeUsage(AttributeTargets.Class), MetadataAttribute] +internal sealed class ExportRazorStatelessLspServiceAttribute(Type handlerType) : ExportStatelessLspServiceAttribute(handlerType, ProtocolConstants.RoslynLspLanguagesContract, WellKnownLspServerKinds.Any); diff --git a/src/Tools/ExternalAccess/Razor/Features/IRazorLspServices.cs b/src/Tools/ExternalAccess/Razor/Features/IRazorLspServices.cs new file mode 100644 index 0000000000000..0e6cd8ca02b14 --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Features/IRazorLspServices.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics.CodeAnalysis; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Features; + +internal interface IRazorLspServices +{ + T? GetService() where T : notnull; + T GetRequiredService() where T : notnull; + + bool TryGetService(Type type, [NotNullWhen(true)] out object? service); + + IEnumerable GetRequiredServices(); +} diff --git a/src/Tools/ExternalAccess/Razor/Features/IRazorRequestWrapper.cs b/src/Tools/ExternalAccess/Razor/Features/IRazorRequestWrapper.cs new file mode 100644 index 0000000000000..8b5623939ae7c --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Features/IRazorRequestWrapper.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. + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Features; + +internal interface IRazorRequestWrapper +{ + Task SendRequestAsync(string methodName, TParams @params, CancellationToken cancellationToken); + ValueTask SendRequestAsync(string methodName, CancellationToken cancellationToken); + ValueTask SendRequestAsync(string methodName, TParams @params, CancellationToken cancellationToken); +} diff --git a/src/Tools/ExternalAccess/Razor/Features/Microsoft.CodeAnalysis.ExternalAccess.Razor.Features.csproj b/src/Tools/ExternalAccess/Razor/Features/Microsoft.CodeAnalysis.ExternalAccess.Razor.Features.csproj new file mode 100644 index 0000000000000..c148f63ee2968 --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Features/Microsoft.CodeAnalysis.ExternalAccess.Razor.Features.csproj @@ -0,0 +1,58 @@ + + + + + Microsoft.CodeAnalysis.ExternalAccess.Razor.Features + $(NetVSCode) + enable + enable + + + true + Microsoft.CodeAnalysis.ExternalAccess.Razor.Features + + A supporting package for Razor: + https://github.com/dotnet/razor + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Tools/ExternalAccess/Razor/Features/RazorEndpointAttribute.cs b/src/Tools/ExternalAccess/Razor/Features/RazorEndpointAttribute.cs new file mode 100644 index 0000000000000..3356a326929bd --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Features/RazorEndpointAttribute.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.Composition; +using Microsoft.CommonLanguageServerProtocol.Framework; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Features; + +[MetadataAttribute] +internal class RazorEndpointAttribute : LanguageServerEndpointAttribute +{ + public RazorEndpointAttribute(string method) : base(method, LanguageServerConstants.DefaultLanguageName) + { + } + + public RazorEndpointAttribute(string method, string language) : base(method, language) + { + } +} diff --git a/src/Tools/ExternalAccess/Razor/Features/RazorLspDynamicFileInfoProvider.cs b/src/Tools/ExternalAccess/Razor/Features/RazorLspDynamicFileInfoProvider.cs new file mode 100644 index 0000000000000..ff860ee5e3fe2 --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Features/RazorLspDynamicFileInfoProvider.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. + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Features; + +internal abstract class RazorLspDynamicFileInfoProvider : AbstractRazorLspService +{ + public abstract Task GetDynamicFileInfoAsync(Workspace workspace, ProjectId projectId, string? projectFilePath, string filePath, CancellationToken cancellationToken); + public abstract Task RemoveDynamicFileInfoAsync(Workspace workspace, ProjectId projectId, string? projectFilePath, string filePath, CancellationToken cancellationToken); + + public event EventHandler? Updated; + + public void Update(Uri razorUri) + { + Updated?.Invoke(this, razorUri); + } +} diff --git a/src/Tools/ExternalAccess/Razor/Features/RazorRequestContext.cs b/src/Tools/ExternalAccess/Razor/Features/RazorRequestContext.cs new file mode 100644 index 0000000000000..0e960e8f7ec5b --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Features/RazorRequestContext.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 Microsoft.CodeAnalysis.LanguageServer; +using Microsoft.CodeAnalysis.LanguageServer.Handler; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Features; + +internal readonly struct RazorRequestContext(RequestContext context) +{ + internal string Method => context.Method; + internal Uri? Uri => context.TextDocument?.GetURI(); + /// + internal Workspace? Workspace => context.Workspace; + /// + internal Solution? Solution => context.Solution; + /// + internal TextDocument? TextDocument => context.TextDocument; + + internal T GetRequiredService() where T : class => context.GetRequiredService(); +} diff --git a/src/Tools/ExternalAccess/Razor/Features/RazorWorkspaceService.cs b/src/Tools/ExternalAccess/Razor/Features/RazorWorkspaceService.cs new file mode 100644 index 0000000000000..9257ab33b0757 --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Features/RazorWorkspaceService.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.LanguageServer; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Features; + +internal abstract class RazorWorkspaceService : AbstractRazorLspService +{ + public abstract void Initialize(Workspace workspace, string pipeName); + public abstract void NotifyDynamicFile(ProjectId projectId); +} diff --git a/src/Tools/ExternalAccess/Razor/Features/WorkspaceExtensions.cs b/src/Tools/ExternalAccess/Razor/Features/WorkspaceExtensions.cs new file mode 100644 index 0000000000000..aa709b664be1a --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Features/WorkspaceExtensions.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 Roslyn.LanguageServer.Protocol; +using Microsoft.CodeAnalysis.LanguageServer; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Features; + +internal static class WorkspaceExtensions +{ + public static ValueTask GetTextDocumentAsync(this Workspace workspace, Uri uri, CancellationToken cancellationToken) + { + var identifier = new TextDocumentIdentifier() { Uri = uri }; + return workspace.CurrentSolution.GetTextDocumentAsync(identifier, cancellationToken); + } +} diff --git a/src/Tools/ExternalAccess/Razor/IRazorDocumentOperationService.cs b/src/Tools/ExternalAccess/Razor/IRazorDocumentOperationService.cs deleted file mode 100644 index 616a8b14973a7..0000000000000 --- a/src/Tools/ExternalAccess/Razor/IRazorDocumentOperationService.cs +++ /dev/null @@ -1,19 +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.ExternalAccess.Razor -{ - internal interface IRazorDocumentOperationService - { - /// - /// document version of - /// - bool CanApplyChange { get; } - - /// - /// indicates whether this document supports diagnostics or not - /// - bool SupportDiagnostics { get; } - } -} diff --git a/src/Tools/ExternalAccess/Razor/IRazorDocumentServiceProvider.cs b/src/Tools/ExternalAccess/Razor/IRazorDocumentServiceProvider.cs deleted file mode 100644 index 101b26d992bd2..0000000000000 --- a/src/Tools/ExternalAccess/Razor/IRazorDocumentServiceProvider.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. - -namespace Microsoft.CodeAnalysis.ExternalAccess.Razor -{ - internal interface IRazorDocumentServiceProvider : IRazorDocumentOperationService - { - /// - /// Gets a document specific service provided by the host identified by the service type. - /// If the host does not provide the service, this method returns null. - /// - TService? GetService() where TService : class; - } -} diff --git a/src/Tools/ExternalAccess/Razor/IRazorDynamicFileInfoProvider.cs b/src/Tools/ExternalAccess/Razor/IRazorDynamicFileInfoProvider.cs deleted file mode 100644 index 277b9da9b906d..0000000000000 --- a/src/Tools/ExternalAccess/Razor/IRazorDynamicFileInfoProvider.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Host; - -namespace Microsoft.CodeAnalysis.ExternalAccess.Razor -{ - internal interface IRazorDynamicFileInfoProvider - { - /// - /// return for the context given - /// - /// this file belongs to - /// full path to project file (ex, csproj) - /// full path to non source file (ex, cshtml) - Task GetDynamicFileInfoAsync(ProjectId projectId, string? projectFilePath, string filePath, CancellationToken cancellationToken); - - /// - /// let provider know certain file has been removed - /// - /// this file belongs to - /// full path to project file (ex, csproj) - /// full path to non source file (ex, cshtml) - Task RemoveDynamicFileInfoAsync(ProjectId projectId, string? projectFilePath, string filePath, CancellationToken cancellationToken); - - /// - /// indicate content of a file has updated. the event argument "string" should be same as "filepath" given to - /// - event EventHandler Updated; - } -} diff --git a/src/Tools/ExternalAccess/Razor/IRazorMappingService.cs b/src/Tools/ExternalAccess/Razor/IRazorMappingService.cs deleted file mode 100644 index 8cda2f0dc1a8c..0000000000000 --- a/src/Tools/ExternalAccess/Razor/IRazorMappingService.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Text; - -namespace Microsoft.CodeAnalysis.ExternalAccess.Razor -{ - internal interface IRazorMappingService - { - Task> MapSpansAsync(Document document, IEnumerable spans, CancellationToken cancellationToken); - Task> MapTextChangesAsync(Document oldDocument, Document newDocument, CancellationToken cancellationToken); - } -} diff --git a/src/Tools/ExternalAccess/Razor/RazorAnalyzerAssemblyResolver.cs b/src/Tools/ExternalAccess/Razor/RazorAnalyzerAssemblyResolver.cs deleted file mode 100644 index f9ccd053fbc40..0000000000000 --- a/src/Tools/ExternalAccess/Razor/RazorAnalyzerAssemblyResolver.cs +++ /dev/null @@ -1,50 +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. -#if NET - -using System; -using System.Composition; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Runtime.Loader; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.VisualStudio.Composition; - -namespace Microsoft.CodeAnalysis.ExternalAccess.Razor -{ - [Export(typeof(IAnalyzerAssemblyResolver)), Shared] - [method: ImportingConstructor] - [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - internal sealed class RazorAnalyzerAssemblyResolver() : IAnalyzerAssemblyResolver - { - private const string RazorCompilerAssemblyName = "Microsoft.CodeAnalysis.Razor.Compiler"; - private const string RazorUtilsAssemblyName = "Microsoft.AspNetCore.Razor.Utilities.Shared"; - private const string ObjectPoolAssemblyName = "Microsoft.Extensions.ObjectPool"; - - private static readonly object s_loaderLock = new(); - - public static Assembly? ResolveRazorAssembly(AssemblyName assemblyName, string rootDirectory) - { - if (assemblyName.Name is RazorCompilerAssemblyName or RazorUtilsAssemblyName or ObjectPoolAssemblyName) - { - lock (s_loaderLock) - { - var compilerContext = AssemblyLoadContext.GetLoadContext(typeof(Compilation).Assembly)!; - if (compilerContext.Assemblies.SingleOrDefault(a => a.GetName().Name == assemblyName.Name) is Assembly loadedAssembly) - { - return loadedAssembly; - } - - var assembly = Path.Combine(rootDirectory, $"{assemblyName.Name}.dll"); - return compilerContext.LoadFromAssemblyPath(assembly); - } - } - return null; - } - - public Assembly? ResolveAssembly(AssemblyName assemblyName, string directoryName) => ResolveRazorAssembly(assemblyName, directoryName); - } -} -#endif diff --git a/src/Tools/ExternalAccess/Razor/RazorDynamicFileInfo.cs b/src/Tools/ExternalAccess/Razor/RazorDynamicFileInfo.cs deleted file mode 100644 index 73d4a49cdae64..0000000000000 --- a/src/Tools/ExternalAccess/Razor/RazorDynamicFileInfo.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.CodeAnalysis.Host; - -namespace Microsoft.CodeAnalysis.ExternalAccess.Razor -{ - /// - /// provides info on the given file - /// - /// this will be used to provide dynamic content such as generated content from cshtml to workspace - /// we acquire this from exposed from external components such as razor for cshtml - /// - internal sealed class RazorDynamicFileInfo - { - public RazorDynamicFileInfo(string filePath, SourceCodeKind sourceCodeKind, TextLoader textLoader, IRazorDocumentServiceProvider documentServiceProvider) - { - FilePath = filePath; - SourceCodeKind = sourceCodeKind; - TextLoader = textLoader; - DocumentServiceProvider = documentServiceProvider; - } - - /// - /// for now, return null. in future, we will use this to get right options from editorconfig - /// - public string FilePath { get; } - - /// - /// return for this file - /// - public SourceCodeKind SourceCodeKind { get; } - - /// - /// return to load content for the dynamic file - /// - public TextLoader TextLoader { get; } - - /// - /// return for the contents it provides - /// - public IRazorDocumentServiceProvider DocumentServiceProvider { get; } - - /// - /// Constructs a new from an existing but with updated - /// text loader and document service provider coming from this instance. - /// - public DocumentInfo ToUpdatedDocumentInfo(DocumentInfo existingDocumentInfo) - { - var serviceProvider = new RazorDocumentServiceProviderWrapper(this.DocumentServiceProvider); - return new DocumentInfo(existingDocumentInfo.Attributes, this.TextLoader, serviceProvider); - } - } -} diff --git a/src/Tools/ExternalAccess/Razor/RazorMappedSpanResult.cs b/src/Tools/ExternalAccess/Razor/RazorMappedSpanResult.cs deleted file mode 100644 index cdd07bdf2a5fa..0000000000000 --- a/src/Tools/ExternalAccess/Razor/RazorMappedSpanResult.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using Microsoft.CodeAnalysis.Text; - -namespace Microsoft.CodeAnalysis.ExternalAccess.Razor -{ - internal readonly struct RazorMappedSpanResult - { - public readonly string FilePath; - - public readonly LinePositionSpan LinePositionSpan; - - public readonly TextSpan Span; - - public RazorMappedSpanResult(string filePath, LinePositionSpan linePositionSpan, TextSpan span) - { - if (string.IsNullOrEmpty(filePath)) - { - throw new ArgumentException(nameof(filePath)); - } - - FilePath = filePath; - LinePositionSpan = linePositionSpan; - Span = span; - } - - public bool IsDefault => FilePath == null; - } - - internal readonly record struct RazorMappedEditoResult(string FilePath, TextChange[] TextChanges) - { - public bool IsDefault => FilePath == null || TextChanges == null; - } -} diff --git a/src/Tools/ExternalAccess/Razor/RazorMappingServiceWrapper.cs b/src/Tools/ExternalAccess/Razor/RazorMappingServiceWrapper.cs deleted file mode 100644 index 16625dbf0c1b6..0000000000000 --- a/src/Tools/ExternalAccess/Razor/RazorMappingServiceWrapper.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. - -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.Host; -using Microsoft.CodeAnalysis.Text; - -namespace Microsoft.CodeAnalysis.ExternalAccess.Razor -{ - internal sealed class RazorMappingServiceWrapper(IRazorMappingService razorMappingService) : ISpanMappingService - { - private readonly IRazorMappingService _razorMappingService = razorMappingService; - - public bool SupportsMappingImportDirectives => true; - - public async Task> GetMappedTextChangesAsync( - Document oldDocument, - Document newDocument, - CancellationToken cancellationToken) - { - var mappedEdits = await _razorMappingService.MapTextChangesAsync(oldDocument, newDocument, cancellationToken).ConfigureAwait(false); - - var changesCount = mappedEdits.Select(e => e.IsDefault ? 0 : e.TextChanges.Length).Sum(); - var changes = new (string mappedFilePath, TextChange mappedTextChange)[changesCount]; - - var i = 0; - foreach (var mappedEdit in mappedEdits) - { - if (mappedEdit.IsDefault) - { - continue; - } - - foreach (var textChange in mappedEdit.TextChanges) - { - changes[i++] = (mappedEdit.FilePath, textChange); - } - } - - Debug.Assert(i == changesCount); - return changes.ToImmutableArray(); - } - - public async Task> MapSpansAsync( - Document document, - IEnumerable spans, - CancellationToken cancellationToken) - { - var razorSpans = await _razorMappingService.MapSpansAsync(document, spans, cancellationToken).ConfigureAwait(false); - var roslynSpans = new MappedSpanResult[razorSpans.Length]; - for (var i = 0; i < razorSpans.Length; i++) - { - var razorSpan = razorSpans[i]; - if (razorSpan.IsDefault) - { - // Unmapped location - roslynSpans[i] = default; - } - else - { - roslynSpans[i] = new MappedSpanResult(razorSpan.FilePath, razorSpan.LinePositionSpan, razorSpan.Span); - } - } - - return roslynSpans.ToImmutableArray(); - } - } -} diff --git a/src/Tools/ExternalAccess/Razor/RazorSpanMappingServiceWrapper.cs b/src/Tools/ExternalAccess/Razor/RazorSpanMappingServiceWrapper.cs deleted file mode 100644 index d186da23ac528..0000000000000 --- a/src/Tools/ExternalAccess/Razor/RazorSpanMappingServiceWrapper.cs +++ /dev/null @@ -1,71 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Text; - -namespace Microsoft.CodeAnalysis.ExternalAccess.Razor -{ - internal sealed class RazorSpanMappingServiceWrapper : AbstractSpanMappingService - { - private readonly IRazorSpanMappingService _razorSpanMappingService; - - public RazorSpanMappingServiceWrapper(IRazorSpanMappingService razorSpanMappingService) - { - _razorSpanMappingService = razorSpanMappingService ?? throw new ArgumentNullException(nameof(razorSpanMappingService)); - } - - /// - /// Modern razor span mapping service can handle if we add imports. Razor will then rewrite that - /// to their own form. - /// - public override bool SupportsMappingImportDirectives => true; - - public override async Task> GetMappedTextChangesAsync( - Document oldDocument, - Document newDocument, - CancellationToken cancellationToken) - { - var diffService = newDocument.Project.Solution.Services.GetRequiredService(); - - // This is a hack that finds a minimal diff. It's not the ideal algorithm but should cover most scenarios. In the future, - // we should improve this algorithm - see https://github.com/dotnet/roslyn/issues/53346 for additional details. - var textChanges = await diffService.GetTextChangesAsync(oldDocument, newDocument, cancellationToken).ConfigureAwait(false); - var mappedSpanResults = await MapSpansAsync(oldDocument, textChanges.Select(tc => tc.Span), cancellationToken).ConfigureAwait(false); - - var mappedTextChanges = MatchMappedSpansToTextChanges(textChanges, mappedSpanResults); - return mappedTextChanges; - } - - public override async Task> MapSpansAsync( - Document document, - IEnumerable spans, - CancellationToken cancellationToken) - { - var razorSpans = await _razorSpanMappingService.MapSpansAsync(document, spans, cancellationToken).ConfigureAwait(false); - var roslynSpans = new MappedSpanResult[razorSpans.Length]; - for (var i = 0; i < razorSpans.Length; i++) - { - var razorSpan = razorSpans[i]; - if (razorSpan.IsDefault) - { - // Unmapped location - roslynSpans[i] = default; - } - else - { - roslynSpans[i] = new MappedSpanResult(razorSpan.FilePath, razorSpan.LinePositionSpan, razorSpan.Span); - } - } - - return roslynSpans.ToImmutableArray(); - } - } -} diff --git a/src/Tools/ExternalAccess/Razor/RazorUri.cs b/src/Tools/ExternalAccess/Razor/Shared/Constants.cs similarity index 51% rename from src/Tools/ExternalAccess/Razor/RazorUri.cs rename to src/Tools/ExternalAccess/Razor/Shared/Constants.cs index dd0e03df5dab1..55ab3341d5c49 100644 --- a/src/Tools/ExternalAccess/Razor/RazorUri.cs +++ b/src/Tools/ExternalAccess/Razor/Shared/Constants.cs @@ -2,16 +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 Microsoft.CodeAnalysis.LanguageServer; namespace Microsoft.CodeAnalysis.ExternalAccess.Razor; -internal static class RazorUri +internal static class Constants { - public static Uri CreateAbsoluteUri(string absolutePath) - => ProtocolConversions.CreateAbsoluteUri(absolutePath); - - public static string GetDocumentFilePathFromUri(Uri uri) - => ProtocolConversions.GetDocumentFilePathFromUri(uri); + public const string RazorLanguageName = LanguageInfoProvider.RazorLanguageName; } diff --git a/src/Tools/ExternalAccess/Razor/Shared/IRazorClientLanguageServerManager.cs b/src/Tools/ExternalAccess/Razor/Shared/IRazorClientLanguageServerManager.cs new file mode 100644 index 0000000000000..1885c5e887230 --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Shared/IRazorClientLanguageServerManager.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.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.LanguageServer; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor; + +internal interface IRazorClientLanguageServerManager : ILspService +{ + ValueTask SendNotificationAsync(string methodName, CancellationToken cancellationToken); + ValueTask SendNotificationAsync(string methodName, TParams @params, CancellationToken cancellationToken); + ValueTask SendRequestAsync(string methodName, CancellationToken cancellationToken); + Task SendRequestAsync(string methodName, TParams @params, CancellationToken cancellationToken); + ValueTask SendRequestAsync(string methodName, TParams @params, CancellationToken cancellationToken); +} + +// TODO: Remove this interface once razor inserts and moves off of it. +internal interface IRazorCohostClientLanguageServerManager : IRazorClientLanguageServerManager +{ } diff --git a/src/Tools/ExternalAccess/Razor/IRazorDocumentExcerptService.cs b/src/Tools/ExternalAccess/Razor/Shared/IRazorDocumentExcerptService.cs similarity index 97% rename from src/Tools/ExternalAccess/Razor/IRazorDocumentExcerptService.cs rename to src/Tools/ExternalAccess/Razor/Shared/IRazorDocumentExcerptService.cs index 8f108e50f09d8..14c006e35d276 100644 --- a/src/Tools/ExternalAccess/Razor/IRazorDocumentExcerptService.cs +++ b/src/Tools/ExternalAccess/Razor/Shared/IRazorDocumentExcerptService.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.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Text; diff --git a/src/Tools/ExternalAccess/Razor/Shared/IRazorDocumentOperationService.cs b/src/Tools/ExternalAccess/Razor/Shared/IRazorDocumentOperationService.cs new file mode 100644 index 0000000000000..5a5b2d2c078ed --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Shared/IRazorDocumentOperationService.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. + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor; + +internal interface IRazorDocumentOperationService +{ + /// + /// document version of + /// + bool CanApplyChange { get; } + + /// + /// indicates whether this document supports diagnostics or not + /// + bool SupportDiagnostics { get; } +} diff --git a/src/Tools/ExternalAccess/Razor/IRazorDocumentPropertiesService.cs b/src/Tools/ExternalAccess/Razor/Shared/IRazorDocumentPropertiesService.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/IRazorDocumentPropertiesService.cs rename to src/Tools/ExternalAccess/Razor/Shared/IRazorDocumentPropertiesService.cs diff --git a/src/Tools/ExternalAccess/Razor/Shared/IRazorDocumentServiceProvider.cs b/src/Tools/ExternalAccess/Razor/Shared/IRazorDocumentServiceProvider.cs new file mode 100644 index 0000000000000..a693aa5d5e624 --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Shared/IRazorDocumentServiceProvider.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. + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor; + +internal interface IRazorDocumentServiceProvider : IRazorDocumentOperationService +{ + /// + /// Gets a document specific service provided by the host identified by the service type. + /// If the host does not provide the service, this method returns null. + /// + TService? GetService() where TService : class; +} diff --git a/src/Tools/ExternalAccess/Razor/Shared/IRazorDynamicFileInfoProvider.cs b/src/Tools/ExternalAccess/Razor/Shared/IRazorDynamicFileInfoProvider.cs new file mode 100644 index 0000000000000..e935bd0e48db8 --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Shared/IRazorDynamicFileInfoProvider.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.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.LanguageServer; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor; + +internal interface IRazorDynamicFileInfoProvider +{ + /// + /// indicate content of a file has updated. the event argument "string" should be same as "filepath" given to + /// + event EventHandler? Updated; + + /// + /// return for the context given + /// + Task GetDynamicFileInfoAsync(ProjectId projectId, string? projectFilePath, string filePath, CancellationToken cancellationToken); + + /// + /// let provider know certain file has been removed + /// + Task RemoveDynamicFileInfoAsync(ProjectId projectId, string? projectFilePath, string filePath, CancellationToken cancellationToken); +} diff --git a/src/Tools/ExternalAccess/Razor/Shared/IRazorMappingService.cs b/src/Tools/ExternalAccess/Razor/Shared/IRazorMappingService.cs new file mode 100644 index 0000000000000..c36a3de25bb46 --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Shared/IRazorMappingService.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.Collections.Generic; +using System.Collections.Immutable; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor; + +internal interface IRazorMappingService +{ + Task> MapSpansAsync(Document document, IEnumerable spans, CancellationToken cancellationToken); + Task> MapTextChangesAsync(Document oldDocument, Document newDocument, CancellationToken cancellationToken); +} diff --git a/src/Tools/ExternalAccess/Razor/Shared/IRazorServiceProvider.cs b/src/Tools/ExternalAccess/Razor/Shared/IRazorServiceProvider.cs new file mode 100644 index 0000000000000..8810125f7e6bf --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Shared/IRazorServiceProvider.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. + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Shared; + +internal interface IRazorServiceProvider +{ + /// + /// Gets a document specific service provided by the host identified by the service type. + /// If the host does not provide the service, this method returns null. + /// + TService? GetService() where TService : class; +} diff --git a/src/Tools/ExternalAccess/Razor/Shared/Microsoft.CodeAnalysis.ExternalAccess.Razor.Shared.projitems b/src/Tools/ExternalAccess/Razor/Shared/Microsoft.CodeAnalysis.ExternalAccess.Razor.Shared.projitems new file mode 100644 index 0000000000000..2c3369d760c2a --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Shared/Microsoft.CodeAnalysis.ExternalAccess.Razor.Shared.projitems @@ -0,0 +1,31 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + 4853a78a-4ec4-4d86-9f02-d0ddeae85520 + + + Microsoft.CodeAnalysis.ExternalAccess.Razor.Shared + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Tools/ExternalAccess/Razor/Shared/Microsoft.CodeAnalysis.ExternalAccess.Razor.Shared.shproj b/src/Tools/ExternalAccess/Razor/Shared/Microsoft.CodeAnalysis.ExternalAccess.Razor.Shared.shproj new file mode 100644 index 0000000000000..150d5f8529ce1 --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Shared/Microsoft.CodeAnalysis.ExternalAccess.Razor.Shared.shproj @@ -0,0 +1,13 @@ + + + + 4853a78a-4ec4-4d86-9f02-d0ddeae85520 + 14.0 + + + + + + + + diff --git a/src/Tools/ExternalAccess/Razor/RazorClassificationOptionsWrapper.cs b/src/Tools/ExternalAccess/Razor/Shared/RazorClassificationOptionsWrapper.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/RazorClassificationOptionsWrapper.cs rename to src/Tools/ExternalAccess/Razor/Shared/RazorClassificationOptionsWrapper.cs diff --git a/src/Tools/ExternalAccess/Razor/Cohost/RazorCohostClientLanguageServerManager.cs b/src/Tools/ExternalAccess/Razor/Shared/RazorClientLanguageServerManager.cs similarity index 86% rename from src/Tools/ExternalAccess/Razor/Cohost/RazorCohostClientLanguageServerManager.cs rename to src/Tools/ExternalAccess/Razor/Shared/RazorClientLanguageServerManager.cs index bde9f3741451f..aa9caa4c8b8ad 100644 --- a/src/Tools/ExternalAccess/Razor/Cohost/RazorCohostClientLanguageServerManager.cs +++ b/src/Tools/ExternalAccess/Razor/Shared/RazorClientLanguageServerManager.cs @@ -6,9 +6,9 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.LanguageServer; -namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost; +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor; -internal class RazorCohostClientLanguageServerManager(IClientLanguageServerManager clientLanguageServerManager) : IRazorCohostClientLanguageServerManager +internal class RazorClientLanguageServerManager(IClientLanguageServerManager clientLanguageServerManager) : IRazorCohostClientLanguageServerManager { public Task SendRequestAsync(string methodName, TParams @params, CancellationToken cancellationToken) => clientLanguageServerManager.SendRequestAsync(methodName, @params, cancellationToken); diff --git a/src/Tools/ExternalAccess/Razor/RazorDocumentExcerptServiceWrapper.cs b/src/Tools/ExternalAccess/Razor/Shared/RazorDocumentExcerptServiceWrapper.cs similarity index 98% rename from src/Tools/ExternalAccess/Razor/RazorDocumentExcerptServiceWrapper.cs rename to src/Tools/ExternalAccess/Razor/Shared/RazorDocumentExcerptServiceWrapper.cs index 56fa64ecf97eb..44f8d1e76e2df 100644 --- a/src/Tools/ExternalAccess/Razor/RazorDocumentExcerptServiceWrapper.cs +++ b/src/Tools/ExternalAccess/Razor/Shared/RazorDocumentExcerptServiceWrapper.cs @@ -7,7 +7,6 @@ using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.Razor { diff --git a/src/Tools/ExternalAccess/Razor/RazorDocumentPropertiesServiceWrapper.cs b/src/Tools/ExternalAccess/Razor/Shared/RazorDocumentPropertiesServiceWrapper.cs similarity index 98% rename from src/Tools/ExternalAccess/Razor/RazorDocumentPropertiesServiceWrapper.cs rename to src/Tools/ExternalAccess/Razor/Shared/RazorDocumentPropertiesServiceWrapper.cs index 64fba48936485..5483060f8def5 100644 --- a/src/Tools/ExternalAccess/Razor/RazorDocumentPropertiesServiceWrapper.cs +++ b/src/Tools/ExternalAccess/Razor/Shared/RazorDocumentPropertiesServiceWrapper.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 Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.ExternalAccess.Razor diff --git a/src/Tools/ExternalAccess/Razor/RazorDocumentServiceProviderWrapper.cs b/src/Tools/ExternalAccess/Razor/Shared/RazorDocumentServiceProviderWrapper.cs similarity index 86% rename from src/Tools/ExternalAccess/Razor/RazorDocumentServiceProviderWrapper.cs rename to src/Tools/ExternalAccess/Razor/Shared/RazorDocumentServiceProviderWrapper.cs index 1611270558b17..6f292bc9e852b 100644 --- a/src/Tools/ExternalAccess/Razor/RazorDocumentServiceProviderWrapper.cs +++ b/src/Tools/ExternalAccess/Razor/Shared/RazorDocumentServiceProviderWrapper.cs @@ -36,17 +36,13 @@ public RazorDocumentServiceProviderWrapper(IRazorDocumentServiceProvider innerDo ref _lazySpanMappingService, static documentServiceProvider => { - // Razor is transitioning implementations from IRazorSpanMappingService to IRazorMappingService. - // While this is happening the service may not be available. If it is, use the newer implementation, - // otherwise fallback to IRazorSpanMappingService var razorMappingService = documentServiceProvider.GetService(); if (razorMappingService is not null) { return new RazorMappingServiceWrapper(razorMappingService); } - var razorSpanMappingService = documentServiceProvider.GetService(); - return razorSpanMappingService != null ? new RazorSpanMappingServiceWrapper(razorSpanMappingService) : null; + return null; }, _innerDocumentServiceProvider); diff --git a/src/Tools/ExternalAccess/Razor/Shared/RazorDynamicFileInfo.cs b/src/Tools/ExternalAccess/Razor/Shared/RazorDynamicFileInfo.cs new file mode 100644 index 0000000000000..e01767ffaa333 --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Shared/RazorDynamicFileInfo.cs @@ -0,0 +1,54 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Host; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor; + +/// +/// provides info on the given file +/// +/// this will be used to provide dynamic content such as generated content from cshtml to workspace +/// we acquire this from exposed from external components such as razor for cshtml +/// +internal sealed class RazorDynamicFileInfo +{ + public RazorDynamicFileInfo(string filePath, SourceCodeKind sourceCodeKind, TextLoader textLoader, IRazorDocumentServiceProvider documentServiceProvider) + { + FilePath = filePath; + SourceCodeKind = sourceCodeKind; + TextLoader = textLoader; + DocumentServiceProvider = documentServiceProvider; + } + + /// + /// for now, return null. in future, we will use this to get right options from editorconfig + /// + public string FilePath { get; } + + /// + /// return for this file + /// + public SourceCodeKind SourceCodeKind { get; } + + /// + /// return to load content for the dynamic file + /// + public TextLoader TextLoader { get; } + + /// + /// return for the contents it provides + /// + public IRazorDocumentServiceProvider DocumentServiceProvider { get; } + + /// + /// Constructs a new from an existing but with updated + /// text loader and document service provider coming from this instance. + /// + public DocumentInfo ToUpdatedDocumentInfo(DocumentInfo existingDocumentInfo) + { + var serviceProvider = new RazorDocumentServiceProviderWrapper(this.DocumentServiceProvider); + return new DocumentInfo(existingDocumentInfo.Attributes, this.TextLoader, serviceProvider); + } +} diff --git a/src/Tools/ExternalAccess/Razor/RazorExcerptMode.cs b/src/Tools/ExternalAccess/Razor/Shared/RazorExcerptMode.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/RazorExcerptMode.cs rename to src/Tools/ExternalAccess/Razor/Shared/RazorExcerptMode.cs diff --git a/src/Tools/ExternalAccess/Razor/RazorExcerptResult.cs b/src/Tools/ExternalAccess/Razor/Shared/RazorExcerptResult.cs similarity index 100% rename from src/Tools/ExternalAccess/Razor/RazorExcerptResult.cs rename to src/Tools/ExternalAccess/Razor/Shared/RazorExcerptResult.cs diff --git a/src/Tools/ExternalAccess/Razor/Shared/RazorMappedSpanResult.cs b/src/Tools/ExternalAccess/Razor/Shared/RazorMappedSpanResult.cs new file mode 100644 index 0000000000000..96adfdc8fb60b --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Shared/RazorMappedSpanResult.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; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor; + +internal readonly struct RazorMappedSpanResult +{ + public readonly string FilePath; + + public readonly LinePositionSpan LinePositionSpan; + + public readonly TextSpan Span; + + public RazorMappedSpanResult(string filePath, LinePositionSpan linePositionSpan, TextSpan span) + { + if (string.IsNullOrEmpty(filePath)) + { + throw new ArgumentException(nameof(filePath)); + } + + FilePath = filePath; + LinePositionSpan = linePositionSpan; + Span = span; + } + + public bool IsDefault => FilePath == null; +} + +internal readonly record struct RazorMappedEditResult(string FilePath, TextChange[] TextChanges) +{ + public bool IsDefault => FilePath == null || TextChanges == null; +} diff --git a/src/Tools/ExternalAccess/Razor/Shared/RazorMappingServiceWrapper.cs b/src/Tools/ExternalAccess/Razor/Shared/RazorMappingServiceWrapper.cs new file mode 100644 index 0000000000000..e7c2b341008aa --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Shared/RazorMappingServiceWrapper.cs @@ -0,0 +1,73 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor; + +internal sealed class RazorMappingServiceWrapper(IRazorMappingService razorMappingService) : ISpanMappingService +{ + private readonly IRazorMappingService _razorMappingService = razorMappingService; + + public bool SupportsMappingImportDirectives => true; + + public async Task> GetMappedTextChangesAsync( + Document oldDocument, + Document newDocument, + CancellationToken cancellationToken) + { + var mappedEdits = await _razorMappingService.MapTextChangesAsync(oldDocument, newDocument, cancellationToken).ConfigureAwait(false); + + var changesCount = mappedEdits.Select(e => e.IsDefault ? 0 : e.TextChanges.Length).Sum(); + var changes = new (string mappedFilePath, TextChange mappedTextChange)[changesCount]; + + var i = 0; + foreach (var mappedEdit in mappedEdits) + { + if (mappedEdit.IsDefault) + { + continue; + } + + foreach (var textChange in mappedEdit.TextChanges) + { + changes[i++] = (mappedEdit.FilePath, textChange); + } + } + + Debug.Assert(i == changesCount); + return changes.ToImmutableArray(); + } + + public async Task> MapSpansAsync( + Document document, + IEnumerable spans, + CancellationToken cancellationToken) + { + var razorSpans = await _razorMappingService.MapSpansAsync(document, spans, cancellationToken).ConfigureAwait(false); + var roslynSpans = new MappedSpanResult[razorSpans.Length]; + for (var i = 0; i < razorSpans.Length; i++) + { + var razorSpan = razorSpans[i]; + if (razorSpan.IsDefault) + { + // Unmapped location + roslynSpans[i] = default; + } + else + { + roslynSpans[i] = new MappedSpanResult(razorSpan.FilePath, razorSpan.LinePositionSpan, razorSpan.Span); + } + } + + return roslynSpans.ToImmutableArray(); + } +} diff --git a/src/Tools/ExternalAccess/RazorTest/Microsoft.CodeAnalysis.ExternalAccess.Razor.UnitTests.csproj b/src/Tools/ExternalAccess/RazorTest/Microsoft.CodeAnalysis.ExternalAccess.Razor.UnitTests.csproj index 3f7a6cdf19ec9..be2b10c7fc1ab 100644 --- a/src/Tools/ExternalAccess/RazorTest/Microsoft.CodeAnalysis.ExternalAccess.Razor.UnitTests.csproj +++ b/src/Tools/ExternalAccess/RazorTest/Microsoft.CodeAnalysis.ExternalAccess.Razor.UnitTests.csproj @@ -4,15 +4,17 @@ Library Microsoft.CodeAnalysis.ExternalAccess.Razor.UnitTests - net472 + $(NetVS);net472 - + + - + - + + \ No newline at end of file diff --git a/src/Tools/ExternalAccess/RazorTest/RazorAnalyzerAssemblyResolverTests.cs b/src/Tools/ExternalAccess/RazorTest/RazorAnalyzerAssemblyResolverTests.cs new file mode 100644 index 0000000000000..0a611aac0d914 --- /dev/null +++ b/src/Tools/ExternalAccess/RazorTest/RazorAnalyzerAssemblyResolverTests.cs @@ -0,0 +1,153 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +#if NET + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.Loader; +using System.Text; +using System.Threading.Tasks; +using Basic.Reference.Assemblies; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.UnitTests; + +public sealed class RazorAnalyzerAssemblyResolverTests : IDisposable +{ + private TempRoot TempRoot { get; } = new TempRoot(); + private int InitialAssemblyCount { get; } + + public RazorAnalyzerAssemblyResolverTests() + { + InitialAssemblyCount = AssemblyLoadContext.GetLoadContext(this.GetType().Assembly)!.Assemblies.Count(); + } + + public void Dispose() + { + TempRoot.Dispose(); + + // This test should not change the set of assemblies loaded in the current context. + var count = AssemblyLoadContext.GetLoadContext(this.GetType().Assembly)!.Assemblies.Count(); + Assert.Equal(InitialAssemblyCount, count); + } + + private void CreateRazorAssemblies(string directory, string versionNumber = "1.0.0.0") + { + foreach (var simpleName in RazorAnalyzerAssemblyResolver.RazorAssemblyNames) + { + BuildOne(simpleName); + } + + void BuildOne(string simpleName) + { + var i = simpleName.LastIndexOf('.'); + var typeName = simpleName[(i + 1)..]; + var source = $$""" + using System.Reflection; + + [assembly: AssemblyVersion("{{versionNumber}}")] + [assembly: AssemblyFileVersion("{{versionNumber}}")] + + public sealed class {{typeName}} { } + """; + + var compilation = CSharpCompilation.Create( + simpleName, + [CSharpSyntaxTree.ParseText(source)], + NetStandard20.References.All, + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + var result = compilation.Emit(Path.Combine(directory, $"{simpleName}.dll")); + Assert.True(result.Success); + } + } + + private static void RunWithLoader(Action action) + { + var compilerLoadContext = new AssemblyLoadContext("Compiler", isCollectible: true); + var currentLoadContext = new AssemblyLoadContext("Current", isCollectible: true); + var loader = new AnalyzerAssemblyLoader([], [AnalyzerAssemblyLoader.DiskAnalyzerAssemblyResolver], compilerLoadContext); +#pragma warning disable 612 + var resolver = CreateResolver(); +#pragma warning restore 612 + action(resolver, loader, currentLoadContext); + + Assert.Empty(currentLoadContext.Assemblies); + currentLoadContext.Unload(); + compilerLoadContext.Unload(); + } + + [Obsolete] + internal static RazorAnalyzerAssemblyResolver CreateResolver() => new RazorAnalyzerAssemblyResolver(); + + /// + /// When running in Visual Studio the razor generator will be redirected to the razor language + /// services directory. That will not contain all of the necessary DLLs. Anything that is a + /// platform DLL, like the object pool, will be in the VS platform directory. Need to fall back + /// to the compiler context to find those. + /// + [Fact] + public void FallbackToCompilerContext() + { + var dir1 = TempRoot.CreateDirectory().Path; + CreateRazorAssemblies(dir1); + var dir2 = TempRoot.CreateDirectory().Path; + var fileName = $"{RazorAnalyzerAssemblyResolver.ObjectPoolAssemblyName}.dll"; + File.Move(Path.Combine(dir1, fileName), Path.Combine(dir2, fileName)); + + RunWithLoader((resolver, loader, currentLoadContext) => + { + Assembly? expectedAssembly = null; + loader.CompilerLoadContext.Resolving += (context, name) => + { + if (name.Name == RazorAnalyzerAssemblyResolver.ObjectPoolAssemblyName) + { + expectedAssembly = context.LoadFromAssemblyPath(Path.Combine(dir2, fileName)); + return expectedAssembly; + } + + return null; + }; + + var actualAssembly = resolver.Resolve( + loader, + new AssemblyName(RazorAnalyzerAssemblyResolver.ObjectPoolAssemblyName), + currentLoadContext, + dir1); + Assert.NotNull(expectedAssembly); + Assert.NotNull(actualAssembly); + Assert.Same(expectedAssembly, actualAssembly); + }); + } + + [Fact] + public void FirstLoadWins() + { + var dir1 = TempRoot.CreateDirectory().Path; + CreateRazorAssemblies(dir1, versionNumber: "1.0.0.0"); + var dir2 = TempRoot.CreateDirectory().Path; + CreateRazorAssemblies(dir2, versionNumber: "2.0.0.0"); + + RunWithLoader((resolver, loader, currentLoadContext) => + { + var assembly1 = resolver.Resolve( + loader, + new AssemblyName(RazorAnalyzerAssemblyResolver.RazorCompilerAssemblyName), + currentLoadContext, + dir1); + var assembly2 = resolver.Resolve( + loader, + new AssemblyName(RazorAnalyzerAssemblyResolver.RazorCompilerAssemblyName), + currentLoadContext, + dir2); + Assert.Same(assembly1, assembly2); + }); + } +} +#endif diff --git a/src/Tools/ExternalAccess/RazorTest/RazorPredefinedProviderNameTests.cs b/src/Tools/ExternalAccess/RazorTest/RazorPredefinedProviderNameTests.cs index b0a53da76ffcd..2feee9644a518 100644 --- a/src/Tools/ExternalAccess/RazorTest/RazorPredefinedProviderNameTests.cs +++ b/src/Tools/ExternalAccess/RazorTest/RazorPredefinedProviderNameTests.cs @@ -50,14 +50,14 @@ private static ImmutableDictionary GetPredefinedNamesFromFields( { return namesType.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public) .Where(field => field.FieldType == typeof(string)) - .ToImmutableDictionary(field => field.Name, field => (string)field.GetValue(null)); + .ToImmutableDictionary(field => field.Name, field => (string)field.GetValue(null)!); } private static ImmutableDictionary GetPredefinedNamesFromProperties(Type namesType) { return namesType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public) .Where(property => property.PropertyType == typeof(string)) - .ToImmutableDictionary(property => property.Name, property => (string)property.GetValue(null)); + .ToImmutableDictionary(property => property.Name, property => (string)property.GetValue(null)!); } } } diff --git a/src/Tools/ExternalAccess/Xaml/Microsoft.CodeAnalysis.ExternalAccess.Xaml.csproj b/src/Tools/ExternalAccess/Xaml/Microsoft.CodeAnalysis.ExternalAccess.Xaml.csproj index 4310078bf9b32..d17ef579337c3 100644 --- a/src/Tools/ExternalAccess/Xaml/Microsoft.CodeAnalysis.ExternalAccess.Xaml.csproj +++ b/src/Tools/ExternalAccess/Xaml/Microsoft.CodeAnalysis.ExternalAccess.Xaml.csproj @@ -31,14 +31,7 @@ - - - - - - - diff --git a/src/Tools/Replay/Replay.csproj b/src/Tools/Replay/Replay.csproj index 0f52b65a3e8f4..fd3d130c7aca8 100644 --- a/src/Tools/Replay/Replay.csproj +++ b/src/Tools/Replay/Replay.csproj @@ -11,12 +11,8 @@ - - - - @@ -36,4 +32,6 @@ + + diff --git a/src/Tools/SemanticSearch/BuildTask/GenerateFilteredReferenceAssembliesTask.cs b/src/Tools/SemanticSearch/BuildTask/GenerateFilteredReferenceAssembliesTask.cs index 6f394264544f9..5a1203605807c 100644 --- a/src/Tools/SemanticSearch/BuildTask/GenerateFilteredReferenceAssembliesTask.cs +++ b/src/Tools/SemanticSearch/BuildTask/GenerateFilteredReferenceAssembliesTask.cs @@ -66,6 +66,11 @@ public sealed class GenerateFilteredReferenceAssembliesTask : Task [Required] public string ApisDir { get; private set; } = null!; + /// + /// True to report an error if any changes in Semantic Search APIs are detected. + /// + public bool RequireNoApiChanges { get; private set; } = false; + public override bool Execute() { try @@ -123,12 +128,14 @@ internal void ExecuteImpl(IEnumerable<(string apiSpecPath, IReadOnlyList return; } - WriteApis(Path.Combine(ApisDir, assemblyName + ".txt"), peImageBuffer); + WriteApis(assemblyName, peImageBuffer); } } - internal void WriteApis(string outputFilePath, byte[] peImage) + internal void WriteApis(string assemblyName, byte[] peImage) { + string outputFilePath = Path.Combine(ApisDir, assemblyName + ".txt"); + using var readableStream = new MemoryStream(peImage, writable: false); var metadataRef = MetadataReference.CreateFromStream(readableStream); var compilation = CSharpCompilation.Create("Metadata", references: [metadataRef]); @@ -146,34 +153,47 @@ internal void WriteApis(string outputFilePath, byte[] peImage) // Doc ids start with "X:" prefix, where X is member kind ('T', 'M' or 'F'): apis.Sort(static (x, y) => x.AsSpan()[2..].CompareTo(y.AsSpan()[2..], StringComparison.Ordinal)); - var newContent = "# Generated, do not update manually\r\n" + - string.Join("\r\n", apis); + var newContent = $"# Generated, do not update manually{Environment.NewLine}" + + string.Join(Environment.NewLine, apis); - string currentContent; - try - { - currentContent = File.ReadAllText(outputFilePath, Encoding.UTF8); - } - catch (Exception) + if (RequireNoApiChanges) { - currentContent = ""; - } + var oldContent = ""; - if (currentContent != newContent) - { - try + if (File.Exists(outputFilePath)) { - File.WriteAllText(outputFilePath, newContent); - Log.LogMessage($"Baseline updated: '{outputFilePath}'"); + try + { + oldContent = File.ReadAllText(outputFilePath, Encoding.UTF8); + } + catch (FileNotFoundException) + { + } + catch (Exception e) + { + Log.LogError($"Unable to read '{outputFilePath}': {e.Message}"); + return; + } } - catch (Exception e) + + if (oldContent != newContent) { - Log.LogError($"Error updating baseline '{outputFilePath}': {e.Message}"); + Log.LogError( + $"APIs listed in file '{outputFilePath}' do not match the public APIs exposed by '{assemblyName}'. " + + $"Build SemanticSearch.ReferenceAssemblies project locally to update the file and review the changes."); + + return; } } - else + + try + { + File.WriteAllText(outputFilePath, newContent, Encoding.UTF8); + Log.LogMessage($"Baseline updated: '{outputFilePath}'"); + } + catch (Exception e) { - Log.LogMessage($"Baseline not updated '{outputFilePath}'"); + Log.LogError($"Error updating baseline '{outputFilePath}': {e.Message}"); } } diff --git a/src/Tools/SemanticSearch/BuildTask/SemanticSearch.BuildTask.csproj b/src/Tools/SemanticSearch/BuildTask/SemanticSearch.BuildTask.csproj index 9e28511dab63f..f0184c57d0cd0 100644 --- a/src/Tools/SemanticSearch/BuildTask/SemanticSearch.BuildTask.csproj +++ b/src/Tools/SemanticSearch/BuildTask/SemanticSearch.BuildTask.csproj @@ -17,10 +17,9 @@ - - + diff --git a/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/Microsoft.CodeAnalysis.CSharp.txt b/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/Microsoft.CodeAnalysis.CSharp.txt index 3075a24a86c70..b37e71720462c 100644 --- a/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/Microsoft.CodeAnalysis.CSharp.txt +++ b/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/Microsoft.CodeAnalysis.CSharp.txt @@ -1,4 +1,4 @@ -# Generated, do not update manually +# Generated, do not update manually Microsoft.CodeAnalysis.CSharp.AwaitExpressionInfo Microsoft.CodeAnalysis.CSharp.AwaitExpressionInfo.Equals(Microsoft.CodeAnalysis.CSharp.AwaitExpressionInfo) Microsoft.CodeAnalysis.CSharp.AwaitExpressionInfo.Equals(System.Object) @@ -407,6 +407,7 @@ Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitExplicitInterfaceSpecifi Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitExpressionColon(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitExpressionElement(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionElementSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitExpressionStatement(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionStatementSyntax) +Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitExtensionDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitExternAliasDirective(Microsoft.CodeAnalysis.CSharp.Syntax.ExternAliasDirectiveSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitFieldDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitFieldExpression(Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax) @@ -701,6 +702,7 @@ Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExplicitInterfaceSpecifie Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExpressionColon(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExpressionElement(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionElementSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExpressionStatement(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionStatementSyntax) +Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExtensionDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExternAliasDirective(Microsoft.CodeAnalysis.CSharp.Syntax.ExternAliasDirectiveSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFieldDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFieldExpression(Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax) @@ -949,6 +951,7 @@ Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.VisitExplicitInterfaceSpecif Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.VisitExpressionColon(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.VisitExpressionElement(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionElementSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.VisitExpressionStatement(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionStatementSyntax) +Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.VisitExtensionDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.VisitExternAliasDirective(Microsoft.CodeAnalysis.CSharp.Syntax.ExternAliasDirectiveSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.VisitFieldDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.VisitFieldExpression(Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax) @@ -1177,6 +1180,7 @@ Microsoft.CodeAnalysis.CSharp.ForEachStatementInfo.get_GetEnumeratorMethod Microsoft.CodeAnalysis.CSharp.ForEachStatementInfo.get_IsAsynchronous Microsoft.CodeAnalysis.CSharp.ForEachStatementInfo.get_MoveNextMethod Microsoft.CodeAnalysis.CSharp.InterceptableLocation +Microsoft.CodeAnalysis.CSharp.InterceptableLocation.Equals(Microsoft.CodeAnalysis.CSharp.InterceptableLocation) Microsoft.CodeAnalysis.CSharp.InterceptableLocation.Equals(System.Object) Microsoft.CodeAnalysis.CSharp.InterceptableLocation.GetDisplayLocation Microsoft.CodeAnalysis.CSharp.InterceptableLocation.GetHashCode @@ -2450,6 +2454,38 @@ Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionStatementSyntax.get_AttributeList Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionStatementSyntax.get_Expression Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionStatementSyntax.get_SemicolonToken Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor) +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.Accept``1(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor{``0}) +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AddAttributeLists(Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax[]) +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AddConstraintClauses(Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterConstraintClauseSyntax[]) +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AddMembers(Microsoft.CodeAnalysis.CSharp.Syntax.MemberDeclarationSyntax[]) +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AddModifiers(Microsoft.CodeAnalysis.SyntaxToken[]) +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AddParameterListParameters(Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax[]) +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AddTypeParameterListParameters(Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterSyntax[]) +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.Update(Microsoft.CodeAnalysis.SyntaxList{Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax},Microsoft.CodeAnalysis.SyntaxTokenList,Microsoft.CodeAnalysis.SyntaxToken,Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax,Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax,Microsoft.CodeAnalysis.SyntaxList{Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterConstraintClauseSyntax},Microsoft.CodeAnalysis.SyntaxToken,Microsoft.CodeAnalysis.SyntaxList{Microsoft.CodeAnalysis.CSharp.Syntax.MemberDeclarationSyntax},Microsoft.CodeAnalysis.SyntaxToken,Microsoft.CodeAnalysis.SyntaxToken) +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithAttributeLists(Microsoft.CodeAnalysis.SyntaxList{Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax}) +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithCloseBraceToken(Microsoft.CodeAnalysis.SyntaxToken) +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithConstraintClauses(Microsoft.CodeAnalysis.SyntaxList{Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterConstraintClauseSyntax}) +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithKeyword(Microsoft.CodeAnalysis.SyntaxToken) +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithMembers(Microsoft.CodeAnalysis.SyntaxList{Microsoft.CodeAnalysis.CSharp.Syntax.MemberDeclarationSyntax}) +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithModifiers(Microsoft.CodeAnalysis.SyntaxTokenList) +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithOpenBraceToken(Microsoft.CodeAnalysis.SyntaxToken) +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithParameterList(Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax) +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithSemicolonToken(Microsoft.CodeAnalysis.SyntaxToken) +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithTypeParameterList(Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax) +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.get_AttributeLists +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.get_BaseList +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.get_CloseBraceToken +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.get_ConstraintClauses +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.get_Identifier +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.get_Keyword +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.get_Members +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.get_Modifiers +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.get_OpenBraceToken +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.get_ParameterList +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.get_SemicolonToken +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.get_TypeParameterList Microsoft.CodeAnalysis.CSharp.Syntax.ExternAliasDirectiveSyntax Microsoft.CodeAnalysis.CSharp.Syntax.ExternAliasDirectiveSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor) Microsoft.CodeAnalysis.CSharp.Syntax.ExternAliasDirectiveSyntax.Accept``1(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor{``0}) @@ -4946,6 +4982,9 @@ Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExpressionStatement(Microsoft.CodeAn Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExpressionStatement(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax,Microsoft.CodeAnalysis.SyntaxToken) Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExpressionStatement(Microsoft.CodeAnalysis.SyntaxList{Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax},Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax) Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExpressionStatement(Microsoft.CodeAnalysis.SyntaxList{Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax},Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax,Microsoft.CodeAnalysis.SyntaxToken) +Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExtensionDeclaration +Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExtensionDeclaration(Microsoft.CodeAnalysis.SyntaxList{Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax},Microsoft.CodeAnalysis.SyntaxTokenList,Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax,Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax,Microsoft.CodeAnalysis.SyntaxList{Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterConstraintClauseSyntax},Microsoft.CodeAnalysis.SyntaxList{Microsoft.CodeAnalysis.CSharp.Syntax.MemberDeclarationSyntax}) +Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExtensionDeclaration(Microsoft.CodeAnalysis.SyntaxList{Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax},Microsoft.CodeAnalysis.SyntaxTokenList,Microsoft.CodeAnalysis.SyntaxToken,Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax,Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax,Microsoft.CodeAnalysis.SyntaxList{Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterConstraintClauseSyntax},Microsoft.CodeAnalysis.SyntaxToken,Microsoft.CodeAnalysis.SyntaxList{Microsoft.CodeAnalysis.CSharp.Syntax.MemberDeclarationSyntax},Microsoft.CodeAnalysis.SyntaxToken,Microsoft.CodeAnalysis.SyntaxToken) Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExternAliasDirective(Microsoft.CodeAnalysis.SyntaxToken) Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExternAliasDirective(Microsoft.CodeAnalysis.SyntaxToken,Microsoft.CodeAnalysis.SyntaxToken,Microsoft.CodeAnalysis.SyntaxToken,Microsoft.CodeAnalysis.SyntaxToken) Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExternAliasDirective(System.String) @@ -5821,6 +5860,8 @@ Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExplicitKeyword Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExpressionColon Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExpressionElement Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExpressionStatement +Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExtensionDeclaration +Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExtensionKeyword Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExternAliasDirective Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExternKeyword Microsoft.CodeAnalysis.CSharp.SyntaxKind.FalseKeyword diff --git a/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/Microsoft.CodeAnalysis.txt b/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/Microsoft.CodeAnalysis.txt index 7f8d403ef4ae5..8ca7dbf98abde 100644 --- a/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/Microsoft.CodeAnalysis.txt +++ b/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/Microsoft.CodeAnalysis.txt @@ -1,4 +1,4 @@ -# Generated, do not update manually +# Generated, do not update manually Microsoft.CodeAnalysis.Accessibility Microsoft.CodeAnalysis.Accessibility.Friend Microsoft.CodeAnalysis.Accessibility.Internal @@ -542,6 +542,7 @@ Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.GetGenerators Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.GetGenerators(System.String) Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.GetGeneratorsForAllLanguages Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.GetHashCode +Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.ToString Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.add_AnalyzerLoadFailed(System.EventHandler{Microsoft.CodeAnalysis.Diagnostics.AnalyzerLoadFailureEventArgs}) Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.get_AssemblyLoader Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.get_Display @@ -1168,10 +1169,13 @@ Microsoft.CodeAnalysis.IErrorTypeSymbol.get_CandidateSymbols Microsoft.CodeAnalysis.IEventSymbol Microsoft.CodeAnalysis.IEventSymbol.get_AddMethod Microsoft.CodeAnalysis.IEventSymbol.get_ExplicitInterfaceImplementations +Microsoft.CodeAnalysis.IEventSymbol.get_IsPartialDefinition Microsoft.CodeAnalysis.IEventSymbol.get_IsWindowsRuntimeEvent Microsoft.CodeAnalysis.IEventSymbol.get_NullableAnnotation Microsoft.CodeAnalysis.IEventSymbol.get_OriginalDefinition Microsoft.CodeAnalysis.IEventSymbol.get_OverriddenEvent +Microsoft.CodeAnalysis.IEventSymbol.get_PartialDefinitionPart +Microsoft.CodeAnalysis.IEventSymbol.get_PartialImplementationPart Microsoft.CodeAnalysis.IEventSymbol.get_RaiseMethod Microsoft.CodeAnalysis.IEventSymbol.get_RemoveMethod Microsoft.CodeAnalysis.IEventSymbol.get_Type @@ -1467,8 +1471,10 @@ Microsoft.CodeAnalysis.ITypeSymbol.ToMinimalDisplayString(Microsoft.CodeAnalysis Microsoft.CodeAnalysis.ITypeSymbol.WithNullableAnnotation(Microsoft.CodeAnalysis.NullableAnnotation) Microsoft.CodeAnalysis.ITypeSymbol.get_AllInterfaces Microsoft.CodeAnalysis.ITypeSymbol.get_BaseType +Microsoft.CodeAnalysis.ITypeSymbol.get_ExtensionParameter Microsoft.CodeAnalysis.ITypeSymbol.get_Interfaces Microsoft.CodeAnalysis.ITypeSymbol.get_IsAnonymousType +Microsoft.CodeAnalysis.ITypeSymbol.get_IsExtension Microsoft.CodeAnalysis.ITypeSymbol.get_IsNativeIntegerType Microsoft.CodeAnalysis.ITypeSymbol.get_IsReadOnly Microsoft.CodeAnalysis.ITypeSymbol.get_IsRecord @@ -3953,6 +3959,7 @@ Microsoft.CodeAnalysis.TypeKind.Delegate Microsoft.CodeAnalysis.TypeKind.Dynamic Microsoft.CodeAnalysis.TypeKind.Enum Microsoft.CodeAnalysis.TypeKind.Error +Microsoft.CodeAnalysis.TypeKind.Extension Microsoft.CodeAnalysis.TypeKind.FunctionPointer Microsoft.CodeAnalysis.TypeKind.Interface Microsoft.CodeAnalysis.TypeKind.Module diff --git a/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/System.Collections.Immutable.txt b/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/System.Collections.Immutable.txt index 1977066cdea78..0769220e56547 100644 --- a/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/System.Collections.Immutable.txt +++ b/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/System.Collections.Immutable.txt @@ -1,4 +1,4 @@ -# Generated, do not update manually +# Generated, do not update manually System.Collections.Frozen.FrozenDictionary System.Collections.Frozen.FrozenDictionary.ToFrozenDictionary``2(System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{``0,``1}},System.Collections.Generic.IEqualityComparer{``0}) System.Collections.Frozen.FrozenDictionary.ToFrozenDictionary``2(System.Collections.Generic.IEnumerable{``0},System.Func{``0,``1},System.Collections.Generic.IEqualityComparer{``1}) @@ -20,6 +20,8 @@ System.Collections.Frozen.FrozenDictionary`2.get_Item(`0) System.Collections.Frozen.FrozenDictionary`2.get_Keys System.Collections.Frozen.FrozenDictionary`2.get_Values System.Collections.Frozen.FrozenSet +System.Collections.Frozen.FrozenSet.Create``1(System.Collections.Generic.IEqualityComparer{``0},System.ReadOnlySpan{``0}) +System.Collections.Frozen.FrozenSet.Create``1(System.ReadOnlySpan{``0}) System.Collections.Frozen.FrozenSet.ToFrozenSet``1(System.Collections.Generic.IEnumerable{``0},System.Collections.Generic.IEqualityComparer{``0}) System.Collections.Frozen.FrozenSet`1 System.Collections.Frozen.FrozenSet`1.Contains(`0) diff --git a/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/System.Collections.txt b/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/System.Collections.txt index 62f756acc8c59..4071eee51a37e 100644 --- a/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/System.Collections.txt +++ b/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/System.Collections.txt @@ -1,4 +1,4 @@ -# Generated, do not update manually +# Generated, do not update manually System.Collections.BitArray System.Collections.BitArray.#ctor(System.Boolean[]) System.Collections.BitArray.#ctor(System.Byte[]) diff --git a/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/System.Linq.txt b/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/System.Linq.txt index 85c524ab52cba..6bc2f9932b265 100644 --- a/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/System.Linq.txt +++ b/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/System.Linq.txt @@ -1,4 +1,4 @@ -# Generated, do not update manually +# Generated, do not update manually System.Linq.Enumerable System.Linq.Enumerable.Aggregate``1(System.Collections.Generic.IEnumerable{``0},System.Func{``0,``0,``0}) System.Linq.Enumerable.Aggregate``2(System.Collections.Generic.IEnumerable{``0},``1,System.Func{``1,``0,``1}) diff --git a/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/System.Runtime.txt b/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/System.Runtime.txt index cb02fc218dc5f..e43bf8dc555ae 100644 --- a/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/System.Runtime.txt +++ b/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/System.Runtime.txt @@ -1,4 +1,4 @@ -# Generated, do not update manually +# Generated, do not update manually System.AccessViolationException System.AccessViolationException.#ctor System.AccessViolationException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext) diff --git a/src/Tools/SemanticSearch/ReferenceAssemblies/SemanticSearch.ReferenceAssemblies.csproj b/src/Tools/SemanticSearch/ReferenceAssemblies/SemanticSearch.ReferenceAssemblies.csproj index e241734e01deb..35388a82d149c 100644 --- a/src/Tools/SemanticSearch/ReferenceAssemblies/SemanticSearch.ReferenceAssemblies.csproj +++ b/src/Tools/SemanticSearch/ReferenceAssemblies/SemanticSearch.ReferenceAssemblies.csproj @@ -45,7 +45,7 @@ '%(ReferencePath.FileName)' == 'Microsoft.CodeAnalysis.CSharp'" /> - + <_InputFile Include="@(ApiSet)" /> <_InputFile Include="@(_InputReference)" /> @@ -58,7 +58,13 @@ - + + + <_RequireNoApiChanges>false + <_RequireNoApiChanges Condition="'$(ContinuousIntegrationBuildCorrectness)' == 'true'">true + + + @@ -66,7 +72,7 @@ - + diff --git a/src/Tools/Source/CompilerGeneratorTools/Source/BoundTreeGenerator/BoundNodeClassWriter.cs b/src/Tools/Source/CompilerGeneratorTools/Source/BoundTreeGenerator/BoundNodeClassWriter.cs index 6fe668757a224..084598463ccf0 100644 --- a/src/Tools/Source/CompilerGeneratorTools/Source/BoundTreeGenerator/BoundNodeClassWriter.cs +++ b/src/Tools/Source/CompilerGeneratorTools/Source/BoundTreeGenerator/BoundNodeClassWriter.cs @@ -769,6 +769,16 @@ private IEnumerable AllSymbolOrSymbolListFields(TreeType node) return AllFields(node).Where(field => TypeIsSymbol(field) || (IsImmutableArray(field.Type, out var elementType) && TypeIsSymbol(elementType))); } + private IEnumerable AllNonTypeSymbolOrNonTypeSymbolListFields(TreeType node) + { + return AllFields(node).Where(field => IsNonTypeSymbolOrNonTypeSymbolListField(field)); + } + + private bool IsNonTypeSymbolOrNonTypeSymbolListField(Field field) + { + return TypeIsNonTypeSymbol(field) || (IsImmutableArray(field.Type, out var elementType) && TypeIsNonTypeSymbol(elementType)); + } + private NullHandling FieldNullHandling(TreeType node, string fieldName) { Field f = GetField(node, fieldName); @@ -1044,6 +1054,9 @@ string notEquals(Field field) private static bool TypeIsSymbol(Field field) => TypeIsSymbol(field.Type); private static bool TypeIsSymbol(string type) => type.TrimEnd('?').EndsWith("Symbol"); + private static bool TypeIsNonTypeSymbol(Field field) => TypeIsNonTypeSymbol(field.Type); + private static bool TypeIsNonTypeSymbol(string type) => TypeIsSymbol(type) && type.TrimEnd('?') != "TypeSymbol"; + private string StripBound(string name) { if (name.StartsWith("Bound", StringComparison.Ordinal)) @@ -1363,7 +1376,7 @@ private void WriteRewriter() Brace(); foreach (var node in _tree.Types.OfType()) { - if (!AllNodeOrNodeListFields(node).Any() && !AllTypeFields(node).Any()) + if (!AllNodeOrNodeListFields(node).Any() && !AllTypeFields(node).Any() && !AllNonTypeSymbolOrNonTypeSymbolListFields(node).Any()) { WriteLine($"{GetVisitFunctionDeclaration(node.Name, isOverride: true)} => node;"); continue; @@ -1371,20 +1384,51 @@ private void WriteRewriter() WriteLine(GetVisitFunctionDeclaration(node.Name, isOverride: true)); Brace(); bool hadField = false; + + foreach (var field in AllNonTypeSymbolOrNonTypeSymbolListFields(node)) + { + hadField = true; + + if (!IsImmutableArray(field.Type, out string elementType)) + { + WriteLine($"{field.Type} {ToCamelCase(field.Name)} = this.Visit{field.Type.TrimEnd('?')}(node.{field.Name});"); + } + else if (elementType.TrimEnd('?') == "LocalSymbol") + { + WriteLine($"{field.Type} {ToCamelCase(field.Name)} = this.VisitLocals(node.{field.Name});"); + } + else if (elementType.TrimEnd('?') == "MethodSymbol" && field.Name.EndsWith("LocalFunctions")) + { + WriteLine($"{field.Type} {ToCamelCase(field.Name)} = this.VisitDeclaredLocalFunctions(node.{field.Name});"); + } + else + { + WriteLine($"{field.Type} {ToCamelCase(field.Name)} = this.VisitSymbols<{elementType}>(node.{field.Name});"); + } + } + foreach (Field field in AllNodeOrNodeListFields(node)) { hadField = true; WriteNodeVisitCall(field); } + foreach (Field field in AllTypeFields(node)) { hadField = true; WriteLine("TypeSymbol? {0} = this.VisitType(node.{1});", ToCamelCase(field.Name), field.Name); } + if (hadField) { Write("return node.Update"); - ParenList(AllSpecifiableFields(node), field => IsDerivedOrListOfDerived("BoundNode", field.Type) || TypeIsTypeSymbol(field) ? ToCamelCase(field.Name) : string.Format("node.{0}", field.Name)); + ParenList( + AllSpecifiableFields(node), + field => IsDerivedOrListOfDerived("BoundNode", field.Type) || + TypeIsTypeSymbol(field) || + IsNonTypeSymbolOrNonTypeSymbolListField(field) ? + ToCamelCase(field.Name) : + string.Format("node.{0}", field.Name)); WriteLine(";"); } else diff --git a/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/CSharpSyntaxGenerator.csproj b/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/CSharpSyntaxGenerator.csproj index 20219430450e9..ee10aa95fbca4 100644 --- a/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/CSharpSyntaxGenerator.csproj +++ b/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/CSharpSyntaxGenerator.csproj @@ -14,6 +14,9 @@ + + + diff --git a/src/VisualStudio/CSharp/Impl/CSharpPackage.cs b/src/VisualStudio/CSharp/Impl/CSharpPackage.cs index 30bfc38cee381..be4d8b5ee2bf5 100644 --- a/src/VisualStudio/CSharp/Impl/CSharpPackage.cs +++ b/src/VisualStudio/CSharp/Impl/CSharpPackage.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.Runtime.InteropServices; @@ -57,7 +55,7 @@ namespace Microsoft.VisualStudio.LanguageServices.CSharp.LanguageService [Guid(Guids.CSharpPackageIdString)] internal sealed class CSharpPackage : AbstractPackage, IVsUserSettingsQuery { - private ObjectBrowserLibraryManager _libraryManager; + private ObjectBrowserLibraryManager? _libraryManager; private uint _libraryManagerCookie; protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) @@ -79,13 +77,13 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke } } - protected override async Task RegisterObjectBrowserLibraryManagerAsync(CancellationToken cancellationToken) + protected override void RegisterObjectBrowserLibraryManager() { - var workspace = this.ComponentModel.GetService(); + Contract.ThrowIfFalse(JoinableTaskFactory.Context.IsOnMainThread); - await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + var workspace = this.ComponentModel.GetService(); - if (await GetServiceAsync(typeof(SVsObjectManager)).ConfigureAwait(true) is IVsObjectManager2 objectManager) + if (GetService(typeof(SVsObjectManager)) is IVsObjectManager2 objectManager) { _libraryManager = new ObjectBrowserLibraryManager(this, ComponentModel, workspace); @@ -96,19 +94,19 @@ protected override async Task RegisterObjectBrowserLibraryManagerAsync(Cancellat } } - protected override async Task UnregisterObjectBrowserLibraryManagerAsync(CancellationToken cancellationToken) + protected override void UnregisterObjectBrowserLibraryManager() { - await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + Contract.ThrowIfFalse(JoinableTaskFactory.Context.IsOnMainThread); if (_libraryManagerCookie != 0) { - if (await GetServiceAsync(typeof(SVsObjectManager)).ConfigureAwait(true) is IVsObjectManager2 objectManager) + if (GetService(typeof(SVsObjectManager)) is IVsObjectManager2 objectManager) { objectManager.UnregisterLibrary(_libraryManagerCookie); _libraryManagerCookie = 0; } - _libraryManager.Dispose(); + _libraryManager?.Dispose(); _libraryManager = null; } } @@ -136,7 +134,7 @@ protected override IEnumerable CreateEditorFactories() var editorFactory = new CSharpEditorFactory(this.ComponentModel); var codePageEditorFactory = new CSharpCodePageEditorFactory(editorFactory); - return new IVsEditorFactory[] { editorFactory, codePageEditorFactory }; + return [editorFactory, codePageEditorFactory]; } protected override CSharpLanguageService CreateLanguageService() diff --git a/src/VisualStudio/CSharp/Impl/LanguageService/CSharpCodePageEditorFactory.cs b/src/VisualStudio/CSharp/Impl/LanguageService/CSharpCodePageEditorFactory.cs index 4d34e27fa8205..dcc7758ce97e3 100644 --- a/src/VisualStudio/CSharp/Impl/LanguageService/CSharpCodePageEditorFactory.cs +++ b/src/VisualStudio/CSharp/Impl/LanguageService/CSharpCodePageEditorFactory.cs @@ -2,19 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Runtime.InteropServices; using Microsoft.VisualStudio.LanguageServices.Implementation; namespace Microsoft.VisualStudio.LanguageServices.CSharp.LanguageService { [Guid(Guids.CSharpCodePageEditorFactoryIdString)] - internal class CSharpCodePageEditorFactory : AbstractCodePageEditorFactory + internal sealed class CSharpCodePageEditorFactory(AbstractEditorFactory editorFactory) : AbstractCodePageEditorFactory(editorFactory) { - public CSharpCodePageEditorFactory(AbstractEditorFactory editorFactory) - : base(editorFactory) - { - } } } diff --git a/src/VisualStudio/CSharp/Impl/LanguageService/CSharpDebuggerIntelliSenseContext.cs b/src/VisualStudio/CSharp/Impl/LanguageService/CSharpDebuggerIntelliSenseContext.cs index cc232ea5b71fc..7b1d995740dce 100644 --- a/src/VisualStudio/CSharp/Impl/LanguageService/CSharpDebuggerIntelliSenseContext.cs +++ b/src/VisualStudio/CSharp/Impl/LanguageService/CSharpDebuggerIntelliSenseContext.cs @@ -25,6 +25,8 @@ namespace Microsoft.VisualStudio.LanguageServices.CSharp.LanguageService { internal class CSharpDebuggerIntelliSenseContext : AbstractDebuggerIntelliSenseContext { + private const string StatementTerminator = ";"; + public CSharpDebuggerIntelliSenseContext( IWpfTextView view, IVsTextView vsTextView, @@ -60,13 +62,19 @@ internal CSharpDebuggerIntelliSenseContext( { } - protected override int GetAdjustedContextPoint(int contextPoint, Document document) + protected override IProjectionBuffer GetAdjustedBuffer(int contextPoint, Document document, ITrackingSpan debuggerMappedSpan) { // Determine the position in the buffer at which to end the tracking span representing // the part of the imaginary buffer before the text in the view. var tree = document.GetSyntaxTreeSynchronously(CancellationToken.None); var token = tree.FindTokenOnLeftOfPosition(contextPoint, CancellationToken.None); + // Typically, the separator between the text before adjustedStart and debuggerMappedSpan is + // a semicolon (StatementTerminator), unless a specific condition outlined later in the + // method is encountered. + var separatorBeforeDebuggerMappedSpan = StatementTerminator; + var adjustedStart = token.FullSpan.End; + // Special case to handle class designer because it asks for debugger IntelliSense using // spans between members. if (contextPoint > token.Span.End && @@ -74,40 +82,46 @@ protected override int GetAdjustedContextPoint(int contextPoint, Document docume token.Parent.IsKind(SyntaxKind.Block) && token.Parent.Parent is MemberDeclarationSyntax) { - return contextPoint; + adjustedStart = contextPoint; } - - if (token.IsKindOrHasMatchingText(SyntaxKind.CloseBraceToken) && + else if (token.IsKindOrHasMatchingText(SyntaxKind.CloseBraceToken) && token.Parent.IsKind(SyntaxKind.Block)) { - return token.SpanStart; + adjustedStart = token.SpanStart; + } + else if (token.IsKindOrHasMatchingText(SyntaxKind.SemicolonToken) && + token.Parent is StatementSyntax) + { + // If the context is at a semicolon terminated statement, then we use the start of + // that statement as the adjusted context position. This is to ensure the placement + // of debuggerMappedSpan is in the same block as token originally was. For example, + // + // for (int i = 0; i < 10; i++) + // [Console.WriteLine(i);] + // + // where [] denotes CurrentStatementSpan, should use the start of CurrentStatementSpan + // as the adjusted context, and should not place a semicolon before debuggerMappedSpan. + // Not doing either of those would place debuggerMappedSpan outside the for loop. + // We use a space as the separator in this case (instead of an empty string) to help + // the vs editor out and not have a projection seam at the location they will bring + // up completion. + separatorBeforeDebuggerMappedSpan = " "; + adjustedStart = token.Parent.SpanStart; } - return token.FullSpan.End; - } - - protected override ITrackingSpan GetPreviousStatementBufferAndSpan(int contextPoint, Document document) - { - var previousTrackingSpan = ContextBuffer.CurrentSnapshot.CreateTrackingSpan(Span.FromBounds(0, contextPoint), SpanTrackingMode.EdgeNegative); - - // terminate the previous expression/statement - var buffer = ProjectionBufferFactoryService.CreateProjectionBuffer( - projectionEditResolver: null, - sourceSpans: [previousTrackingSpan, this.StatementTerminator], - options: ProjectionBufferOptions.None, - contentType: this.ContentType); + var beforeAdjustedStart = ContextBuffer.CurrentSnapshot.CreateTrackingSpan(Span.FromBounds(0, adjustedStart), SpanTrackingMode.EdgeNegative); + var afterAdjustedStart = ContextBuffer.CurrentSnapshot.CreateTrackingSpanFromIndexToEnd(adjustedStart, SpanTrackingMode.EdgePositive); - return buffer.CurrentSnapshot.CreateTrackingSpan(0, buffer.CurrentSnapshot.Length, SpanTrackingMode.EdgeNegative); + return ProjectionBufferFactoryService.CreateProjectionBuffer( + projectionEditResolver: null, + sourceSpans: [beforeAdjustedStart, separatorBeforeDebuggerMappedSpan, debuggerMappedSpan, StatementTerminator, afterAdjustedStart], + options: ProjectionBufferOptions.None, + contentType: ContentType); } public override bool CompletionStartsOnQuestionMark { get { return false; } } - - protected override string StatementTerminator - { - get { return ";"; } - } } } diff --git a/src/VisualStudio/CSharp/Impl/LanguageService/CSharpEditorFactory.cs b/src/VisualStudio/CSharp/Impl/LanguageService/CSharpEditorFactory.cs index b224aec2a8c39..355231b21a254 100644 --- a/src/VisualStudio/CSharp/Impl/LanguageService/CSharpEditorFactory.cs +++ b/src/VisualStudio/CSharp/Impl/LanguageService/CSharpEditorFactory.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.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; @@ -18,13 +16,8 @@ namespace Microsoft.VisualStudio.LanguageServices.CSharp.LanguageService { [ExcludeFromCodeCoverage] [Guid(Guids.CSharpEditorFactoryIdString)] - internal class CSharpEditorFactory : AbstractEditorFactory + internal class CSharpEditorFactory(IComponentModel componentModel) : AbstractEditorFactory(componentModel) { - public CSharpEditorFactory(IComponentModel componentModel) - : base(componentModel) - { - } - protected override string ContentTypeName => ContentTypeNames.CSharpContentType; protected override string LanguageName => LanguageNames.CSharp; diff --git a/src/VisualStudio/CSharp/Impl/Options/CSharpVisualStudioCopilotOptionsService.cs b/src/VisualStudio/CSharp/Impl/Options/CSharpVisualStudioCopilotOptionsService.cs index d815050c1e954..a9eab90ec968f 100644 --- a/src/VisualStudio/CSharp/Impl/Options/CSharpVisualStudioCopilotOptionsService.cs +++ b/src/VisualStudio/CSharp/Impl/Options/CSharpVisualStudioCopilotOptionsService.cs @@ -10,8 +10,8 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.Internal.VisualStudio.Shell.Interop; -using Microsoft.VisualStudio.Settings; using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Utilities.UnifiedSettings; namespace Microsoft.VisualStudio.LanguageServices.CSharp.Options; @@ -39,12 +39,12 @@ internal sealed class CSharpVisualStudioCopilotOptionsService : ICopilotOptionsS /// private const string GitHubAccountStatusIsCopilotEntitled = "3DE3FA6E-91B2-46C1-9E9E-DD04975BB890"; - private const string CopilotOptionNamePrefix = "Microsoft.VisualStudio.Conversations"; - // 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 readonly CopilotOption _copilotCodeAnalysisOption = new("copilot.featureFlags.editor.enableCSharpCodeAnalysis", false); + private readonly CopilotOption _copilotRefineOption = new("copilot.featureFlags.editor.enableCSharpRefineQuickActionSuggestion", false); + private readonly CopilotOption _copilotOnTheFlyDocsOption = new("copilot.general.editor.enableOnTheFlyDocs", true); + private readonly CopilotOption _copilotGenerateDocumentationCommentOption = new("copilot.general.editor.enableGenerateDocumentationComment", true); + private readonly CopilotOption _copilotGenerateMethodImplementationOption = new("copilot.featureFlags.editor.enableCSharpGenerateMethodImplementation", false); private static readonly UIContext s_copilotHasLoadedUIContext = UIContext.FromUIContextGuid(new Guid(CopilotHasLoadedGuid)); private static readonly UIContext s_gitHubAccountStatusDeterminedContext = UIContext.FromUIContextGuid(new Guid(GitHubAccountStatusDetermined)); @@ -52,6 +52,7 @@ internal sealed class CSharpVisualStudioCopilotOptionsService : ICopilotOptionsS private static readonly UIContext s_gitHubAccountStatusSignedInUIContext = UIContext.FromUIContextGuid(new Guid(GitHubAccountStatusSignedIn)); private readonly Task _settingsManagerTask; + private ISettingsReader? _settingsReader; /// /// Determines if Copilot is active and the user is signed in and entitled to use Copilot. @@ -65,7 +66,7 @@ private static bool IsGithubCopilotLoadedAndSignedIn [method: ImportingConstructor] [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public CSharpVisualStudioCopilotOptionsService( - IVsService settingsManagerService, + IVsService settingsManagerService, IThreadingContext threadingContext) { _settingsManagerTask = settingsManagerService.GetValueAsync(threadingContext.DisposalToken); @@ -76,11 +77,23 @@ 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. - // 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); + if (_settingsReader == null) + { + var settingsManager = await _settingsManagerTask.ConfigureAwait(false); + _settingsReader = settingsManager.GetReader(); + } + + try + { + if (_settingsReader.GetValue(option.Name) is { Outcome: SettingRetrievalOutcome.Success } setting) + return setting.Value; + + return option.DefaultValue; + } + catch + { + return option.DefaultValue; + } } public Task IsCodeAnalysisOptionEnabledAsync() @@ -92,5 +105,11 @@ public Task IsRefineOptionEnabledAsync() public Task IsOnTheFlyDocsOptionEnabledAsync() => IsCopilotOptionEnabledAsync(_copilotOnTheFlyDocsOption); + public Task IsGenerateDocumentationCommentOptionEnabledAsync() + => IsCopilotOptionEnabledAsync(_copilotGenerateDocumentationCommentOption); + + public Task IsImplementNotImplementedExceptionEnabledAsync() + => IsCopilotOptionEnabledAsync(_copilotGenerateMethodImplementationOption); + private record struct CopilotOption(string Name, bool DefaultValue); } diff --git a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/TempPECompilerService.cs b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/TempPECompilerService.cs index 02f811eb9514b..9f5e10f499e86 100644 --- a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/TempPECompilerService.cs +++ b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/TempPECompilerService.cs @@ -6,7 +6,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.IO; using System.Linq; using System.Runtime.InteropServices; @@ -15,7 +14,6 @@ using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServices.CSharp.ProjectSystemShim.Interop; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.CSharp.ProjectSystemShim { diff --git a/src/VisualStudio/CSharp/Impl/SemanticSearch/CSharpSemanticSearchContentType.cs b/src/VisualStudio/CSharp/Impl/SemanticSearch/CSharpSemanticSearchContentType.cs new file mode 100644 index 0000000000000..2a503d3dd90d5 --- /dev/null +++ b/src/VisualStudio/CSharp/Impl/SemanticSearch/CSharpSemanticSearchContentType.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.ComponentModel.Composition; +using Microsoft.CodeAnalysis.Editor; +using Microsoft.VisualStudio.Utilities; + +namespace Microsoft.VisualStudio.LanguageServices.CSharp; + +internal static class CSharpSemanticSearchContentType +{ + public const string Name = "SemanticSearch-CSharp"; + + [Export] + [Name(Name)] + [BaseDefinition(ContentTypeNames.CSharpContentType)] + public static readonly ContentTypeDefinition Definition = null!; +} diff --git a/src/VisualStudio/CSharp/Impl/SemanticSearch/SemanticSearchToolWindowImpl.cs b/src/VisualStudio/CSharp/Impl/SemanticSearch/SemanticSearchToolWindowImpl.cs index d51c7b44a8e87..784d47eb1def3 100644 --- a/src/VisualStudio/CSharp/Impl/SemanticSearch/SemanticSearchToolWindowImpl.cs +++ b/src/VisualStudio/CSharp/Impl/SemanticSearch/SemanticSearchToolWindowImpl.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Immutable; using System.Composition; +using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; using System.Windows; @@ -15,7 +16,6 @@ using System.Windows.Media; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Classification; -using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ErrorReporting; @@ -36,6 +36,7 @@ using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Operations; using Microsoft.VisualStudio.TextManager.Interop; using Microsoft.VisualStudio.Threading; using Microsoft.VisualStudio.Utilities; @@ -61,6 +62,9 @@ internal sealed class SemanticSearchToolWindowImpl( IGlobalOptionService globalOptions, VisualStudioWorkspace workspace, IStreamingFindUsagesPresenter resultsPresenter, + ITextUndoHistoryRegistry undoHistoryRegistry, + ISemanticSearchCopilotService copilotService, + Lazy copilotUIProvider, // lazy to avoid loading Microsoft.VisualStudio.LanguageServices.ExternalAccess.Copilot IVsService vsUIShellProvider) : ISemanticSearchWorkspaceHost, OptionsProvider { private const int ToolBarHeight = 26; @@ -68,7 +72,7 @@ internal sealed class SemanticSearchToolWindowImpl( private static readonly Lazy s_buttonTemplate = new(CreateButtonTemplate); - private readonly IContentType _contentType = contentTypeRegistry.GetContentType(ContentTypeNames.CSharpContentType); + private readonly IContentType _contentType = contentTypeRegistry.GetContentType(CSharpSemanticSearchContentType.Name); private readonly IAsynchronousOperationListener _asyncListener = listenerProvider.GetListener(FeatureAttribute.SemanticSearch); private readonly Lazy _semanticSearchWorkspace @@ -100,7 +104,9 @@ public async Task InitializeAsync(CancellationToken cancellati var vsUIShell = await vsUIShellProvider.GetValueAsync(cancellationToken).ConfigureAwait(false); - var textViewHost = CreateTextViewHost(vsUIShell); + var copilotUI = CreateCopilotUI(); + + var textViewHost = CreateTextViewHost(vsUIShell, copilotUI); var textViewControl = textViewHost.HostControl; _textView = textViewHost.TextView; _textBuffer = textViewHost.TextView.TextBuffer; @@ -112,7 +118,8 @@ public async Task InitializeAsync(CancellationToken cancellati var toolWindowGrid = new Grid(); toolWindowGrid.ColumnDefinitions.Add(new ColumnDefinition()); toolWindowGrid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(ToolBarHeight, GridUnitType.Pixel) }); - toolWindowGrid.RowDefinitions.Add(new RowDefinition()); + toolWindowGrid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto }); + toolWindowGrid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Star) }); var toolbarGrid = new Grid(); @@ -143,18 +150,30 @@ public async Task InitializeAsync(CancellationToken cancellati _cancelButton = cancelButton; toolWindowGrid.Children.Add(toolbarGrid); + + if (copilotUI != null) + { + toolWindowGrid.Children.Add(copilotUI.Control); + } + toolWindowGrid.Children.Add(textViewControl); toolbarGrid.Children.Add(executeButton); toolbarGrid.Children.Add(cancelButton); // placement within the tool window grid: - Grid.SetRow(textViewControl, 1); - Grid.SetColumn(textViewControl, 0); - Grid.SetRow(toolbarGrid, 0); Grid.SetColumn(toolbarGrid, 0); + if (copilotUI != null) + { + Grid.SetRow(copilotUI.Control, 1); + Grid.SetColumn(copilotUI.Control, 0); + } + + Grid.SetRow(textViewControl, 2); + Grid.SetColumn(textViewControl, 0); + // placement within the toolbar grid: Grid.SetRow(executeButton, 0); @@ -172,6 +191,106 @@ public async Task InitializeAsync(CancellationToken cancellati SemanticSearchWorkspace ISemanticSearchWorkspaceHost.Workspace => _semanticSearchWorkspace.Value; + private CopilotUI? CreateCopilotUI() + { + if (!copilotUIProvider.Value.IsAvailable || !copilotService.IsAvailable) + { + return null; + } + + if (!globalOptions.GetOption(SemanticSearchFeatureFlag.PromptEnabled)) + { + return null; + } + + var outerGrid = new Grid() + { + Background = (Brush)Application.Current.FindResource(CommonControlsColors.TextBoxBackgroundBrushKey), + }; + + ImageThemingUtilities.SetImageBackgroundColor(outerGrid, (Color)Application.Current.Resources[CommonDocumentColors.PageBackgroundColorKey]); + ThemedDialogStyleLoader.SetUseDefaultThemedDialogStyles(outerGrid, true); + + // [ prompt border | empty ] + outerGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); + outerGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); + + var promptGrid = new Grid(); + + // [ input | panel ] + promptGrid.ColumnDefinitions.Add(new ColumnDefinition { MaxWidth = 600, Width = GridLength.Auto }); + promptGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); + + var promptTextBox = copilotUIProvider.Value.GetTextBox(); + + var panel = new StackPanel() + { + Orientation = Orientation.Horizontal, + HorizontalAlignment = HorizontalAlignment.Left, + VerticalAlignment = VerticalAlignment.Bottom, + Margin = new Thickness(8, 8, 0, 8), + }; + + Grid.SetColumn(promptTextBox.Control, 0); + promptGrid.Children.Add(promptTextBox.Control); + + Grid.SetColumn(panel, 1); + promptGrid.Children.Add(panel); + + var promptGridBorder = new Border + { + Name = "PromptBorder", + BorderBrush = (Brush)Application.Current.Resources[EnvironmentColors.SystemHighlightBrushKey], + BorderThickness = new Thickness(1), + Child = promptGrid + }; + + Grid.SetColumn(promptGridBorder, 0); + outerGrid.Children.Add(promptGridBorder); + + // ComboBox for model selection + var modelPicker = new ComboBox + { + SelectedIndex = 0, + HorizontalAlignment = HorizontalAlignment.Right, + VerticalAlignment = VerticalAlignment.Top, + Margin = new Thickness(4, 0, 4, 0), + Height = 24, + IsEditable = false, + IsReadOnly = true, + BorderThickness = new Thickness(0), + MinHeight = 24, + VerticalContentAlignment = VerticalAlignment.Top, + TabIndex = 1, + Style = (Style)Application.Current.FindResource(VsResourceKeys.ComboBoxStyleKey) + }; + + modelPicker.Items.Add("gpt-4o"); + modelPicker.Items.Add("gpt-4o-mini"); + modelPicker.Items.Add("o1"); + modelPicker.Items.Add("o1-ga"); + modelPicker.Items.Add("o1-mini"); + + panel.Children.Add(modelPicker); + + var submitButton = CreateButton( + KnownMonikers.Send, + automationName: "Generate query", + acceleratorKey: "Ctrl+Enter", + toolTip: "Generate query"); + + panel.Children.Add(submitButton); + + submitButton.Click += (_, _) => SubmitCopilotQuery(promptTextBox.Text, modelPicker.Text); + + return new CopilotUI() + { + Control = outerGrid, + Input = promptTextBox, + ModelPicker = modelPicker, + }; + } + private static Button CreateButton( Imaging.Interop.ImageMoniker moniker, string automationName, @@ -250,7 +369,7 @@ private static ControlTemplate CreateButtonTemplate() """, context); } - private IWpfTextViewHost CreateTextViewHost(IVsUIShell vsUIShell) + private IWpfTextViewHost CreateTextViewHost(IVsUIShell vsUIShell, CopilotUI? copilotUI) { Contract.ThrowIfFalse(threadingContext.JoinableTaskContext.IsOnMainThread); @@ -289,7 +408,7 @@ private IWpfTextViewHost CreateTextViewHost(IVsUIShell vsUIShell) ErrorHandler.ThrowOnFailure(windowFrame.SetProperty((int)__VSFPROPID.VSFPROPID_ViewHelper, textViewAdapter)); - _ = new CommandFilter(this, textViewAdapter); + _ = new CommandFilter(this, textViewAdapter, copilotUI); return textViewHost; } @@ -315,6 +434,74 @@ private void UpdateUIState() _cancelButton.IsEnabled = isExecuting; } + private void SubmitCopilotQuery(string input, string model) + { + Contract.ThrowIfFalse(threadingContext.JoinableTaskContext.IsOnMainThread); + Contract.ThrowIfNull(_textBuffer); + Contract.ThrowIfNull(copilotService); + + // TODO: hook up cancel button for copilot queries + var cancellationSource = new CancellationTokenSource(); + + // TODO: fade out current content and show overlay spinner + + var completionToken = _asyncListener.BeginAsyncOperation(nameof(SemanticSearchToolWindow) + "." + nameof(SubmitCopilotQuery)); + _ = ExecuteAsync(cancellationSource.Token).ReportNonFatalErrorAsync().CompletesAsyncOperation(completionToken); + + async Task ExecuteAsync(CancellationToken cancellationToken) + { + await TaskScheduler.Default; + + SemanticSearchCopilotGeneratedQuery query; + + // TODO: generate list from SemanticSearch.ReferenceAssemblies: + var codeAnalysisVersion = new Version(4, 14, 0); + var sdkVersion = new Version(9, 0, 0); + + var context = new SemanticSearchCopilotContext() + { + ModelName = model, + AvailablePackages = + [ + ("Microsoft.CodeAnalysis", codeAnalysisVersion), + ("Microsoft.CodeAnalysis.CSharp", codeAnalysisVersion), + ("System.Collections.Immutable", sdkVersion), + ("System.Collections", sdkVersion), + ("System.Linq", sdkVersion), + ("System.Runtime", sdkVersion), + ] + }; + + try + { + query = await copilotService.TryGetQueryAsync(input, context, cancellationToken).ConfigureAwait(false); + } + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken, ErrorSeverity.Critical)) + { + return; + } + catch (OperationCanceledException) + { + return; + } + + // Replace text buffer content. Allow using Ctrl+Z to revert to the previous content. + + await threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(CancellationToken.None); + + Contract.ThrowIfFalse(undoHistoryRegistry.TryGetHistory(_textBuffer, out var undoHistory)); + using var undoTransaction = undoHistory.CreateTransaction(FeaturesResources.SemanticSearch); + + using (var edit = _textBuffer.CreateEdit()) + { + edit.Replace(0, _textBuffer.CurrentSnapshot.Length, query.Text); + edit.Apply(); + } + + undoTransaction.Complete(); + } + } + private void CancelQuery() { Contract.ThrowIfFalse(threadingContext.JoinableTaskContext.IsOnMainThread); @@ -485,7 +672,14 @@ public NavigableLocation GetNavigableLocation(TextSpan textSpan) public ValueTask GetOptionsAsync(Microsoft.CodeAnalysis.Host.LanguageServices languageServices, CancellationToken cancellationToken) => new(globalOptions.GetClassificationOptions(languageServices.Language)); - internal sealed class ResultsObserver(Document queryDocument, IFindUsagesContext presenterContext) : ISemanticSearchResultsObserver + private sealed class CopilotUI + { + public required FrameworkElement Control { get; init; } + public required ITextBoxControl Input { get; init; } + public required ComboBox ModelPicker { get; init; } + } + + private sealed class ResultsObserver(Document queryDocument, IFindUsagesContext presenterContext) : ISemanticSearchResultsObserver { public ValueTask OnDefinitionFoundAsync(DefinitionItem definition, CancellationToken cancellationToken) => presenterContext.OnDefinitionFoundAsync(definition, cancellationToken); @@ -509,19 +703,29 @@ public async ValueTask OnCompilationFailureAsync(ImmutableArray _copilotUI?.Input.View.HasAggregateFocus == true; + public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) - => _editorCommandTarget.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText); + { + var target = HasCopilotInputFocus ? _copilotUI.Input.CommandTarget : _editorCommandTarget; + + return target.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText); + } public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) { @@ -530,6 +734,12 @@ public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pv switch ((VSConstants.VSStd2KCmdID)nCmdID) { case VSConstants.VSStd2KCmdID.OPENLINEABOVE: + if (HasCopilotInputFocus) + { + _window.SubmitCopilotQuery(_copilotUI.Input.Text, _copilotUI.ModelPicker.Text); + return VSConstants.S_OK; + } + if (!_window.IsExecutingUIState()) { _window.RunQuery(); @@ -549,7 +759,8 @@ public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pv } } - return _editorCommandTarget.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); + var target = HasCopilotInputFocus ? _copilotUI.Input.CommandTarget : _editorCommandTarget; + return target.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); } } } diff --git a/src/VisualStudio/CSharp/Impl/Utilities/CSharpParseOptionsChangingService.cs b/src/VisualStudio/CSharp/Impl/Utilities/CSharpParseOptionsChangingService.cs index 0ad07e8b66f65..04f83a67b30e0 100644 --- a/src/VisualStudio/CSharp/Impl/Utilities/CSharpParseOptionsChangingService.cs +++ b/src/VisualStudio/CSharp/Impl/Utilities/CSharpParseOptionsChangingService.cs @@ -8,7 +8,6 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.VisualStudio.LanguageServices.Utilities; -using Roslyn.Utilities; using VSLangProj80; namespace Microsoft.VisualStudio.LanguageServices.CSharp.Utilities diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.cs.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.cs.xlf index 2afd0b93c4f35..f70d707d87f9b 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.cs.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.cs.xlf @@ -184,12 +184,12 @@ Show name s_uggestions - Show name s_uggestions + Zobrazovat návr_hy názvů Show new snippet experience - Show new snippet experience + Zobrazit nové prostředí fragmentů kódu @@ -714,7 +714,7 @@ Show name suggestions - Zobrazovat návr_hy názvů + Zobrazovat návrhy názvů diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.de.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.de.xlf index 84959e8ae705f..554b6a3fbf0f4 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.de.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.de.xlf @@ -184,12 +184,12 @@ Show name s_uggestions - Show name s_uggestions + Namensv_orschläge anzeigen Show new snippet experience - Show new snippet experience + Neue Codeausschnittoberfläche anzeigen @@ -714,7 +714,7 @@ Show name suggestions - Namensv_orschläge anzeigen + Namensvorschläge anzeigen diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.es.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.es.xlf index 57551e43d2c1d..7c2b3b3cd3464 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.es.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.es.xlf @@ -184,12 +184,12 @@ Show name s_uggestions - Show name s_uggestions + Mostrar s_ugerencias de nombres Show new snippet experience - Show new snippet experience + Mostrar nueva experiencia de fragmento de código @@ -714,7 +714,7 @@ Show name suggestions - Mostrar s_ugerencias de nombres + Mostrar sugerencias de nombres diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.fr.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.fr.xlf index f81239c73f579..9bb61f31ce94e 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.fr.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.fr.xlf @@ -184,12 +184,12 @@ Show name s_uggestions - Show name s_uggestions + Afficher les s_uggestions de nom Show new snippet experience - Show new snippet experience + Afficher une nouvelle expérience d’extrait de code @@ -714,7 +714,7 @@ Show name suggestions - Afficher les s_uggestions de nom + Afficher les suggestions de nom diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.it.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.it.xlf index 88e4ba0fb263e..952d1eb15bbf1 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.it.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.it.xlf @@ -184,12 +184,12 @@ Show name s_uggestions - Show name s_uggestions + Mostra s_uggerimenti per nomi Show new snippet experience - Show new snippet experience + Mostra nuova esperienza frammento @@ -714,7 +714,7 @@ Show name suggestions - Mostra s_uggerimenti per nomi + Mostra suggerimenti per nomi diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ja.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ja.xlf index 0f28b50458bbf..3e3685779a78e 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ja.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ja.xlf @@ -184,12 +184,12 @@ Show name s_uggestions - Show name s_uggestions + 名前の提案を表示(_U) Show new snippet experience - Show new snippet experience + 新しいスニペット エクスペリエンスを表示する @@ -714,7 +714,7 @@ Show name suggestions - 名前の提案を表示(_U) + 名前の提案を表示 diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ko.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ko.xlf index 0b768384a3d5b..a3f1dd37b7630 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ko.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ko.xlf @@ -184,12 +184,12 @@ Show name s_uggestions - Show name s_uggestions + 이름 제안 표시(_U) Show new snippet experience - Show new snippet experience + 새 코드 조각 환경 표시 @@ -714,7 +714,7 @@ Show name suggestions - 이름 제안 표시(_U) + 이름 제안 표시 diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pl.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pl.xlf index f11c52cd3f1ce..0458cc8caf079 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pl.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pl.xlf @@ -184,12 +184,12 @@ Show name s_uggestions - Show name s_uggestions + Pokaż s_ugestie dotyczące nazwy Show new snippet experience - Show new snippet experience + Pokaż nowe środowisko fragmentu kodu @@ -714,7 +714,7 @@ Show name suggestions - Pokaż s_ugestie dotyczące nazwy + Pokaż sugestie dotyczące nazw diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pt-BR.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pt-BR.xlf index d120421b416d9..c6936ad43aafd 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pt-BR.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pt-BR.xlf @@ -184,12 +184,12 @@ Show name s_uggestions - Show name s_uggestions + Mostrar s_ugestões de nomes Show new snippet experience - Show new snippet experience + Mostrar a nova experiência de trecho @@ -714,7 +714,7 @@ Show name suggestions - Mostrar s_ugestões de nomes + Mostrar sugestões de nome diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ru.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ru.xlf index 9bb3a8631fa78..178b20b4117e3 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ru.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ru.xlf @@ -184,12 +184,12 @@ Show name s_uggestions - Show name s_uggestions + Показывать в_арианты имен Show new snippet experience - Show new snippet experience + Показывать новый интерфейс фрагмента кода @@ -714,7 +714,7 @@ Show name suggestions - Показывать в_арианты имен + Показывать варианты имен diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.tr.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.tr.xlf index 77bb0bf7bb6de..d91806353f28e 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.tr.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.tr.xlf @@ -184,12 +184,12 @@ Show name s_uggestions - Show name s_uggestions + Ad ö_nerilerini göster Show new snippet experience - Show new snippet experience + Yeni kod parçacığı deneyimini göster @@ -714,7 +714,7 @@ Show name suggestions - Ad ö_nerilerini göster + Ad önerilerini göster diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hans.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hans.xlf index b54dba08ed3f1..bc7e6ded801fd 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hans.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hans.xlf @@ -184,12 +184,12 @@ Show name s_uggestions - Show name s_uggestions + 显示名称建议 Show new snippet experience - Show new snippet experience + 显示新的代码片段体验 @@ -714,7 +714,7 @@ Show name suggestions - 显示名称建议(_U) + 显示名称建议 diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hant.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hant.xlf index e4f89e27cb877..8001cbed91d86 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hant.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hant.xlf @@ -184,12 +184,12 @@ Show name s_uggestions - Show name s_uggestions + 顯示名稱建議(_U) Show new snippet experience - Show new snippet experience + 顯示新的程式碼片段體驗 @@ -714,7 +714,7 @@ Show name suggestions - 顯示名稱建議(_U) + 顯示名稱建議 diff --git a/src/VisualStudio/CSharp/Test/CallHierarchy/CSharpCallHierarchyTests.cs b/src/VisualStudio/CSharp/Test/CallHierarchy/CSharpCallHierarchyTests.cs index e1b1bf3a44b7b..7eb87cd5d2e96 100644 --- a/src/VisualStudio/CSharp/Test/CallHierarchy/CSharpCallHierarchyTests.cs +++ b/src/VisualStudio/CSharp/Test/CallHierarchy/CSharpCallHierarchyTests.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.UnitTests.CallHierarchy; @@ -11,505 +9,545 @@ using Roslyn.Test.Utilities; using Xunit; -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CallHierarchy -{ - [UseExportProvider] - [Trait(Traits.Feature, Traits.Features.CallHierarchy)] - public class CSharpCallHierarchyTests - { - [WpfFact] - public async Task InvokeOnMethod() - { - var text = @" -namespace N -{ - class C - { - void G$$oo() - { - } - } -}"; - using var testState = CallHierarchyTestState.Create(text); - var root = await testState.GetRootAsync(); - testState.VerifyRoot(root, "N.C.Goo()"); - } - - [WpfFact] - public async Task InvokeOnProperty() - { - var text = @" -namespace N -{ - class C - { - public int G$$oo { get; set;} - } -}"; - using var testState = CallHierarchyTestState.Create(text); - var root = await testState.GetRootAsync(); - testState.VerifyRoot(root, "N.C.Goo"); - } - - [WpfFact] - public async Task InvokeOnEvent() - { - var text = @" -using System; -namespace N -{ - class C - { - public event EventHandler Go$$o; - } -}"; - using var testState = CallHierarchyTestState.Create(text); - var root = await testState.GetRootAsync(); - testState.VerifyRoot(root, "N.C.Goo"); - } - - [WpfFact] - public async Task Method_FindCalls() - { - var text = @" -namespace N -{ - class C - { - void G$$oo() - { - } - } +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CallHierarchy; - class G - { - void Main() - { - var c = new C(); - c.Goo(); - } - - void Main2() - { - var c = new C(); - c.Goo(); - } - } -}"; - using var testState = CallHierarchyTestState.Create(text); - var root = await testState.GetRootAsync(); - testState.VerifyRoot(root, "N.C.Goo()", [string.Format(EditorFeaturesResources.Calls_To_0, "Goo")]); - testState.VerifyResult(root, string.Format(EditorFeaturesResources.Calls_To_0, "Goo"), ["N.G.Main()", "N.G.Main2()"]); - } - - [WpfFact] - public async Task Method_InterfaceImplementation() - { - var text = @" -namespace N +[UseExportProvider] +[Trait(Traits.Feature, Traits.Features.CallHierarchy)] +public sealed class CSharpCallHierarchyTests { - interface I + [WpfFact] + public async Task InvokeOnMethod() { - void Goo(); + var text = """ + namespace N + { + class C + { + void G$$oo() + { + } + } + } + """; + using var testState = CallHierarchyTestState.Create(text); + var root = await testState.GetRootAsync(); + testState.VerifyRoot(root, "N.C.Goo()"); } - class C : I + [WpfFact] + public async Task InvokeOnProperty() { - public void G$$oo() - { - } + var text = """ + namespace N + { + class C + { + public int G$$oo { get; set;} + } + } + """; + using var testState = CallHierarchyTestState.Create(text); + var root = await testState.GetRootAsync(); + testState.VerifyRoot(root, "N.C.Goo"); } - class G + [WpfFact] + public async Task InvokeOnEvent() { - void Main() - { - I c = new C(); - c.Goo(); - } - - void Main2() - { - var c = new C(); - c.Goo(); - } + var text = """ + using System; + namespace N + { + class C + { + public event EventHandler Go$$o; + } + } + """; + using var testState = CallHierarchyTestState.Create(text); + var root = await testState.GetRootAsync(); + testState.VerifyRoot(root, "N.C.Goo"); } -}"; - using var testState = CallHierarchyTestState.Create(text); - var root = await testState.GetRootAsync(); - testState.VerifyRoot(root, "N.C.Goo()", [string.Format(EditorFeaturesResources.Calls_To_0, "Goo"), string.Format(EditorFeaturesResources.Calls_To_Interface_Implementation_0, "N.I.Goo()")]); - testState.VerifyResult(root, string.Format(EditorFeaturesResources.Calls_To_0, "Goo"), ["N.G.Main2()"]); - testState.VerifyResult(root, string.Format(EditorFeaturesResources.Calls_To_Interface_Implementation_0, "N.I.Goo()"), ["N.G.Main()"]); - } - - [WpfFact] - public async Task Method_CallToOverride() - { - var text = @" -namespace N -{ - class C + + [WpfFact] + public async Task Method_FindCalls() { - protected virtual void G$$oo() { } + var text = """ + namespace N + { + class C + { + void G$$oo() + { + } + } + + class G + { + void Main() + { + var c = new C(); + c.Goo(); + } + + void Main2() + { + var c = new C(); + c.Goo(); + } + } + } + """; + using var testState = CallHierarchyTestState.Create(text); + var root = await testState.GetRootAsync(); + testState.VerifyRoot(root, "N.C.Goo()", [string.Format(EditorFeaturesResources.Calls_To_0, "Goo")]); + testState.VerifyResult(root, string.Format(EditorFeaturesResources.Calls_To_0, "Goo"), ["N.G.Main()", "N.G.Main2()"]); } - class D : C + [WpfFact] + public async Task Method_InterfaceImplementation() { - protected override void Goo() { } - - void Bar() - { - C c; - c.Goo() - } - - void Baz() - { - D d; - d.Goo(); - } + var text = """ + namespace N + { + interface I + { + void Goo(); + } + + class C : I + { + public void G$$oo() + { + } + } + + class G + { + void Main() + { + I c = new C(); + c.Goo(); + } + + void Main2() + { + var c = new C(); + c.Goo(); + } + } + } + """; + using var testState = CallHierarchyTestState.Create(text); + var root = await testState.GetRootAsync(); + testState.VerifyRoot(root, "N.C.Goo()", [string.Format(EditorFeaturesResources.Calls_To_0, "Goo"), string.Format(EditorFeaturesResources.Calls_To_Interface_Implementation_0, "N.I.Goo()")]); + testState.VerifyResult(root, string.Format(EditorFeaturesResources.Calls_To_0, "Goo"), ["N.G.Main2()"]); + testState.VerifyResult(root, string.Format(EditorFeaturesResources.Calls_To_Interface_Implementation_0, "N.I.Goo()"), ["N.G.Main()"]); } -}"; - using var testState = CallHierarchyTestState.Create(text); - var root = await testState.GetRootAsync(); - testState.VerifyRoot(root, "N.C.Goo()", [string.Format(EditorFeaturesResources.Calls_To_0, "Goo"), EditorFeaturesResources.Calls_To_Overrides]); - testState.VerifyResult(root, string.Format(EditorFeaturesResources.Calls_To_0, "Goo"), ["N.D.Bar()"]); - testState.VerifyResult(root, EditorFeaturesResources.Calls_To_Overrides, ["N.D.Baz()"]); - } - - [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/829705")] - public async Task Method_CallToBase() - { - var text = @" -namespace N -{ - class C + + [WpfFact] + public async Task Method_CallToOverride() { - protected virtual void Goo() { } + var text = """ + namespace N + { + class C + { + protected virtual void G$$oo() { } + } + + class D : C + { + protected override void Goo() { } + + void Bar() + { + C c; + c.Goo() + } + + void Baz() + { + D d; + d.Goo(); + } + } + } + """; + using var testState = CallHierarchyTestState.Create(text); + var root = await testState.GetRootAsync(); + testState.VerifyRoot(root, "N.C.Goo()", [string.Format(EditorFeaturesResources.Calls_To_0, "Goo"), EditorFeaturesResources.Calls_To_Overrides]); + testState.VerifyResult(root, string.Format(EditorFeaturesResources.Calls_To_0, "Goo"), ["N.D.Bar()"]); + testState.VerifyResult(root, EditorFeaturesResources.Calls_To_Overrides, ["N.D.Baz()"]); } - class D : C + [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/829705")] + public async Task Method_CallToBase() { - protected override void Goo() { } - - void Bar() - { - C c; - c.Goo() - } - - void Baz() - { - D d; - d.Go$$o(); - } + var text = """ + namespace N + { + class C + { + protected virtual void Goo() { } + } + + class D : C + { + protected override void Goo() { } + + void Bar() + { + C c; + c.Goo() + } + + void Baz() + { + D d; + d.Go$$o(); + } + } + } + """; + using var testState = CallHierarchyTestState.Create(text); + var root = await testState.GetRootAsync(); + testState.VerifyRoot(root, "N.D.Goo()", [string.Format(EditorFeaturesResources.Calls_To_0, "Goo"), string.Format(EditorFeaturesResources.Calls_To_Base_Member_0, "N.C.Goo()")]); + testState.VerifyResult(root, string.Format(EditorFeaturesResources.Calls_To_0, "Goo"), ["N.D.Baz()"]); + testState.VerifyResult(root, string.Format(EditorFeaturesResources.Calls_To_Base_Member_0, "N.C.Goo()"), ["N.D.Bar()"]); } -}"; - using var testState = CallHierarchyTestState.Create(text); - var root = await testState.GetRootAsync(); - testState.VerifyRoot(root, "N.D.Goo()", [string.Format(EditorFeaturesResources.Calls_To_0, "Goo"), string.Format(EditorFeaturesResources.Calls_To_Base_Member_0, "N.C.Goo()")]); - testState.VerifyResult(root, string.Format(EditorFeaturesResources.Calls_To_0, "Goo"), ["N.D.Baz()"]); - testState.VerifyResult(root, string.Format(EditorFeaturesResources.Calls_To_Base_Member_0, "N.C.Goo()"), ["N.D.Bar()"]); - } - - [WpfFact] - public async Task FieldInitializers() - { - var text = @" -namespace N -{ - class C - { - public int goo = Goo(); - protected int Goo$$() { return 0; } - } -}"; - using var testState = CallHierarchyTestState.Create(text); - var root = await testState.GetRootAsync(); - testState.VerifyRoot(root, "N.C.Goo()", [string.Format(EditorFeaturesResources.Calls_To_0, "Goo")]); - testState.VerifyResultName(root, string.Format(EditorFeaturesResources.Calls_To_0, "Goo"), [EditorFeaturesResources.Initializers]); - } - - [WpfFact] - public async Task FieldReferences() - { - var text = @" -namespace N -{ - class C + [WpfFact] + public async Task FieldInitializers() { - public int g$$oo; + var text = """ + namespace N + { + class C + { + public int goo = Goo(); - protected void Goo() { goo = 3; } + protected int Goo$$() { return 0; } + } + } + """; + using var testState = CallHierarchyTestState.Create(text); + var root = await testState.GetRootAsync(); + testState.VerifyRoot(root, "N.C.Goo()", [string.Format(EditorFeaturesResources.Calls_To_0, "Goo")]); + testState.VerifyResultName(root, string.Format(EditorFeaturesResources.Calls_To_0, "Goo"), [EditorFeaturesResources.Initializers]); } -}"; - using var testState = CallHierarchyTestState.Create(text); - var root = await testState.GetRootAsync(); - testState.VerifyRoot(root, "N.C.goo", [string.Format(EditorFeaturesResources.References_To_Field_0, "goo")]); - testState.VerifyResult(root, string.Format(EditorFeaturesResources.References_To_Field_0, "goo"), ["N.C.Goo()"]); - } - - [WpfFact] - public async Task PropertyGet() - { - var text = @" -namespace N -{ - class C + + [WpfFact] + public async Task FieldReferences() { - public int val - { - g$$et + var text = """ + namespace N { - return 0; - } - } + class C + { + public int g$$oo; - public int goo() - { - var x = this.val; - } - } -}"; - using var testState = CallHierarchyTestState.Create(text); - var root = await testState.GetRootAsync(); - testState.VerifyRoot(root, "N.C.val.get", [string.Format(EditorFeaturesResources.Calls_To_0, "get_val")]); - testState.VerifyResult(root, string.Format(EditorFeaturesResources.Calls_To_0, "get_val"), ["N.C.goo()"]); - } - - [WpfFact] - public async Task Generic() - { - var text = @" -namespace N -{ - class C - { - public int gen$$eric(this string generic, ref T stuff) - { - return 0; - } - - public int goo() - { - int i; - generic("", ref i); - } - } -}"; - using var testState = CallHierarchyTestState.Create(text); - var root = await testState.GetRootAsync(); - testState.VerifyRoot(root, "N.C.generic(this string, ref T)", [string.Format(EditorFeaturesResources.Calls_To_0, "generic")]); - testState.VerifyResult(root, string.Format(EditorFeaturesResources.Calls_To_0, "generic"), ["N.C.goo()"]); - } - - [WpfFact] - public async Task ExtensionMethods() - { - var text = @" -namespace ConsoleApplication10 -{ - class Program - { - static void Main(string[] args) - { - var x = ""string""; - x.BarStr$$ing(); - } - } - - public static class Extensions - { - public static string BarString(this string s) - { - return s; - } + protected void Goo() { goo = 3; } + } + } + """; + using var testState = CallHierarchyTestState.Create(text); + var root = await testState.GetRootAsync(); + testState.VerifyRoot(root, "N.C.goo", [string.Format(EditorFeaturesResources.References_To_Field_0, "goo")]); + testState.VerifyResult(root, string.Format(EditorFeaturesResources.References_To_Field_0, "goo"), ["N.C.Goo()"]); } -}"; - using var testState = CallHierarchyTestState.Create(text); - var root = await testState.GetRootAsync(); - testState.VerifyRoot(root, "ConsoleApplication10.Extensions.BarString(this string)", [string.Format(EditorFeaturesResources.Calls_To_0, "BarString")]); - testState.VerifyResult(root, string.Format(EditorFeaturesResources.Calls_To_0, "BarString"), ["ConsoleApplication10.Program.Main(string[])"]); - } - - [WpfFact] - public async Task GenericExtensionMethods() - { - var text = @" -using System.Collections.Generic; -using System.Linq; -namespace N -{ - class Program + + [WpfFact] + public async Task PropertyGet() { - static void Main(string[] args) - { - List x = new List(); - var z = x.Si$$ngle(); - } + var text = """ + namespace N + { + class C + { + public int val + { + g$$et + { + return 0; + } + } + + public int goo() + { + var x = this.val; + } + } + } + """; + using var testState = CallHierarchyTestState.Create(text); + var root = await testState.GetRootAsync(); + testState.VerifyRoot(root, "N.C.val.get", [string.Format(EditorFeaturesResources.Calls_To_0, "get_val")]); + testState.VerifyResult(root, string.Format(EditorFeaturesResources.Calls_To_0, "get_val"), ["N.C.goo()"]); } -}"; - using var testState = CallHierarchyTestState.Create(text); - var root = await testState.GetRootAsync(); - testState.VerifyRoot(root, "System.Linq.Enumerable.Single(this System.Collections.Generic.IEnumerable)", [string.Format(EditorFeaturesResources.Calls_To_0, "Single")]); - testState.VerifyResult(root, string.Format(EditorFeaturesResources.Calls_To_0, "Single"), ["N.Program.Main(string[])"]); - } - - [WpfFact] - public async Task InterfaceImplementors() - { - var text = @" -namespace N -{ - interface I + + [WpfFact] + public async Task Generic() { - void Go$$o(); + var text = """ + namespace N + { + class C + { + public int gen$$eric(this string generic, ref T stuff) + { + return 0; + } + + public int goo() + { + int i; + generic(", ref i); + } + } + } + """; + using var testState = CallHierarchyTestState.Create(text); + var root = await testState.GetRootAsync(); + testState.VerifyRoot(root, "N.C.generic(this string, ref T)", [string.Format(EditorFeaturesResources.Calls_To_0, "generic")]); + testState.VerifyResult(root, string.Format(EditorFeaturesResources.Calls_To_0, "generic"), ["N.C.goo()"]); } - class C : I + [WpfFact] + public async Task ExtensionMethods() { - public void Goo() - { - } + var text = """ + namespace ConsoleApplication10 + { + class Program + { + static void Main(string[] args) + { + var x = "string"; + x.BarStr$$ing(); + } + } + + public static class Extensions + { + public static string BarString(this string s) + { + return s; + } + } + } + """; + using var testState = CallHierarchyTestState.Create(text); + var root = await testState.GetRootAsync(); + testState.VerifyRoot(root, "ConsoleApplication10.Extensions.BarString(this string)", [string.Format(EditorFeaturesResources.Calls_To_0, "BarString")]); + testState.VerifyResult(root, string.Format(EditorFeaturesResources.Calls_To_0, "BarString"), ["ConsoleApplication10.Program.Main(string[])"]); } - class G + [WpfFact] + public async Task GenericExtensionMethods() { - void Main() - { - I c = new C(); - c.Goo(); - } - - void Main2() - { - var c = new C(); - c.Goo(); - } + var text = """ + using System.Collections.Generic; + using System.Linq; + namespace N + { + class Program + { + static void Main(string[] args) + { + List x = new List(); + var z = x.Si$$ngle(); + } + } + } + """; + using var testState = CallHierarchyTestState.Create(text); + var root = await testState.GetRootAsync(); + testState.VerifyRoot(root, "System.Linq.Enumerable.Single(this System.Collections.Generic.IEnumerable)", [string.Format(EditorFeaturesResources.Calls_To_0, "Single")]); + testState.VerifyResult(root, string.Format(EditorFeaturesResources.Calls_To_0, "Single"), ["N.Program.Main(string[])"]); } -}"; - using var testState = CallHierarchyTestState.Create(text); - var root = await testState.GetRootAsync(); - testState.VerifyRoot(root, "N.I.Goo()", [string.Format(EditorFeaturesResources.Calls_To_0, "Goo"), string.Format(EditorFeaturesResources.Implements_0, "Goo")]); - testState.VerifyResult(root, string.Format(EditorFeaturesResources.Calls_To_0, "Goo"), ["N.G.Main()"]); - testState.VerifyResult(root, string.Format(EditorFeaturesResources.Implements_0, "Goo"), ["N.C.Goo()"]); - } - - [WpfFact] - public async Task NoFindOverridesOnSealedMethod() - { - var text = @" -namespace N -{ - class C + + [WpfFact] + public async Task InterfaceImplementors() { - void G$$oo() - { - } + var text = """ + namespace N + { + interface I + { + void Go$$o(); + } + + class C : I + { + public void Goo() + { + } + } + + class G + { + void Main() + { + I c = new C(); + c.Goo(); + } + + void Main2() + { + var c = new C(); + c.Goo(); + } + } + } + """; + using var testState = CallHierarchyTestState.Create(text); + var root = await testState.GetRootAsync(); + testState.VerifyRoot(root, "N.I.Goo()", [string.Format(EditorFeaturesResources.Calls_To_0, "Goo"), string.Format(EditorFeaturesResources.Implements_0, "Goo")]); + testState.VerifyResult(root, string.Format(EditorFeaturesResources.Calls_To_0, "Goo"), ["N.G.Main()"]); + testState.VerifyResult(root, string.Format(EditorFeaturesResources.Implements_0, "Goo"), ["N.C.Goo()"]); } -}"; - using var testState = CallHierarchyTestState.Create(text); - var root = await testState.GetRootAsync(); - Assert.DoesNotContain("Overrides", root.SupportedSearchCategories.Select(s => s.DisplayName)); - } - - [WpfFact] - public async Task FindOverrides() - { - var text = @" -namespace N -{ - class C + + [WpfFact] + public async Task NoFindOverridesOnSealedMethod() { - public virtual void G$$oo() - { - } + var text = """ + namespace N + { + class C + { + void G$$oo() + { + } + } + } + """; + using var testState = CallHierarchyTestState.Create(text); + var root = await testState.GetRootAsync(); + Assert.DoesNotContain("Overrides", root.SupportedSearchCategories.Select(s => s.DisplayName)); } - class G : C + [WpfFact] + public async Task FindOverrides() { - public override void Goo() - { - } + var text = """ + namespace N + { + class C + { + public virtual void G$$oo() + { + } + } + + class G : C + { + public override void Goo() + { + } + } + } + """; + using var testState = CallHierarchyTestState.Create(text); + var root = await testState.GetRootAsync(); + testState.VerifyRoot(root, "N.C.Goo()", [string.Format(EditorFeaturesResources.Calls_To_0, "Goo"), EditorFeaturesResources.Overrides_]); + testState.VerifyResult(root, EditorFeaturesResources.Overrides_, ["N.G.Goo()"]); } -}"; - using var testState = CallHierarchyTestState.Create(text); - var root = await testState.GetRootAsync(); - testState.VerifyRoot(root, "N.C.Goo()", [string.Format(EditorFeaturesResources.Calls_To_0, "Goo"), EditorFeaturesResources.Overrides_]); - testState.VerifyResult(root, EditorFeaturesResources.Overrides_, ["N.G.Goo()"]); - } - - [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/844613")] - public async Task AbstractMethodInclusionToOverrides() - { - var text = @" -using System; - -abstract class Base -{ - public abstract void $$M(); -} - -class Derived : Base -{ - public override void M() + + [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/844613")] + public async Task AbstractMethodInclusionToOverrides() { - throw new NotImplementedException(); + var text = """ + using System; + + abstract class Base + { + public abstract void $$M(); + } + + class Derived : Base + { + public override void M() + { + throw new NotImplementedException(); + } + } + """; + using var testState = CallHierarchyTestState.Create(text); + var root = await testState.GetRootAsync(); + testState.VerifyRoot(root, "Base.M()", [string.Format(EditorFeaturesResources.Calls_To_0, "M"), EditorFeaturesResources.Overrides_, EditorFeaturesResources.Calls_To_Overrides]); + testState.VerifyResult(root, EditorFeaturesResources.Overrides_, ["Derived.M()"]); } -}"; - using var testState = CallHierarchyTestState.Create(text); - var root = await testState.GetRootAsync(); - testState.VerifyRoot(root, "Base.M()", [string.Format(EditorFeaturesResources.Calls_To_0, "M"), EditorFeaturesResources.Overrides_, EditorFeaturesResources.Calls_To_Overrides]); - testState.VerifyResult(root, EditorFeaturesResources.Overrides_, ["Derived.M()"]); - } - - [WpfFact] - public async Task SearchAfterEditWorks() - { - var text = @" -namespace N -{ - class C + + [WpfFact] + public async Task SearchAfterEditWorks() { - void G$$oo() - { - } - - void M() - { - Goo(); - } - } -}"; - using var testState = CallHierarchyTestState.Create(text); - var root = await testState.GetRootAsync(); + var text = """ + namespace N + { + class C + { + void G$$oo() + { + } + + void M() + { + Goo(); + } + } + } + """; + using var testState = CallHierarchyTestState.Create(text); + var root = await testState.GetRootAsync(); - testState.Workspace.Documents.Single().GetTextBuffer().Insert(0, "/* hello */"); + testState.Workspace.Documents.Single().GetTextBuffer().Insert(0, "/* hello */"); - testState.VerifyRoot(root, "N.C.Goo()", [string.Format(EditorFeaturesResources.Calls_To_0, "Goo"),]); - testState.VerifyResult(root, string.Format(EditorFeaturesResources.Calls_To_0, "Goo"), expectedCallers: ["N.C.M()"]); - } + testState.VerifyRoot(root, "N.C.Goo()", [string.Format(EditorFeaturesResources.Calls_To_0, "Goo"),]); + testState.VerifyResult(root, string.Format(EditorFeaturesResources.Calls_To_0, "Goo"), expectedCallers: ["N.C.M()"]); + } - [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/57856")] - public async Task PropertySet() - { - var code = @" -namespace N -{ - class C + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/57856")] + public async Task PropertySet() { - public int Property { get; s$$et; } - void M() - { - Property = 2; - } + var code = """ + namespace N + { + class C + { + public int Property { get; s$$et; } + void M() + { + Property = 2; + } + } + } + """; + using var testState = CallHierarchyTestState.Create(code); + var root = await testState.GetRootAsync(); + testState.VerifyRoot(root, "N.C.Property.set", [string.Format(EditorFeaturesResources.Calls_To_0, "set_Property")]); + testState.VerifyResult(root, string.Format(EditorFeaturesResources.Calls_To_0, "set_Property"), ["N.C.M()"]); } -}"; - using var testState = CallHierarchyTestState.Create(code); - var root = await testState.GetRootAsync(); - testState.VerifyRoot(root, "N.C.Property.set", [string.Format(EditorFeaturesResources.Calls_To_0, "set_Property")]); - testState.VerifyResult(root, string.Format(EditorFeaturesResources.Calls_To_0, "set_Property"), ["N.C.M()"]); - } + + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/77327")] + public async Task PrimaryConstructor() + { + var code = """ + public class $$Class1(string test) + { + } + + class D + { + public void M() + { + var c = new Class1("test"); + } + } + """; + using var testState = CallHierarchyTestState.Create(code); + var root = await testState.GetRootAsync(); + testState.VerifyRoot(root, "Class1.Class1(string)", [string.Format(EditorFeaturesResources.Calls_To_0, ".ctor")]); + testState.VerifyResult(root, string.Format(EditorFeaturesResources.Calls_To_0, ".ctor"), ["D.M()"]); } } diff --git a/src/VisualStudio/CSharp/Test/DocumentOutline/DocumentOutlineTestsBase.cs b/src/VisualStudio/CSharp/Test/DocumentOutline/DocumentOutlineTestsBase.cs index 5b549fcc253d8..9df6aa70e214d 100644 --- a/src/VisualStudio/CSharp/Test/DocumentOutline/DocumentOutlineTestsBase.cs +++ b/src/VisualStudio/CSharp/Test/DocumentOutline/DocumentOutlineTestsBase.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.Runtime.Serialization; using System.Threading; @@ -9,17 +10,17 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.CodeAnalysis.Editor.Test; using Microsoft.CodeAnalysis.Editor.UnitTests; using Microsoft.CodeAnalysis.LanguageServer.Handler; -using Microsoft.CodeAnalysis.LanguageServer.UnitTests; using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; +using Microsoft.CommonLanguageServerProtocol.Framework; using Microsoft.VisualStudio.LanguageServer.Client; using Microsoft.VisualStudio.LanguageServices.DocumentOutline; using Microsoft.VisualStudio.Text; +using Roslyn.LanguageServer.Protocol; +using Roslyn.Test.Utilities; using StreamJsonRpc; using Xunit.Abstractions; using static Roslyn.Test.Utilities.AbstractLanguageServerProtocolTests; @@ -94,7 +95,7 @@ protected async Task CreateMocksAsync(string code) } } - private async Task CreateTestLspServerAsync(EditorTestWorkspace workspace) + private async Task CreateTestLspServerAsync(EditorTestWorkspace workspace) { var solution = workspace.CurrentSolution; @@ -118,10 +119,25 @@ private async Task CreateTestLspServerAsync(EditorTestWorkspace w solution = solution.WithAnalyzerReferences([new TestAnalyzerReferenceByLanguage(DiagnosticExtensions.GetCompilerDiagnosticAnalyzersMap())]); await workspace.ChangeSolutionAsync(solution); - var server = await TestLspServer.CreateAsync(workspace, new InitializationOptions(), _logger); + var server = await EditorTestLspServer.CreateAsync(workspace, new InitializationOptions(), _logger); return server; } + internal class EditorTestLspServer : AbstractTestLspServer + { + private EditorTestLspServer(EditorTestWorkspace testWorkspace, Dictionary> locations, InitializationOptions options, AbstractLspLogger logger) : base(testWorkspace, locations, options, logger) + { + } + + public static async Task CreateAsync(EditorTestWorkspace testWorkspace, InitializationOptions initializationOptions, AbstractLspLogger logger) + { + var locations = await GetAnnotatedLocationsAsync(testWorkspace, testWorkspace.CurrentSolution); + var server = new EditorTestLspServer(testWorkspace, locations, initializationOptions, logger); + await server.InitializeAsync(); + return server; + } + } + [DataContract] private class NewtonsoftInitializeParams { diff --git a/src/VisualStudio/CSharp/Test/Microsoft.VisualStudio.LanguageServices.CSharp.UnitTests.csproj b/src/VisualStudio/CSharp/Test/Microsoft.VisualStudio.LanguageServices.CSharp.UnitTests.csproj index cab7be9c43233..3b17836fefa1e 100644 --- a/src/VisualStudio/CSharp/Test/Microsoft.VisualStudio.LanguageServices.CSharp.UnitTests.csproj +++ b/src/VisualStudio/CSharp/Test/Microsoft.VisualStudio.LanguageServices.CSharp.UnitTests.csproj @@ -16,6 +16,7 @@ + diff --git a/src/VisualStudio/CSharp/Test/ProjectSystemShim/TestEvaluationData.cs b/src/VisualStudio/CSharp/Test/ProjectSystemShim/TestEvaluationData.cs index 3eea12d66da49..055f3bfdb87e4 100644 --- a/src/VisualStudio/CSharp/Test/ProjectSystemShim/TestEvaluationData.cs +++ b/src/VisualStudio/CSharp/Test/ProjectSystemShim/TestEvaluationData.cs @@ -3,8 +3,8 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; +using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.LanguageServices.ProjectSystem; -using Roslyn.Utilities; namespace Roslyn.VisualStudio.CSharp.UnitTests.ProjectSystemShim; diff --git a/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyCommandHandler.cs b/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyCommandHandler.cs index 826fbb6f7b468..8ae227be08710 100644 --- a/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyCommandHandler.cs +++ b/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyCommandHandler.cs @@ -2,23 +2,20 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Generic; -using System.Collections.Immutable; using System.ComponentModel.Composition; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Host; -using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.CodeAnalysis.FindSymbols; +using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.Shared.TestHooks; -using Microsoft.CodeAnalysis.SymbolMapping; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.LanguageServices; +using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; using Microsoft.VisualStudio.Utilities; using Roslyn.Utilities; @@ -30,81 +27,66 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.CallHierarchy; [ContentType(ContentTypeNames.VisualBasicContentType)] [Name("CallHierarchy")] [Order(After = PredefinedCommandHandlerNames.DocumentationComments)] -internal class CallHierarchyCommandHandler : ICommandHandler +[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 CallHierarchyCommandHandler( + IThreadingContext threadingContext, + IUIThreadOperationExecutor threadOperationExecutor, + IAsynchronousOperationListenerProvider asynchronousOperationListenerProvider, + [ImportMany] IEnumerable presenters, + CallHierarchyProvider provider) : ICommandHandler { - private readonly IThreadingContext _threadingContext; - private readonly IUIThreadOperationExecutor _threadOperationExecutor; - private readonly IAsynchronousOperationListener _listener; - private readonly ICallHierarchyPresenter _presenter; - private readonly CallHierarchyProvider _provider; + private readonly IThreadingContext _threadingContext = threadingContext; + private readonly IUIThreadOperationExecutor _threadOperationExecutor = threadOperationExecutor; + private readonly IAsynchronousOperationListener _listener = asynchronousOperationListenerProvider.GetListener(FeatureAttribute.CallHierarchy); + private readonly ICallHierarchyPresenter _presenter = presenters.FirstOrDefault(); + private readonly CallHierarchyProvider _provider = provider; - public string DisplayName => EditorFeaturesResources.Call_Hierarchy; + public string DisplayName + => EditorFeaturesResources.Call_Hierarchy; - [ImportingConstructor] - [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] - public CallHierarchyCommandHandler( - IThreadingContext threadingContext, - IUIThreadOperationExecutor threadOperationExecutor, - IAsynchronousOperationListenerProvider asynchronousOperationListenerProvider, - [ImportMany] IEnumerable presenters, - CallHierarchyProvider provider) - { - _threadingContext = threadingContext; - _threadOperationExecutor = threadOperationExecutor; - _listener = asynchronousOperationListenerProvider.GetListener(FeatureAttribute.CallHierarchy); - _presenter = presenters.FirstOrDefault(); - _provider = provider; - } + public CommandState GetCommandState(ViewCallHierarchyCommandArgs args) + => CommandState.Available; public bool ExecuteCommand(ViewCallHierarchyCommandArgs args, CommandExecutionContext context) { + var document = args.SubjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); + if (document == null) + return false; + + var point = args.TextView.Caret.Position.Point.GetPoint(args.SubjectBuffer, PositionAffinity.Predecessor); + if (point is null) + return false; + // We're showing our own UI, ensure the editor doesn't show anything itself. context.OperationContext.TakeOwnership(); var token = _listener.BeginAsyncOperation(nameof(ExecuteCommand)); - ExecuteCommandAsync(args, context) + ExecuteCommandAsync(document, point.Value.Position) .ReportNonFatalErrorAsync() .CompletesAsyncOperation(token); return true; } - private async Task ExecuteCommandAsync(ViewCallHierarchyCommandArgs args, CommandExecutionContext commandExecutionContext) + private async Task ExecuteCommandAsync(Document document, int caretPosition) { - Document document; - using (var context = _threadOperationExecutor.BeginExecute( EditorFeaturesResources.Call_Hierarchy, ServicesVSResources.Navigating, allowCancellation: true, showProgress: false)) { - document = await args.SubjectBuffer.CurrentSnapshot.GetFullyLoadedOpenDocumentInCurrentContextWithChangesAsync( - commandExecutionContext.OperationContext).ConfigureAwait(true); - if (document == null) - { - return; - } - - var caretPosition = args.TextView.Caret.Position.BufferPosition.Position; var cancellationToken = context.UserCancellationToken; - var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var symbolUnderCaret = await SymbolFinder.FindSymbolAtPositionAsync( - semanticModel, caretPosition, document.Project.Solution.Services, cancellationToken).ConfigureAwait(false); + var symbolAndProject = await FindUsagesHelpers.GetRelevantSymbolAndProjectAtPositionAsync( + document, caretPosition, preferPrimaryConstructor: true, cancellationToken).ConfigureAwait(false); - if (symbolUnderCaret != null) + if (symbolAndProject is (var symbol, var project)) { - // Map symbols so that Call Hierarchy works from metadata-as-source - var mappingService = document.Project.Solution.Services.GetService(); - var mapping = await mappingService.MapSymbolAsync(document, symbolUnderCaret, cancellationToken).ConfigureAwait(false); + var node = await _provider.CreateItemAsync(symbol, project, callsites: [], cancellationToken).ConfigureAwait(false); - if (mapping.Symbol != null) + if (node != null) { - var node = await _provider.CreateItemAsync(mapping.Symbol, mapping.Project, [], cancellationToken).ConfigureAwait(false); - - if (node != null) - { - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - _presenter.PresentRoot((CallHierarchyItem)node); - return; - } + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + _presenter.PresentRoot(node); + return; } } @@ -112,10 +94,7 @@ private async Task ExecuteCommandAsync(ViewCallHierarchyCommandArgs args, Comman await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); } - var notificationService = document.Project.Solution.Services.GetService(); + var notificationService = document.Project.Solution.Services.GetRequiredService(); notificationService.SendNotification(EditorFeaturesResources.Cursor_must_be_on_a_member_name, severity: NotificationSeverity.Information); } - - public CommandState GetCommandState(ViewCallHierarchyCommandArgs args) - => CommandState.Available; } diff --git a/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyItem.cs b/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyItem.cs index 24be31df5a6a3..69e54e1e0a570 100644 --- a/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyItem.cs +++ b/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyItem.cs @@ -19,12 +19,12 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.CallHierarchy; -internal class CallHierarchyItem : ICallHierarchyMemberItem +internal sealed class CallHierarchyItem : ICallHierarchyMemberItem { private readonly Workspace _workspace; private readonly INavigableLocation _navigableLocation; - private readonly IEnumerable _callsites; - private readonly IEnumerable _finders; + private readonly ImmutableArray _callsites; + private readonly ImmutableArray _finders; private readonly Func _glyphCreator; private readonly CallHierarchyProvider _provider; @@ -32,7 +32,7 @@ public CallHierarchyItem( CallHierarchyProvider provider, ISymbol symbol, INavigableLocation navigableLocation, - IEnumerable finders, + ImmutableArray finders, Func glyphCreator, ImmutableArray callsites, Project project) diff --git a/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyProvider.cs b/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyProvider.cs index 26041774a48bb..13177bb5ee2ba 100644 --- a/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyProvider.cs +++ b/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyProvider.cs @@ -19,7 +19,6 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; -using Microsoft.VisualStudio.Language.CallHierarchy; using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; using Microsoft.VisualStudio.Utilities; @@ -52,7 +51,7 @@ public CallHierarchyProvider( _streamingPresenter = streamingPresenter; } - public async Task CreateItemAsync( + public async Task CreateItemAsync( ISymbol symbol, Project project, ImmutableArray callsites, CancellationToken cancellationToken) { if (symbol.Kind is SymbolKind.Method or @@ -65,7 +64,7 @@ SymbolKind.Event or var finders = await CreateFindersAsync(symbol, project, cancellationToken).ConfigureAwait(false); var location = await GoToDefinitionHelpers.GetDefinitionLocationAsync( symbol, project.Solution, this.ThreadingContext, _streamingPresenter.Value, cancellationToken).ConfigureAwait(false); - ICallHierarchyMemberItem item = new CallHierarchyItem( + return new CallHierarchyItem( this, symbol, location, @@ -73,8 +72,6 @@ SymbolKind.Event or () => symbol.GetGlyph().GetImageSource(GlyphService), callsites, project); - - return item; } return null; @@ -100,11 +97,11 @@ public FieldInitializerItem CreateInitializerItem(IEnumerable> CreateFindersAsync(ISymbol symbol, Project project, CancellationToken cancellationToken) + public async Task> CreateFindersAsync(ISymbol symbol, Project project, CancellationToken cancellationToken) { if (symbol.Kind is SymbolKind.Property or - SymbolKind.Event or - SymbolKind.Method) + SymbolKind.Event or + SymbolKind.Method) { var finders = new List { @@ -138,14 +135,12 @@ SymbolKind.Event or finders.Add(new ImplementerFinder(symbol, project.Id, AsyncListener, this)); } - return finders; + return finders.ToImmutableArray(); } if (symbol.Kind == SymbolKind.Field) - { return [new FieldReferenceFinder(symbol, project.Id, AsyncListener, this)]; - } - return null; + return []; } } diff --git a/src/VisualStudio/Core/Def/CallHierarchy/FieldInitializerItem.cs b/src/VisualStudio/Core/Def/CallHierarchy/FieldInitializerItem.cs index d05deb2230de3..4c7be3ec97382 100644 --- a/src/VisualStudio/Core/Def/CallHierarchy/FieldInitializerItem.cs +++ b/src/VisualStudio/Core/Def/CallHierarchy/FieldInitializerItem.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.Windows.Media; using Microsoft.VisualStudio.Language.CallHierarchy; diff --git a/src/VisualStudio/Core/Def/CallHierarchy/Finders/BaseMemberFinder.cs b/src/VisualStudio/Core/Def/CallHierarchy/Finders/BaseMemberFinder.cs index b3390745f91ef..1e5116b26bb87 100644 --- a/src/VisualStudio/Core/Def/CallHierarchy/Finders/BaseMemberFinder.cs +++ b/src/VisualStudio/Core/Def/CallHierarchy/Finders/BaseMemberFinder.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.Linq; diff --git a/src/VisualStudio/Core/Def/CallHierarchy/Finders/CallToOverrideFinder.cs b/src/VisualStudio/Core/Def/CallHierarchy/Finders/CallToOverrideFinder.cs index 1f0b59391d4a4..87944cc297c2b 100644 --- a/src/VisualStudio/Core/Def/CallHierarchy/Finders/CallToOverrideFinder.cs +++ b/src/VisualStudio/Core/Def/CallHierarchy/Finders/CallToOverrideFinder.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; diff --git a/src/VisualStudio/Core/Def/CallHierarchy/Finders/FieldReferenceFinder.cs b/src/VisualStudio/Core/Def/CallHierarchy/Finders/FieldReferenceFinder.cs index 41dd82913cfc0..5cf04ac1a6649 100644 --- a/src/VisualStudio/Core/Def/CallHierarchy/Finders/FieldReferenceFinder.cs +++ b/src/VisualStudio/Core/Def/CallHierarchy/Finders/FieldReferenceFinder.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.Linq; diff --git a/src/VisualStudio/Core/Def/CallHierarchy/Finders/ImplementerFinder.cs b/src/VisualStudio/Core/Def/CallHierarchy/Finders/ImplementerFinder.cs index 7713dbaa000d3..2655580251f4e 100644 --- a/src/VisualStudio/Core/Def/CallHierarchy/Finders/ImplementerFinder.cs +++ b/src/VisualStudio/Core/Def/CallHierarchy/Finders/ImplementerFinder.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.Immutable; diff --git a/src/VisualStudio/Core/Def/CallHierarchy/Finders/InterfaceImplementationCallFinder.cs b/src/VisualStudio/Core/Def/CallHierarchy/Finders/InterfaceImplementationCallFinder.cs index e69f4ce718296..91e58184bf69e 100644 --- a/src/VisualStudio/Core/Def/CallHierarchy/Finders/InterfaceImplementationCallFinder.cs +++ b/src/VisualStudio/Core/Def/CallHierarchy/Finders/InterfaceImplementationCallFinder.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.Linq; diff --git a/src/VisualStudio/Core/Def/CallHierarchy/Finders/MethodCallFinder.cs b/src/VisualStudio/Core/Def/CallHierarchy/Finders/MethodCallFinder.cs index 258fa2bd88cf0..0815365e85099 100644 --- a/src/VisualStudio/Core/Def/CallHierarchy/Finders/MethodCallFinder.cs +++ b/src/VisualStudio/Core/Def/CallHierarchy/Finders/MethodCallFinder.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.Linq; diff --git a/src/VisualStudio/Core/Def/CallHierarchy/Finders/OverridingMemberFinder.cs b/src/VisualStudio/Core/Def/CallHierarchy/Finders/OverridingMemberFinder.cs index 5744cdbf8fc6a..d18a2ab43d692 100644 --- a/src/VisualStudio/Core/Def/CallHierarchy/Finders/OverridingMemberFinder.cs +++ b/src/VisualStudio/Core/Def/CallHierarchy/Finders/OverridingMemberFinder.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.Immutable; diff --git a/src/VisualStudio/Core/Def/CallHierarchy/ICallHierarchyPresenter.cs b/src/VisualStudio/Core/Def/CallHierarchy/ICallHierarchyPresenter.cs index 37a9af768bb48..b0843a2a19eca 100644 --- a/src/VisualStudio/Core/Def/CallHierarchy/ICallHierarchyPresenter.cs +++ b/src/VisualStudio/Core/Def/CallHierarchy/ICallHierarchyPresenter.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Editor.Implementation.CallHierarchy; namespace Microsoft.CodeAnalysis.Editor.Host; diff --git a/src/VisualStudio/Core/Def/ChangeSignature/ChangeSignatureDialogViewModel.cs b/src/VisualStudio/Core/Def/ChangeSignature/ChangeSignatureDialogViewModel.cs index 073e8e25ae3a8..9ab08d0a04201 100644 --- a/src/VisualStudio/Core/Def/ChangeSignature/ChangeSignatureDialogViewModel.cs +++ b/src/VisualStudio/Core/Def/ChangeSignature/ChangeSignatureDialogViewModel.cs @@ -15,7 +15,6 @@ using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Notification; -using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; using Microsoft.VisualStudio.Text.Classification; using Roslyn.Utilities; diff --git a/src/VisualStudio/Core/Def/CodeCleanup/CommonCodeCleanUpFixerDiagnosticIds.cs b/src/VisualStudio/Core/Def/CodeCleanup/CommonCodeCleanUpFixerDiagnosticIds.cs index 45bd1af61476a..5be87f357eafc 100644 --- a/src/VisualStudio/Core/Def/CodeCleanup/CommonCodeCleanUpFixerDiagnosticIds.cs +++ b/src/VisualStudio/Core/Def/CodeCleanup/CommonCodeCleanUpFixerDiagnosticIds.cs @@ -31,18 +31,18 @@ internal static class CommonCodeCleanUpFixerDiagnosticIds public static readonly FixIdDefinition? RemoveQualificationDiagnosticId; [Export] - [FixId(IDEDiagnosticIds.AddAccessibilityModifiersDiagnosticId)] - [Name(IDEDiagnosticIds.AddAccessibilityModifiersDiagnosticId)] + [FixId(IDEDiagnosticIds.AddOrRemoveAccessibilityModifiersDiagnosticId)] + [Name(IDEDiagnosticIds.AddOrRemoveAccessibilityModifiersDiagnosticId)] [Order(After = IDEDiagnosticIds.AddBracesDiagnosticId)] [ConfigurationKey("unused")] - [HelpLink($"https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/{IDEDiagnosticIds.AddAccessibilityModifiersDiagnosticId}")] + [HelpLink($"https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/{IDEDiagnosticIds.AddOrRemoveAccessibilityModifiersDiagnosticId}")] [LocalizedName(typeof(AnalyzersResources), nameof(AnalyzersResources.Add_accessibility_modifiers))] - public static readonly FixIdDefinition? AddAccessibilityModifiersDiagnosticId; + public static readonly FixIdDefinition? AddOrRemoveAccessibilityModifiersDiagnosticId; [Export] [FixId(IDEDiagnosticIds.OrderModifiersDiagnosticId)] [Name(IDEDiagnosticIds.OrderModifiersDiagnosticId)] - [Order(After = IDEDiagnosticIds.AddAccessibilityModifiersDiagnosticId)] + [Order(After = IDEDiagnosticIds.AddOrRemoveAccessibilityModifiersDiagnosticId)] [ConfigurationKey("unused")] [HelpLink($"https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/{IDEDiagnosticIds.OrderModifiersDiagnosticId}")] [LocalizedName(typeof(AnalyzersResources), nameof(AnalyzersResources.Order_modifiers))] diff --git a/src/VisualStudio/Core/Def/CodeLens/RemoteCodeLensReferencesService.cs b/src/VisualStudio/Core/Def/CodeLens/RemoteCodeLensReferencesService.cs index 702de2078b64f..222a13c2d8a2b 100644 --- a/src/VisualStudio/Core/Def/CodeLens/RemoteCodeLensReferencesService.cs +++ b/src/VisualStudio/Core/Def/CodeLens/RemoteCodeLensReferencesService.cs @@ -17,7 +17,6 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.CodeLens; @@ -123,7 +122,7 @@ public ValueTask GetProjectCodeLensVersionAsync(Solution solution, var client = await RemoteHostClient.TryGetClientAsync(solution.Services, cancellationToken).ConfigureAwait(false); if (client != null) { - var result = await client.TryInvokeAsync( + var result = await client.TryInvokeAsync( solution, (service, solutionInfo, cancellationToken) => service.GetFullyQualifiedNameAsync(solutionInfo, documentId, syntaxNode.Span, cancellationToken), cancellationToken).ConfigureAwait(false); diff --git a/src/VisualStudio/Core/Def/CodeModel/ICodeModelInstanceFactory.cs b/src/VisualStudio/Core/Def/CodeModel/ICodeModelInstanceFactory.cs index 224fc3c9d407b..bba5338ef6fec 100644 --- a/src/VisualStudio/Core/Def/CodeModel/ICodeModelInstanceFactory.cs +++ b/src/VisualStudio/Core/Def/CodeModel/ICodeModelInstanceFactory.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.VisualStudio.LanguageServices.Implementation.CodeModel; internal interface ICodeModelInstanceFactory diff --git a/src/VisualStudio/Core/Def/CodeModel/IProjectCodeModelFactory.cs b/src/VisualStudio/Core/Def/CodeModel/IProjectCodeModelFactory.cs index e9c45b0331bd4..aa0e0a470fb96 100644 --- a/src/VisualStudio/Core/Def/CodeModel/IProjectCodeModelFactory.cs +++ b/src/VisualStudio/Core/Def/CodeModel/IProjectCodeModelFactory.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis; namespace Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel; diff --git a/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.ColorSchemeReader.cs b/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.ColorSchemeReader.cs index 45b025871bcf4..77fd8274475aa 100644 --- a/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.ColorSchemeReader.cs +++ b/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.ColorSchemeReader.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Immutable; using System.Globalization; using System.IO; using System.Linq; diff --git a/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.cs b/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.cs index b9ac22121c1fd..04e21d0fe143c 100644 --- a/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.cs +++ b/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.cs @@ -13,12 +13,12 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Threading; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Settings; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Threading; -using Roslyn.Utilities; using Task = System.Threading.Tasks.Task; namespace Microsoft.CodeAnalysis.ColorSchemes; diff --git a/src/VisualStudio/Core/Def/ColorSchemes/VisualStudio2017.xml b/src/VisualStudio/Core/Def/ColorSchemes/VisualStudio2017.xml index ba5c889c9428f..2cf5c5cfa8692 100644 --- a/src/VisualStudio/Core/Def/ColorSchemes/VisualStudio2017.xml +++ b/src/VisualStudio/Core/Def/ColorSchemes/VisualStudio2017.xml @@ -790,7 +790,8 @@ - + + diff --git a/src/VisualStudio/Core/Def/ColorSchemes/VisualStudio2019.xml b/src/VisualStudio/Core/Def/ColorSchemes/VisualStudio2019.xml index 99a3dbfdf8685..7dc8bafcedef3 100644 --- a/src/VisualStudio/Core/Def/ColorSchemes/VisualStudio2019.xml +++ b/src/VisualStudio/Core/Def/ColorSchemes/VisualStudio2019.xml @@ -817,7 +817,8 @@ - + + diff --git a/src/VisualStudio/Core/Def/CommonControls/MemberSelection.xaml b/src/VisualStudio/Core/Def/CommonControls/MemberSelection.xaml index 50efb6bda4e56..0e1684017beaa 100644 --- a/src/VisualStudio/Core/Def/CommonControls/MemberSelection.xaml +++ b/src/VisualStudio/Core/Def/CommonControls/MemberSelection.xaml @@ -5,10 +5,15 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:utilities="clr-namespace:Microsoft.VisualStudio.LanguageServices.Implementation.Utilities" xmlns:commoncontrols="clr-namespace:Microsoft.VisualStudio.LanguageServices.Implementation.CommonControls" + xmlns:utilities="clr-namespace:Microsoft.VisualStudio.LanguageServices.Implementation.Utilities" + xmlns:commoncontrols="clr-namespace:Microsoft.VisualStudio.LanguageServices.Implementation.CommonControls" + xmlns:platformimaging="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Imaging" + xmlns:vsutil="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Utilities" + xmlns:vs="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.15.0" mc:Ignorable="d" xmlns:vsui="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.15.0" xmlns:vsshell="clr-namespace:Microsoft.VisualStudio.Shell;assembly=Microsoft.VisualStudio.Shell.15.0" + platformimaging:ImageThemingUtilities.ImageBackgroundColor="{DynamicResource VsColor.ToolWindowBackground}" d:DesignHeight="450" d:DesignWidth="800"> @@ -18,6 +23,7 @@ 2, 4, 4, 2 + @@ -96,7 +102,19 @@ + Width="16" + Height="16"> + + + + + + + + >> _symbolToDependentsMap; + private readonly ImmutableDictionary>>? _symbolToDependentsMap; private readonly ImmutableDictionary _symbolToMemberViewMap; public MemberSelectionViewModel( IUIThreadOperationExecutor uiThreadOperationExecutor, ImmutableArray members, - ImmutableDictionary>> dependentsMap, + ImmutableDictionary>>? dependentsMap, TypeKind destinationTypeKind = TypeKind.Class, bool showDependentsButton = true, bool showPublicButton = true) @@ -115,9 +113,10 @@ public void SelectDependents() showProgress: true, context => { - foreach (var member in Members) + if (_symbolToDependentsMap != null) { - _symbolToDependentsMap[member.Symbol].Wait(context.UserCancellationToken); + foreach (var member in Members) + _symbolToDependentsMap[member.Symbol].Wait(context.UserCancellationToken); } }); @@ -180,11 +179,12 @@ private ImmutableHashSet FindDependentsRecursively(ISymbol member) var currentMember = queue.Dequeue(); result.Add(currentMember); visited.Add(currentMember); - foreach (var dependent in _symbolToDependentsMap[currentMember].Result) + if (_symbolToDependentsMap != null) { - if (!visited.Contains(dependent)) + foreach (var dependent in _symbolToDependentsMap[currentMember].Result) { - queue.Enqueue(dependent); + if (!visited.Contains(dependent)) + queue.Enqueue(dependent); } } } diff --git a/src/VisualStudio/Core/Def/CommonControls/NewTypeDestinationSelection.xaml.cs b/src/VisualStudio/Core/Def/CommonControls/NewTypeDestinationSelection.xaml.cs index 64af5906493e6..ea7a67e166fe4 100644 --- a/src/VisualStudio/Core/Def/CommonControls/NewTypeDestinationSelection.xaml.cs +++ b/src/VisualStudio/Core/Def/CommonControls/NewTypeDestinationSelection.xaml.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.Windows; using System.Windows.Controls; using System.Windows.Input; diff --git a/src/VisualStudio/Core/Def/DebuggerIntelliSense/AbstractDebuggerIntelliSenseContext.cs b/src/VisualStudio/Core/Def/DebuggerIntelliSense/AbstractDebuggerIntelliSenseContext.cs index 9459a5d3ecff1..ec77450e5b849 100644 --- a/src/VisualStudio/Core/Def/DebuggerIntelliSense/AbstractDebuggerIntelliSenseContext.cs +++ b/src/VisualStudio/Core/Def/DebuggerIntelliSense/AbstractDebuggerIntelliSenseContext.cs @@ -92,11 +92,7 @@ protected AbstractDebuggerIntelliSenseContext( public abstract bool CompletionStartsOnQuestionMark { get; } - protected abstract string StatementTerminator { get; } - - protected abstract int GetAdjustedContextPoint(int contextPoint, Document document); - - protected abstract ITrackingSpan GetPreviousStatementBufferAndSpan(int lastTokenEndPoint, Document document); + protected abstract IProjectionBuffer GetAdjustedBuffer(int contextPoint, Document document, ITrackingSpan debuggerMappedSpan); // Since the immediate window doesn't actually tell us when we change lines, we'll have to // determine ourselves when to rebuild our tracking spans to include only the last (input) @@ -152,21 +148,10 @@ private bool TrySetContext( regionEdit.Apply(); } - // Adjust the context point to ensure that the right information is in scope. - // For example, we may need to move the point to the end of the last statement in a method body - // in order to be able to access all local variables. var contextPoint = this.ContextBuffer.CurrentSnapshot.GetLineFromLineNumber(CurrentStatementSpan.iEndLine).Start + CurrentStatementSpan.iEndIndex; - var adjustedContextPoint = GetAdjustedContextPoint(contextPoint, document); - - // Get the previous span/text. We might have to insert another newline or something. - var previousStatementSpan = GetPreviousStatementBufferAndSpan(adjustedContextPoint, document); - - // Build the tracking span that includes the rest of the file - var restOfFileSpan = ContextBuffer.CurrentSnapshot.CreateTrackingSpanFromIndexToEnd(adjustedContextPoint, SpanTrackingMode.EdgePositive); - // Put it all into a projection buffer - _projectionBuffer = this.ProjectionBufferFactoryService.CreateProjectionBuffer(null, - [previousStatementSpan, debuggerMappedSpan, this.StatementTerminator, restOfFileSpan], ProjectionBufferOptions.None, ContentType); + // Get the adjusted buffer + _projectionBuffer = GetAdjustedBuffer(contextPoint, document, debuggerMappedSpan); // 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); diff --git a/src/VisualStudio/Core/Def/DebuggerIntelliSense/DebuggerIntellisenseFilter.cs b/src/VisualStudio/Core/Def/DebuggerIntelliSense/DebuggerIntellisenseFilter.cs index 7a52ecb07cf53..1998be1c60a8c 100644 --- a/src/VisualStudio/Core/Def/DebuggerIntelliSense/DebuggerIntellisenseFilter.cs +++ b/src/VisualStudio/Core/Def/DebuggerIntelliSense/DebuggerIntellisenseFilter.cs @@ -7,6 +7,7 @@ using System; using System.Diagnostics; using System.Runtime.InteropServices; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.VisualStudio.ComponentModelHost; using Microsoft.VisualStudio.Editor; @@ -15,7 +16,6 @@ using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.TextManager.Interop; using Microsoft.VisualStudio.Utilities; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.DebuggerIntelliSense; diff --git a/src/VisualStudio/Core/Def/DebuggerIntelliSense/DebuggerIntellisenseHelpers.cs b/src/VisualStudio/Core/Def/DebuggerIntelliSense/DebuggerIntellisenseHelpers.cs index 59f87e3ede631..d79f834673806 100644 --- a/src/VisualStudio/Core/Def/DebuggerIntelliSense/DebuggerIntellisenseHelpers.cs +++ b/src/VisualStudio/Core/Def/DebuggerIntelliSense/DebuggerIntellisenseHelpers.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.VisualStudio.Text; namespace Microsoft.VisualStudio.LanguageServices.Implementation.DebuggerIntelliSense; diff --git a/src/VisualStudio/Core/Def/DebuggerIntelliSense/DebuggerIntellisenseWorkspace.cs b/src/VisualStudio/Core/Def/DebuggerIntelliSense/DebuggerIntellisenseWorkspace.cs index 2d5179e906f5f..8fd27b88f1d27 100644 --- a/src/VisualStudio/Core/Def/DebuggerIntelliSense/DebuggerIntellisenseWorkspace.cs +++ b/src/VisualStudio/Core/Def/DebuggerIntelliSense/DebuggerIntellisenseWorkspace.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Text; diff --git a/src/VisualStudio/Core/Def/DesignerAttribute/VisualStudioDesignerAttributeService.cs b/src/VisualStudio/Core/Def/DesignerAttribute/VisualStudioDesignerAttributeService.cs index aeddff70e487b..699bfc38552a4 100644 --- a/src/VisualStudio/Core/Def/DesignerAttribute/VisualStudioDesignerAttributeService.cs +++ b/src/VisualStudio/Core/Def/DesignerAttribute/VisualStudioDesignerAttributeService.cs @@ -20,6 +20,7 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Threading; using Microsoft.VisualStudio.Designer.Interfaces; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; using Microsoft.VisualStudio.Shell.Interop; @@ -30,7 +31,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.DesignerAttribu [ExportEventListener(WellKnownEventListeners.Workspace, WorkspaceKind.Host), Shared] internal sealed class VisualStudioDesignerAttributeService : - IDesignerAttributeDiscoveryService.ICallback, IEventListener, IDisposable + IDesignerAttributeDiscoveryService.ICallback, IEventListener { private readonly VisualStudioWorkspaceImpl _workspace; private readonly IThreadingContext _threadingContext; @@ -86,18 +87,21 @@ public VisualStudioDesignerAttributeService( _threadingContext.DisposalToken); } - public void Dispose() + void IEventListener.StartListening(Workspace workspace) { - _workspace.WorkspaceChanged -= OnWorkspaceChanged; + if (workspace != _workspace) + return; + + _workspace.WorkspaceChanged += OnWorkspaceChanged; + _workQueue.AddWork(cancelExistingWork: true); } - void IEventListener.StartListening(Workspace workspace, object _) + void IEventListener.StopListening(Workspace workspace) { if (workspace != _workspace) return; - _workspace.WorkspaceChanged += OnWorkspaceChanged; - _workQueue.AddWork(cancelExistingWork: true); + _workspace.WorkspaceChanged -= OnWorkspaceChanged; } private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs e) diff --git a/src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerProvider.Factory.cs b/src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerProvider.Factory.cs index 0edbbe0210450..6a7cbe8655fe6 100644 --- a/src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerProvider.Factory.cs +++ b/src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerProvider.Factory.cs @@ -47,7 +47,7 @@ public async Task GetOrCreateProviderAsy // this will allow us to build once and deploy on different versions of VS SxS. var vsDteVersion = Version.Parse(dte.Version.Split(' ')[0]); // DTE.Version is in the format of D[D[.D[D]]][ (?+)], so we need to split out the version part and check for uninitialized Major/Minor below - var assembly = Assembly.Load($"Microsoft.VisualStudio.ExtensionManager, Version={(vsDteVersion.Major == -1 ? 0 : vsDteVersion.Major)}.{(vsDteVersion.Minor == -1 ? 0 : vsDteVersion.Minor)}.0.0, PublicKeyToken=b03f5f7f11d50a3a"); + var assembly = Assembly.Load($"Microsoft.VisualStudio.ExtensionManager, Version={(vsDteVersion.Major == -1 ? 0 : vsDteVersion.Major)}.{(vsDteVersion.Minor == -1 ? 0 : vsDteVersion.Minor)}.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); var typeIExtensionContent = assembly.GetType("Microsoft.VisualStudio.ExtensionManager.IExtensionContent"); var type = assembly.GetType("Microsoft.VisualStudio.ExtensionManager.SVsExtensionManager"); var extensionManager = _serviceProvider.GetService(type); diff --git a/src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerProvider.Loader.cs b/src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerProvider.Loader.cs index 19cb2fe3f95f6..c365e2881eca6 100644 --- a/src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerProvider.Loader.cs +++ b/src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerProvider.Loader.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.Reflection; using Microsoft.CodeAnalysis; @@ -18,7 +16,7 @@ private sealed class Loader : IAnalyzerAssemblyLoader public Loader() { - _fallbackLoader = new DefaultAnalyzerAssemblyLoader(); + _fallbackLoader = new AnalyzerAssemblyLoader(); } public void AddDependencyLocation(string fullPath) diff --git a/src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerProvider.WorkspaceEventListener.cs b/src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerProvider.WorkspaceEventListener.cs index ba45c8e817d57..b07550c7d9849 100644 --- a/src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerProvider.WorkspaceEventListener.cs +++ b/src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerProvider.WorkspaceEventListener.cs @@ -24,22 +24,16 @@ internal partial class VisualStudioDiagnosticAnalyzerProvider /// [Export] [ExportEventListener(WellKnownEventListeners.Workspace, WorkspaceKind.Host, WorkspaceKind.Interactive, WorkspaceKind.SemanticSearch), Shared] - internal sealed class WorkspaceEventListener : IEventListener + [method: ImportingConstructor] + [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + internal sealed class WorkspaceEventListener( + IAsynchronousOperationListenerProvider listenerProvider, + IVisualStudioDiagnosticAnalyzerProviderFactory providerFactory) : IEventListener { - private readonly IAsynchronousOperationListener _listener; - private readonly IVisualStudioDiagnosticAnalyzerProviderFactory _providerFactory; + private readonly IAsynchronousOperationListener _listener = listenerProvider.GetListener(nameof(Workspace)); + private readonly IVisualStudioDiagnosticAnalyzerProviderFactory _providerFactory = providerFactory; - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public WorkspaceEventListener( - IAsynchronousOperationListenerProvider listenerProvider, - IVisualStudioDiagnosticAnalyzerProviderFactory providerFactory) - { - _listener = listenerProvider.GetListener(nameof(Workspace)); - _providerFactory = providerFactory; - } - - public void StartListening(Workspace workspace, object serviceOpt) + public void StartListening(Workspace workspace) { var setter = workspace.Services.GetService(); if (setter != null) @@ -50,6 +44,11 @@ public void StartListening(Workspace workspace, object serviceOpt) } } + public void StopListening(Workspace workspace) + { + // Nothing to do here. We already kicked off the work to initialize the workspace. + } + private async Task InitializeWorkspaceAsync(ISolutionAnalyzerSetterWorkspaceService setter) { try diff --git a/src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineViewModel.cs b/src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineViewModel.cs index 439e12fccf8fa..02e1bffa43eb0 100644 --- a/src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineViewModel.cs +++ b/src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineViewModel.cs @@ -20,6 +20,7 @@ using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Threading; using Microsoft.CodeAnalysis.Utilities; using Microsoft.VisualStudio.LanguageServer.Client; using Microsoft.VisualStudio.LanguageServices.Utilities; diff --git a/src/VisualStudio/Core/Def/DocumentOutline/DocumentSymbolDataViewModelSorter.cs b/src/VisualStudio/Core/Def/DocumentOutline/DocumentSymbolDataViewModelSorter.cs index 351bcc84e61b8..db3bc907a9933 100644 --- a/src/VisualStudio/Core/Def/DocumentOutline/DocumentSymbolDataViewModelSorter.cs +++ b/src/VisualStudio/Core/Def/DocumentOutline/DocumentSymbolDataViewModelSorter.cs @@ -8,7 +8,7 @@ using System.Globalization; using System.Windows.Data; using System.Windows.Markup; -using Roslyn.Utilities; +using Microsoft.CodeAnalysis; namespace Microsoft.VisualStudio.LanguageServices.DocumentOutline; diff --git a/src/VisualStudio/Core/Def/DocumentationComments/VisualStudioDocumentationProvider.cs b/src/VisualStudio/Core/Def/DocumentationComments/VisualStudioDocumentationProvider.cs index 1378403555140..3d01824e40fac 100644 --- a/src/VisualStudio/Core/Def/DocumentationComments/VisualStudioDocumentationProvider.cs +++ b/src/VisualStudio/Core/Def/DocumentationComments/VisualStudioDocumentationProvider.cs @@ -9,7 +9,6 @@ using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.Shell.Interop; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.DocumentationComments; diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Common/EditorTextUpdater.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/EditorTextUpdater.cs index f6472a0b34bed..f37d10131c66c 100644 --- a/src/VisualStudio/Core/Def/EditorConfigSettings/Common/EditorTextUpdater.cs +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/EditorTextUpdater.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Collections.Immutable; using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Editor; diff --git a/src/VisualStudio/Core/Def/Extensions/SnapshotSpanExtensions.cs b/src/VisualStudio/Core/Def/Extensions/SnapshotSpanExtensions.cs index fd1455dafe5dd..56d15b5166fba 100644 --- a/src/VisualStudio/Core/Def/Extensions/SnapshotSpanExtensions.cs +++ b/src/VisualStudio/Core/Def/Extensions/SnapshotSpanExtensions.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.VisualStudio.Text; using VsTextSpan = Microsoft.VisualStudio.TextManager.Interop.TextSpan; diff --git a/src/VisualStudio/Core/Def/Extensions/SourceTextExtensions.cs b/src/VisualStudio/Core/Def/Extensions/SourceTextExtensions.cs index a59a43bc5f594..2fa7365201364 100644 --- a/src/VisualStudio/Core/Def/Extensions/SourceTextExtensions.cs +++ b/src/VisualStudio/Core/Def/Extensions/SourceTextExtensions.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using VsTextSpan = Microsoft.VisualStudio.TextManager.Interop.TextSpan; diff --git a/src/VisualStudio/Core/Def/Extensions/VirtualTreePointExtensions.cs b/src/VisualStudio/Core/Def/Extensions/VirtualTreePointExtensions.cs index a839bfa0c9307..a56262d8de8fc 100644 --- a/src/VisualStudio/Core/Def/Extensions/VirtualTreePointExtensions.cs +++ b/src/VisualStudio/Core/Def/Extensions/VirtualTreePointExtensions.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using VsTextSpan = Microsoft.VisualStudio.TextManager.Interop.TextSpan; diff --git a/src/VisualStudio/Core/Def/Extensions/VsTextSpanExtensions.cs b/src/VisualStudio/Core/Def/Extensions/VsTextSpanExtensions.cs index 925f35ee2919c..6d8f9d9361fc7 100644 --- a/src/VisualStudio/Core/Def/Extensions/VsTextSpanExtensions.cs +++ b/src/VisualStudio/Core/Def/Extensions/VsTextSpanExtensions.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; diff --git a/src/VisualStudio/Core/Def/ExternalAccess/LegacyCodeAnalysis/Api/ILegacyCodeAnalysisVisualStudioDiagnosticAnalyzerServiceAccessor.cs b/src/VisualStudio/Core/Def/ExternalAccess/LegacyCodeAnalysis/Api/ILegacyCodeAnalysisVisualStudioDiagnosticAnalyzerServiceAccessor.cs index 23540ec27030b..bdefef6dfa93f 100644 --- a/src/VisualStudio/Core/Def/ExternalAccess/LegacyCodeAnalysis/Api/ILegacyCodeAnalysisVisualStudioDiagnosticAnalyzerServiceAccessor.cs +++ b/src/VisualStudio/Core/Def/ExternalAccess/LegacyCodeAnalysis/Api/ILegacyCodeAnalysisVisualStudioDiagnosticAnalyzerServiceAccessor.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 Microsoft.VisualStudio.Shell.Interop; diff --git a/src/VisualStudio/Core/Def/ExternalAccess/LegacyCodeAnalysis/Api/ILegacyCodeAnalysisVisualStudioSuppressionFixServiceAccessor.cs b/src/VisualStudio/Core/Def/ExternalAccess/LegacyCodeAnalysis/Api/ILegacyCodeAnalysisVisualStudioSuppressionFixServiceAccessor.cs index 7d8742e8b352c..714fccbf89afc 100644 --- a/src/VisualStudio/Core/Def/ExternalAccess/LegacyCodeAnalysis/Api/ILegacyCodeAnalysisVisualStudioSuppressionFixServiceAccessor.cs +++ b/src/VisualStudio/Core/Def/ExternalAccess/LegacyCodeAnalysis/Api/ILegacyCodeAnalysisVisualStudioSuppressionFixServiceAccessor.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.VisualStudio.Shell.Interop; namespace Microsoft.CodeAnalysis.ExternalAccess.LegacyCodeAnalysis.Api; diff --git a/src/VisualStudio/Core/Def/ExternalAccess/LegacyCodeAnalysis/LegacyCodeAnalysisVisualStudioDiagnosticAnalyzerServiceAccessor.cs b/src/VisualStudio/Core/Def/ExternalAccess/LegacyCodeAnalysis/LegacyCodeAnalysisVisualStudioDiagnosticAnalyzerServiceAccessor.cs index eba7538fe3e9c..e1fab3941fb6d 100644 --- a/src/VisualStudio/Core/Def/ExternalAccess/LegacyCodeAnalysis/LegacyCodeAnalysisVisualStudioDiagnosticAnalyzerServiceAccessor.cs +++ b/src/VisualStudio/Core/Def/ExternalAccess/LegacyCodeAnalysis/LegacyCodeAnalysisVisualStudioDiagnosticAnalyzerServiceAccessor.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.Composition; diff --git a/src/VisualStudio/Core/Def/ExternalAccess/VSTypeScript/Api/IVsTypeScriptRemoteLanguageServiceWorkspaceAccessor.cs b/src/VisualStudio/Core/Def/ExternalAccess/VSTypeScript/Api/IVsTypeScriptRemoteLanguageServiceWorkspaceAccessor.cs index 4da111c63a1d5..9dfa5292a698d 100644 --- a/src/VisualStudio/Core/Def/ExternalAccess/VSTypeScript/Api/IVsTypeScriptRemoteLanguageServiceWorkspaceAccessor.cs +++ b/src/VisualStudio/Core/Def/ExternalAccess/VSTypeScript/Api/IVsTypeScriptRemoteLanguageServiceWorkspaceAccessor.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis; namespace Microsoft.VisualStudio.LanguageServices.ExternalAccess.VSTypeScript.Api; diff --git a/src/VisualStudio/Core/Def/ExtractClass/ExtractClassDialog.xaml.cs b/src/VisualStudio/Core/Def/ExtractClass/ExtractClassDialog.xaml.cs index e623674e74e18..1a0dd45ee7dc5 100644 --- a/src/VisualStudio/Core/Def/ExtractClass/ExtractClassDialog.xaml.cs +++ b/src/VisualStudio/Core/Def/ExtractClass/ExtractClassDialog.xaml.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.Windows; using System.Windows.Input; using Microsoft.CodeAnalysis; diff --git a/src/VisualStudio/Core/Def/ExtractInterface/ExtractInterfaceDialog.xaml.cs b/src/VisualStudio/Core/Def/ExtractInterface/ExtractInterfaceDialog.xaml.cs index 294f36a2880c6..ada2aefe57d5c 100644 --- a/src/VisualStudio/Core/Def/ExtractInterface/ExtractInterfaceDialog.xaml.cs +++ b/src/VisualStudio/Core/Def/ExtractInterface/ExtractInterfaceDialog.xaml.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.Windows; using System.Windows.Controls; using System.Windows.Input; diff --git a/src/VisualStudio/Core/Def/ExtractInterface/ExtractInterfaceDialogViewModel.cs b/src/VisualStudio/Core/Def/ExtractInterface/ExtractInterfaceDialogViewModel.cs index 3e9883fa74a87..7eb0025b1a22c 100644 --- a/src/VisualStudio/Core/Def/ExtractInterface/ExtractInterfaceDialogViewModel.cs +++ b/src/VisualStudio/Core/Def/ExtractInterface/ExtractInterfaceDialogViewModel.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.Linq; @@ -27,7 +25,7 @@ internal ExtractInterfaceDialogViewModel( IUIThreadOperationExecutor uiThreadOperationExecutor, INotificationService notificationService, string defaultInterfaceName, - List conflictingTypeNames, + ImmutableArray conflictingTypeNames, ImmutableArray memberViewModels, string defaultNamespace, string generatedNameTypeParameterSuffix, @@ -49,7 +47,7 @@ internal ExtractInterfaceDialogViewModel( languageName, defaultNamespace, generatedNameTypeParameterSuffix, - [.. conflictingTypeNames], + conflictingTypeNames, syntaxFactsService, canAddDocument); } diff --git a/src/VisualStudio/Core/Def/ExtractInterface/VisualStudioExtractInterfaceOptionsService.cs b/src/VisualStudio/Core/Def/ExtractInterface/VisualStudioExtractInterfaceOptionsService.cs index a5520a85ea979..697c26bc9a23d 100644 --- a/src/VisualStudio/Core/Def/ExtractInterface/VisualStudioExtractInterfaceOptionsService.cs +++ b/src/VisualStudio/Core/Def/ExtractInterface/VisualStudioExtractInterfaceOptionsService.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Composition; using System.Linq; using System.Threading; @@ -26,7 +27,10 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.ExtractInterfac [ExportWorkspaceService(typeof(IExtractInterfaceOptionsService), ServiceLayer.Host), Shared] [method: ImportingConstructor] [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] -internal sealed class VisualStudioExtractInterfaceOptionsService(IGlyphService glyphService, IThreadingContext threadingContext, IUIThreadOperationExecutor uiThreadOperationExecutor) : IExtractInterfaceOptionsService +internal sealed class VisualStudioExtractInterfaceOptionsService( + IGlyphService glyphService, + IThreadingContext threadingContext, + IUIThreadOperationExecutor uiThreadOperationExecutor) : IExtractInterfaceOptionsService { private readonly IGlyphService _glyphService = glyphService; private readonly IThreadingContext _threadingContext = threadingContext; @@ -34,12 +38,11 @@ internal sealed class VisualStudioExtractInterfaceOptionsService(IGlyphService g public ExtractInterfaceOptionsResult GetExtractInterfaceOptions( Document document, - List extractableMembers, + ImmutableArray extractableMembers, string defaultInterfaceName, - List allTypeNames, + ImmutableArray allTypeNames, string defaultNamespace, - string generatedNameTypeParameterSuffix, - CancellationToken cancellationToken) + string generatedNameTypeParameterSuffix) { _threadingContext.ThrowIfNotOnUIThread(); var solution = document.Project.Solution; diff --git a/src/VisualStudio/Core/Def/F1Help/AbstractHelpContextService.cs b/src/VisualStudio/Core/Def/F1Help/AbstractHelpContextService.cs index 2fcaf8540ac7b..044d79d90e967 100644 --- a/src/VisualStudio/Core/Def/F1Help/AbstractHelpContextService.cs +++ b/src/VisualStudio/Core/Def/F1Help/AbstractHelpContextService.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; @@ -45,5 +43,5 @@ internal abstract class AbstractHelpContextService : IHelpContextService public abstract Task GetHelpTermAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken); - public abstract string FormatSymbol(ISymbol symbol); + public abstract string? FormatSymbol(ISymbol symbol); } diff --git a/src/VisualStudio/Core/Def/F1Help/IHelpContextService.cs b/src/VisualStudio/Core/Def/F1Help/IHelpContextService.cs index 1f3a8fa6e70ef..0eac1400cc821 100644 --- a/src/VisualStudio/Core/Def/F1Help/IHelpContextService.cs +++ b/src/VisualStudio/Core/Def/F1Help/IHelpContextService.cs @@ -17,5 +17,5 @@ internal interface IHelpContextService : ILanguageService Task GetHelpTermAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken); - string FormatSymbol(ISymbol symbol); + string? FormatSymbol(ISymbol symbol); } diff --git a/src/VisualStudio/Core/Def/FindReferences/ContainingMemberColumnDefinition.cs b/src/VisualStudio/Core/Def/FindReferences/ContainingMemberColumnDefinition.cs index 13a5443c42b87..e9a48eb11a722 100644 --- a/src/VisualStudio/Core/Def/FindReferences/ContainingMemberColumnDefinition.cs +++ b/src/VisualStudio/Core/Def/FindReferences/ContainingMemberColumnDefinition.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.ComponentModel.Composition; using Microsoft.CodeAnalysis.FindSymbols.Finders; diff --git a/src/VisualStudio/Core/Def/FindReferences/Contexts/AbstractTableDataSourceFindUsagesContext.cs b/src/VisualStudio/Core/Def/FindReferences/Contexts/AbstractTableDataSourceFindUsagesContext.cs index a4a0895b1616d..0a7c6416824b2 100644 --- a/src/VisualStudio/Core/Def/FindReferences/Contexts/AbstractTableDataSourceFindUsagesContext.cs +++ b/src/VisualStudio/Core/Def/FindReferences/Contexts/AbstractTableDataSourceFindUsagesContext.cs @@ -25,6 +25,7 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Threading; using Microsoft.VisualStudio.Shell.FindAllReferences; using Microsoft.VisualStudio.Shell.TableControl; using Microsoft.VisualStudio.Shell.TableManager; diff --git a/src/VisualStudio/Core/Def/FindReferences/Entries/AbstractDocumentSpanEntry.cs b/src/VisualStudio/Core/Def/FindReferences/Entries/AbstractDocumentSpanEntry.cs index 69965dc0e8136..9dcf56e7cffe9 100644 --- a/src/VisualStudio/Core/Def/FindReferences/Entries/AbstractDocumentSpanEntry.cs +++ b/src/VisualStudio/Core/Def/FindReferences/Entries/AbstractDocumentSpanEntry.cs @@ -83,7 +83,7 @@ await documentNavigationService.TryNavigateToPositionAsync( var service = documentSpan.Document.DocumentServiceProvider.GetService(); if (service == null) { - return new MappedSpanResult(documentSpan.Document.FilePath, sourceText.Lines.GetLinePositionSpan(documentSpan.SourceSpan), documentSpan.SourceSpan); + return new MappedSpanResult(documentSpan.Document.FilePath!, sourceText.Lines.GetLinePositionSpan(documentSpan.SourceSpan), documentSpan.SourceSpan); } var results = await service.MapSpansAsync( @@ -91,7 +91,7 @@ await documentNavigationService.TryNavigateToPositionAsync( if (results.IsDefaultOrEmpty) { - return new MappedSpanResult(documentSpan.Document.FilePath, sourceText.Lines.GetLinePositionSpan(documentSpan.SourceSpan), documentSpan.SourceSpan); + return new MappedSpanResult(documentSpan.Document.FilePath!, sourceText.Lines.GetLinePositionSpan(documentSpan.SourceSpan), documentSpan.SourceSpan); } // if span mapping service filtered out the span, make sure diff --git a/src/VisualStudio/Core/Def/FindReferences/Entries/SimpleMessageEntry.cs b/src/VisualStudio/Core/Def/FindReferences/Entries/SimpleMessageEntry.cs index d0e60da16ee5b..3265dc00db67a 100644 --- a/src/VisualStudio/Core/Def/FindReferences/Entries/SimpleMessageEntry.cs +++ b/src/VisualStudio/Core/Def/FindReferences/Entries/SimpleMessageEntry.cs @@ -4,9 +4,9 @@ using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Navigation; using Microsoft.VisualStudio.Shell.TableManager; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.FindUsages; diff --git a/src/VisualStudio/Core/Def/FindReferences/StreamingFindUsagesPresenter.cs b/src/VisualStudio/Core/Def/FindReferences/StreamingFindUsagesPresenter.cs index 69a9189727488..1361f431f020d 100644 --- a/src/VisualStudio/Core/Def/FindReferences/StreamingFindUsagesPresenter.cs +++ b/src/VisualStudio/Core/Def/FindReferences/StreamingFindUsagesPresenter.cs @@ -28,7 +28,6 @@ using Microsoft.VisualStudio.Shell.TableControl; using Microsoft.VisualStudio.Shell.TableManager; using Microsoft.VisualStudio.Text.Classification; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.FindUsages; diff --git a/src/VisualStudio/Core/Def/GenerateType/GenerateTypeDialog.xaml.cs b/src/VisualStudio/Core/Def/GenerateType/GenerateTypeDialog.xaml.cs index 6faa8ef9f0fcd..31d98aa3f07d4 100644 --- a/src/VisualStudio/Core/Def/GenerateType/GenerateTypeDialog.xaml.cs +++ b/src/VisualStudio/Core/Def/GenerateType/GenerateTypeDialog.xaml.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.Windows; using System.Windows.Controls; diff --git a/src/VisualStudio/Core/Def/HACK_ThemeColorFixer.cs b/src/VisualStudio/Core/Def/HACK_ThemeColorFixer.cs index e91e1f328f051..4799e923de405 100644 --- a/src/VisualStudio/Core/Def/HACK_ThemeColorFixer.cs +++ b/src/VisualStudio/Core/Def/HACK_ThemeColorFixer.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.ObjectModel; using System.ComponentModel.Composition; diff --git a/src/VisualStudio/Core/Def/IAnalyzerNodeSetup.cs b/src/VisualStudio/Core/Def/IAnalyzerNodeSetup.cs index 3b659254e82f8..8d255e214a5e5 100644 --- a/src/VisualStudio/Core/Def/IAnalyzerNodeSetup.cs +++ b/src/VisualStudio/Core/Def/IAnalyzerNodeSetup.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.VisualStudio.Shell; diff --git a/src/VisualStudio/Core/Def/ID.CSharpCommands.cs b/src/VisualStudio/Core/Def/ID.CSharpCommands.cs index 1631078fa0112..662c709ad2dea 100644 --- a/src/VisualStudio/Core/Def/ID.CSharpCommands.cs +++ b/src/VisualStudio/Core/Def/ID.CSharpCommands.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.VisualStudio.LanguageServices; internal static partial class ID diff --git a/src/VisualStudio/Core/Def/IInvisibleEditor.cs b/src/VisualStudio/Core/Def/IInvisibleEditor.cs index 06a5cfa8f15de..09aa4ba17dec0 100644 --- a/src/VisualStudio/Core/Def/IInvisibleEditor.cs +++ b/src/VisualStudio/Core/Def/IInvisibleEditor.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.VisualStudio.Text; diff --git a/src/VisualStudio/Core/Def/Implementation/AbstractEditorFactory.cs b/src/VisualStudio/Core/Def/Implementation/AbstractEditorFactory.cs index c0888cb0e04b6..c5168624c3e6d 100644 --- a/src/VisualStudio/Core/Def/Implementation/AbstractEditorFactory.cs +++ b/src/VisualStudio/Core/Def/Implementation/AbstractEditorFactory.cs @@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; @@ -25,22 +24,18 @@ using Microsoft.VisualStudio.TextManager.Interop; using Microsoft.VisualStudio.Utilities; using Microsoft.VisualStudio.WinForms.Interfaces; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation; /// /// The base class of both the Roslyn editor factories. /// -internal abstract class AbstractEditorFactory : IVsEditorFactory, IVsEditorFactory4, IVsEditorFactoryNotify +internal abstract class AbstractEditorFactory(IComponentModel componentModel) : IVsEditorFactory, IVsEditorFactory4, IVsEditorFactoryNotify { - private readonly IComponentModel _componentModel; + private readonly IComponentModel _componentModel = componentModel; private Microsoft.VisualStudio.OLE.Interop.IServiceProvider? _oleServiceProvider; private bool _encoding; - protected AbstractEditorFactory(IComponentModel componentModel) - => _componentModel = componentModel; - protected abstract string ContentTypeName { get; } protected abstract string LanguageName { get; } diff --git a/src/VisualStudio/Core/Def/Implementation/AbstractOleCommandTarget.Query.cs b/src/VisualStudio/Core/Def/Implementation/AbstractOleCommandTarget.Query.cs index 3d7ae6167f9e0..5ecfbc0281b4a 100644 --- a/src/VisualStudio/Core/Def/Implementation/AbstractOleCommandTarget.Query.cs +++ b/src/VisualStudio/Core/Def/Implementation/AbstractOleCommandTarget.Query.cs @@ -5,8 +5,8 @@ #nullable disable using System; +using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.OLE.Interop; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation; diff --git a/src/VisualStudio/Core/Def/Implementation/AbstractOleCommandTarget.cs b/src/VisualStudio/Core/Def/Implementation/AbstractOleCommandTarget.cs index 937c7342b8289..47fca7fc4bda2 100644 --- a/src/VisualStudio/Core/Def/Implementation/AbstractOleCommandTarget.cs +++ b/src/VisualStudio/Core/Def/Implementation/AbstractOleCommandTarget.cs @@ -4,6 +4,7 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.VisualStudio.ComponentModelHost; @@ -12,7 +13,6 @@ using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.TextManager.Interop; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation; diff --git a/src/VisualStudio/Core/Def/Implementation/AbstractVsTextViewFilter.cs b/src/VisualStudio/Core/Def/Implementation/AbstractVsTextViewFilter.cs index c76b3b9699c59..70eb12b511530 100644 --- a/src/VisualStudio/Core/Def/Implementation/AbstractVsTextViewFilter.cs +++ b/src/VisualStudio/Core/Def/Implementation/AbstractVsTextViewFilter.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.BraceMatching; using Microsoft.CodeAnalysis.Debugging; using Microsoft.CodeAnalysis.Editor; diff --git a/src/VisualStudio/Core/Def/Implementation/ICodeModelNavigationPointService.cs b/src/VisualStudio/Core/Def/Implementation/ICodeModelNavigationPointService.cs index 9aaffb5d09402..1ca589511f72c 100644 --- a/src/VisualStudio/Core/Def/Implementation/ICodeModelNavigationPointService.cs +++ b/src/VisualStudio/Core/Def/Implementation/ICodeModelNavigationPointService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Formatting; diff --git a/src/VisualStudio/Core/Def/Implementation/VisualStudioUIContextActivationService.cs b/src/VisualStudio/Core/Def/Implementation/VisualStudioUIContextActivationService.cs index 41b73f8a55c5c..63fd2e3236b9a 100644 --- a/src/VisualStudio/Core/Def/Implementation/VisualStudioUIContextActivationService.cs +++ b/src/VisualStudio/Core/Def/Implementation/VisualStudioUIContextActivationService.cs @@ -4,10 +4,10 @@ using System; using System.Composition; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.VisualStudio.Shell; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation; diff --git a/src/VisualStudio/Core/Def/InheritanceMargin/InheritanceGlyphFactory.cs b/src/VisualStudio/Core/Def/InheritanceMargin/InheritanceGlyphFactory.cs index 3529db24e4879..855b372ac16ee 100644 --- a/src/VisualStudio/Core/Def/InheritanceMargin/InheritanceGlyphFactory.cs +++ b/src/VisualStudio/Core/Def/InheritanceMargin/InheritanceGlyphFactory.cs @@ -13,7 +13,6 @@ using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Formatting; using Microsoft.VisualStudio.Utilities; -using Roslyn.Utilities; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.InheritanceMargin; diff --git a/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/MenuItemContainerTemplateSelector.cs b/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/MenuItemContainerTemplateSelector.cs index ea160fee7fdee..ef414babf9f31 100644 --- a/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/MenuItemContainerTemplateSelector.cs +++ b/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/MenuItemContainerTemplateSelector.cs @@ -4,7 +4,7 @@ using System.Windows; using System.Windows.Controls; -using Roslyn.Utilities; +using Microsoft.CodeAnalysis; namespace Microsoft.VisualStudio.LanguageServices.Implementation.InheritanceMargin.MarginGlyph; diff --git a/src/VisualStudio/Core/Def/Interactive/LogMessage.cs b/src/VisualStudio/Core/Def/Interactive/LogMessage.cs index 27eac0147b20a..5d66eb88594e0 100644 --- a/src/VisualStudio/Core/Def/Interactive/LogMessage.cs +++ b/src/VisualStudio/Core/Def/Interactive/LogMessage.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.VisualStudio.LanguageServices.Interactive; internal static class LogMessage diff --git a/src/VisualStudio/Core/Def/Interactive/VsInteractiveWindowProvider.cs b/src/VisualStudio/Core/Def/Interactive/VsInteractiveWindowProvider.cs index bd38aac5f3580..9b4fe70571d2a 100644 --- a/src/VisualStudio/Core/Def/Interactive/VsInteractiveWindowProvider.cs +++ b/src/VisualStudio/Core/Def/Interactive/VsInteractiveWindowProvider.cs @@ -12,6 +12,7 @@ using System.Diagnostics; using System.Linq; using InteractiveHost::Microsoft.CodeAnalysis.Interactive; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Interactive; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.VisualStudio.InteractiveWindow.Commands; diff --git a/src/VisualStudio/Core/Def/Interactive/VsUpdateSolutionEvents.cs b/src/VisualStudio/Core/Def/Interactive/VsUpdateSolutionEvents.cs index b9a4540eff33c..75b19605fb0b7 100644 --- a/src/VisualStudio/Core/Def/Interactive/VsUpdateSolutionEvents.cs +++ b/src/VisualStudio/Core/Def/Interactive/VsUpdateSolutionEvents.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.Runtime.InteropServices; using System.Threading.Tasks; using Microsoft.VisualStudio.Shell.Interop; diff --git a/src/VisualStudio/Core/Def/Interop/ComAggregate.cs b/src/VisualStudio/Core/Def/Interop/ComAggregate.cs index 463116bded3f7..86c23d4e7d16e 100644 --- a/src/VisualStudio/Core/Def/Interop/ComAggregate.cs +++ b/src/VisualStudio/Core/Def/Interop/ComAggregate.cs @@ -4,7 +4,7 @@ using System.Diagnostics; using System.Runtime.InteropServices; -using Roslyn.Utilities; +using Microsoft.CodeAnalysis; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Interop; diff --git a/src/VisualStudio/Core/Def/Interop/Feedback.cs b/src/VisualStudio/Core/Def/Interop/Feedback.cs index 763d1e38ae3bb..2cdf47a14504d 100644 --- a/src/VisualStudio/Core/Def/Interop/Feedback.cs +++ b/src/VisualStudio/Core/Def/Interop/Feedback.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.Runtime.InteropServices; namespace Microsoft.VisualStudio.Feedback.Interop; diff --git a/src/VisualStudio/Core/Def/KeybindingReset/KeybindingResetDetector.cs b/src/VisualStudio/Core/Def/KeybindingReset/KeybindingResetDetector.cs index e94d9c9579b6b..cd088e1f5d81c 100644 --- a/src/VisualStudio/Core/Def/KeybindingReset/KeybindingResetDetector.cs +++ b/src/VisualStudio/Core/Def/KeybindingReset/KeybindingResetDetector.cs @@ -16,6 +16,7 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Threading; using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; using Microsoft.VisualStudio.OLE.Interop; using Microsoft.VisualStudio.PlatformUI.OleComponentSupport; diff --git a/src/VisualStudio/Core/Def/LanguageClient/LogHubLspLogger.cs b/src/VisualStudio/Core/Def/LanguageClient/LogHubLspLogger.cs index 4aacd546fca84..85206d8e1ab58 100644 --- a/src/VisualStudio/Core/Def/LanguageClient/LogHubLspLogger.cs +++ b/src/VisualStudio/Core/Def/LanguageClient/LogHubLspLogger.cs @@ -4,10 +4,10 @@ using System; using System.Diagnostics; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.LanguageServer; using Microsoft.CommonLanguageServerProtocol.Framework; using Microsoft.VisualStudio.LogHub; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.LanguageClient; diff --git a/src/VisualStudio/Core/Def/LanguageService/AbstractCreateServicesOnTextViewConnection.cs b/src/VisualStudio/Core/Def/LanguageService/AbstractCreateServicesOnTextViewConnection.cs index 629a09e27f115..01e7b4d0faf02 100644 --- a/src/VisualStudio/Core/Def/LanguageService/AbstractCreateServicesOnTextViewConnection.cs +++ b/src/VisualStudio/Core/Def/LanguageService/AbstractCreateServicesOnTextViewConnection.cs @@ -16,9 +16,9 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Snippets; +using Microsoft.CodeAnalysis.Threading; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService; diff --git a/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService.IVsAutoOutliningClient.cs b/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService.IVsAutoOutliningClient.cs index a85b4b8317d46..41b3ff62c5dd8 100644 --- a/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService.IVsAutoOutliningClient.cs +++ b/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService.IVsAutoOutliningClient.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.VisualStudio.TextManager.Interop; namespace Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService; diff --git a/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService.cs b/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService.cs index dff463140016e..988564af7482b 100644 --- a/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService.cs +++ b/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService.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; namespace Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService; diff --git a/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.IVsLanguageDebugInfo.cs b/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.IVsLanguageDebugInfo.cs index 9820e02d3087e..8cd5493da8635 100644 --- a/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.IVsLanguageDebugInfo.cs +++ b/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.IVsLanguageDebugInfo.cs @@ -5,9 +5,9 @@ #nullable disable using System; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; -using Roslyn.Utilities; using IVsEnumBSTR = Microsoft.VisualStudio.TextManager.Interop.IVsEnumBSTR; using IVsTextBuffer = Microsoft.VisualStudio.TextManager.Interop.IVsTextBuffer; using TextSpan = Microsoft.VisualStudio.TextManager.Interop.TextSpan; diff --git a/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.IVsLanguageDebugInfo2.cs b/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.IVsLanguageDebugInfo2.cs index cb3078b2cc18c..37d4110b8178c 100644 --- a/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.IVsLanguageDebugInfo2.cs +++ b/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.IVsLanguageDebugInfo2.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.VisualStudio.TextManager.Interop; diff --git a/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.VsCodeWindowManager.cs b/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.VsCodeWindowManager.cs index e56b9e517e887..61e63b0fb5b06 100644 --- a/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.VsCodeWindowManager.cs +++ b/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.VsCodeWindowManager.cs @@ -158,7 +158,7 @@ private void AddDropdownBar(IVsDropdownBarManager dropdownManager) var navigationBarClient = new NavigationBarClient(dropdownManager, _codeWindow, _languageService.SystemServiceProvider, _languageService.Workspace); var textBuffer = _languageService.EditorAdaptersFactoryService.GetDataBuffer(buffer); var controllerFactoryService = _languageService.Package.ComponentModel.GetService(); - var newController = controllerFactoryService.CreateController(navigationBarClient, textBuffer); + var newController = controllerFactoryService.CreateController(navigationBarClient, textBuffer!); var hr = dropdownManager.AddDropdownBar(cCombos: 3, pClient: navigationBarClient); if (ErrorHandler.Failed(hr)) diff --git a/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.VsLanguageDebugInfo.cs b/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.VsLanguageDebugInfo.cs index abdf5313d6093..790628ecd98ad 100644 --- a/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.VsLanguageDebugInfo.cs +++ b/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.VsLanguageDebugInfo.cs @@ -13,7 +13,6 @@ using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text.Shared.Extensions; -using Microsoft.Internal.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.LanguageServices.Implementation.Extensions; using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; using Microsoft.VisualStudio.Utilities; @@ -166,13 +165,13 @@ public int GetProximityExpressions(IVsTextBuffer pBuffer, int iLine, int iCol, i public int IsMappedLocation(IVsTextBuffer pBuffer, int iLine, int iCol) => VSConstants.E_NOTIMPL; - public int ResolveName(string pszName, uint dwFlags, out IVsEnumDebugName? ppNames) + public int ResolveName(string? pszName, uint dwFlags, out IVsEnumDebugName? ppNames) { // In VS, this method frequently get's called with an empty string to test if the language service // supports this method (some language services, like F#, implement IVsLanguageDebugInfo but don't // implement this method). In that scenario, there's no sense doing work, so we'll just return // S_FALSE (as the old VB language service did). - if (string.IsNullOrEmpty(pszName)) + if (pszName is null or "") { ppNames = null; return VSConstants.S_FALSE; @@ -227,7 +226,7 @@ private async ValueTask CreateDebugNameAsync( if (mappedSpan != null) span = mappedSpan.Value; - return new VsDebugName(breakpoint.LocationNameOpt, filePath, span); + return new VsDebugName(breakpoint.LocationNameOpt, filePath!, span); } public int ValidateBreakpointLocation(IVsTextBuffer pBuffer, int iLine, int iCol, VsTextSpan[] pCodeSpan) diff --git a/src/VisualStudio/Core/Def/LanguageService/AbstractPackage.cs b/src/VisualStudio/Core/Def/LanguageService/AbstractPackage.cs index e6babc4236130..64ff1b7dde1fb 100644 --- a/src/VisualStudio/Core/Def/LanguageService/AbstractPackage.cs +++ b/src/VisualStudio/Core/Def/LanguageService/AbstractPackage.cs @@ -35,16 +35,17 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke Assumes.Present(_componentModel_doNotAccessDirectly); } - protected override Task OnAfterPackageLoadedAsync(CancellationToken cancellationToken) + protected override async Task OnAfterPackageLoadedAsync(CancellationToken cancellationToken) { + await base.OnAfterPackageLoadedAsync(cancellationToken).ConfigureAwait(false); + // TODO: remove, workaround for https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1985204 var globalOptions = ComponentModel.GetService(); if (globalOptions.GetOption(SemanticSearchFeatureFlag.Enabled)) { + await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); UIContext.FromUIContextGuid(new Guid(SemanticSearchFeatureFlag.UIContextId)).IsActive = true; } - - return base.OnAfterPackageLoadedAsync(cancellationToken); } protected async Task LoadComponentsInUIContextOnceSolutionFullyLoadedAsync(CancellationToken cancellationToken) diff --git a/src/VisualStudio/Core/Def/LanguageService/AbstractPackage`2.cs b/src/VisualStudio/Core/Def/LanguageService/AbstractPackage`2.cs index d53c66478e03d..c1afbf754dc74 100644 --- a/src/VisualStudio/Core/Def/LanguageService/AbstractPackage`2.cs +++ b/src/VisualStudio/Core/Def/LanguageService/AbstractPackage`2.cs @@ -2,12 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Packaging; using Microsoft.CodeAnalysis.SymbolSearch; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; @@ -25,10 +24,11 @@ internal abstract partial class AbstractPackage : Ab where TPackage : AbstractPackage where TLanguageService : AbstractLanguageService { - private TLanguageService _languageService; + private TLanguageService? _languageService; - private PackageInstallerService _packageInstallerService; - private VisualStudioSymbolSearchService _symbolSearchService; + private PackageInstallerService? _packageInstallerService; + private VisualStudioSymbolSearchService? _symbolSearchService; + private IVsShell? _shell; protected AbstractPackage() { @@ -40,12 +40,14 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - var shell = (IVsShell7)await GetServiceAsync(typeof(SVsShell)).ConfigureAwait(true); - var solution = (IVsSolution)await GetServiceAsync(typeof(SVsSolution)).ConfigureAwait(true); - cancellationToken.ThrowIfCancellationRequested(); + var shell = (IVsShell7?)await GetServiceAsync(typeof(SVsShell)).ConfigureAwait(true); + var solution = (IVsSolution?)await GetServiceAsync(typeof(SVsSolution)).ConfigureAwait(true); Assumes.Present(shell); Assumes.Present(solution); + _shell = (IVsShell?)shell; + Assumes.Present(_shell); + foreach (var editorFactory in CreateEditorFactories()) { RegisterEditorFactory(editorFactory); @@ -61,7 +63,7 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke _languageService = CreateLanguageService(); await _languageService.SetupAsync(cancellationToken).ConfigureAwait(false); - return _languageService.ComAggregate; + return _languageService.ComAggregate!; }); await shell.LoadPackageAsync(Guids.RoslynPackageId); @@ -69,11 +71,11 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke var miscellaneousFilesWorkspace = this.ComponentModel.GetService(); RegisterMiscellaneousFilesWorkspaceInformation(miscellaneousFilesWorkspace); - if (!IVsShellExtensions.IsInCommandLineMode(JoinableTaskFactory)) + if (!_shell.IsInCommandLineMode()) { // not every derived package support object browser and for those languages // this is a no op - await RegisterObjectBrowserLibraryManagerAsync(cancellationToken).ConfigureAwait(true); + RegisterObjectBrowserLibraryManager(); } LoadComponentsInUIContextOnceSolutionFullyLoadedAsync(cancellationToken).Forget(); @@ -117,9 +119,11 @@ protected override void Dispose(bool disposing) { if (disposing) { - if (!IVsShellExtensions.IsInCommandLineMode(JoinableTaskFactory)) + // Per VS core team, Package.Dispose is called on the UI thread. + Contract.ThrowIfFalse(JoinableTaskFactory.Context.IsOnMainThread); + if (_shell != null && !_shell.IsInCommandLineMode()) { - JoinableTaskFactory.Run(async () => await UnregisterObjectBrowserLibraryManagerAsync(CancellationToken.None).ConfigureAwait(true)); + UnregisterObjectBrowserLibraryManager(); } // If we've created the language service then tell it it's time to clean itself up now. @@ -135,17 +139,15 @@ protected override void Dispose(bool disposing) protected abstract string RoslynLanguageName { get; } - protected virtual Task RegisterObjectBrowserLibraryManagerAsync(CancellationToken cancellationToken) + protected virtual void RegisterObjectBrowserLibraryManager() { // it is virtual rather than abstract to not break other languages which derived from our // base package implementations - return Task.CompletedTask; } - protected virtual Task UnregisterObjectBrowserLibraryManagerAsync(CancellationToken cancellationToken) + protected virtual void UnregisterObjectBrowserLibraryManager() { // it is virtual rather than abstract to not break other languages which derived from our // base package implementations - return Task.CompletedTask; } } diff --git a/src/VisualStudio/Core/Def/Library/AbstractLibraryManager.cs b/src/VisualStudio/Core/Def/Library/AbstractLibraryManager.cs index 1544d9983e218..2e05c7a1d69aa 100644 --- a/src/VisualStudio/Core/Def/Library/AbstractLibraryManager.cs +++ b/src/VisualStudio/Core/Def/Library/AbstractLibraryManager.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.Editor.Shared.Utilities; using Microsoft.VisualStudio.ComponentModelHost; diff --git a/src/VisualStudio/Core/Def/Library/AbstractLibraryManager_IOleCommandTarget.cs b/src/VisualStudio/Core/Def/Library/AbstractLibraryManager_IOleCommandTarget.cs index c66fa76e4e793..1343a9a07c0c4 100644 --- a/src/VisualStudio/Core/Def/Library/AbstractLibraryManager_IOleCommandTarget.cs +++ b/src/VisualStudio/Core/Def/Library/AbstractLibraryManager_IOleCommandTarget.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.VisualStudio.OLE.Interop; diff --git a/src/VisualStudio/Core/Def/Library/AbstractLibraryService.cs b/src/VisualStudio/Core/Def/Library/AbstractLibraryService.cs index 321f868ec4708..4183d6041f559 100644 --- a/src/VisualStudio/Core/Def/Library/AbstractLibraryService.cs +++ b/src/VisualStudio/Core/Def/Library/AbstractLibraryService.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; using Microsoft.VisualStudio.LanguageServices.Implementation.Library.VsNavInfo; diff --git a/src/VisualStudio/Core/Def/Library/ILibraryService.cs b/src/VisualStudio/Core/Def/Library/ILibraryService.cs index f79d93b015ea3..0e21eb290941d 100644 --- a/src/VisualStudio/Core/Def/Library/ILibraryService.cs +++ b/src/VisualStudio/Core/Def/Library/ILibraryService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Host; using Microsoft.VisualStudio.LanguageServices.Implementation.Library.VsNavInfo; diff --git a/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractDescriptionBuilder.LinkFlags.cs b/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractDescriptionBuilder.LinkFlags.cs index f1841f69a59e9..9fc3118f44b4d 100644 --- a/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractDescriptionBuilder.LinkFlags.cs +++ b/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractDescriptionBuilder.LinkFlags.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; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectBrowser; diff --git a/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager_Description.cs b/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager_Description.cs index dfce8ffdb2c53..59800af59ec80 100644 --- a/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager_Description.cs +++ b/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager_Description.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.VisualStudio.Shell.Interop; diff --git a/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager_ListItems.cs b/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager_ListItems.cs index 171dcc085cbd9..f9bbbc26a14ec 100644 --- a/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager_ListItems.cs +++ b/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager_ListItems.cs @@ -2,9 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - -using System; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; diff --git a/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager_Search.cs b/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager_Search.cs index 1e1398be7e774..f997206dc6ae1 100644 --- a/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager_Search.cs +++ b/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager_Search.cs @@ -4,7 +4,6 @@ #nullable disable -using System; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; diff --git a/src/VisualStudio/Core/Def/Library/ObjectBrowser/Helpers.cs b/src/VisualStudio/Core/Def/Library/ObjectBrowser/Helpers.cs index 2e795297e017e..c8abc4011b95f 100644 --- a/src/VisualStudio/Core/Def/Library/ObjectBrowser/Helpers.cs +++ b/src/VisualStudio/Core/Def/Library/ObjectBrowser/Helpers.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.Diagnostics; using Microsoft.VisualStudio.Shell.Interop; diff --git a/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/FolderListItem.cs b/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/FolderListItem.cs index d5b6d53b8cddb..744cd107f4400 100644 --- a/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/FolderListItem.cs +++ b/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/FolderListItem.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.Language.Intellisense; diff --git a/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/MemberListItem.cs b/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/MemberListItem.cs index a68f9f5dcce40..5e9307b8e8d7e 100644 --- a/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/MemberListItem.cs +++ b/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/MemberListItem.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.Diagnostics; using Microsoft.CodeAnalysis; diff --git a/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/NamespaceListItem.cs b/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/NamespaceListItem.cs index c263a0e1edd62..74f1ebe43b8d4 100644 --- a/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/NamespaceListItem.cs +++ b/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/NamespaceListItem.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectBrowser.Lists; diff --git a/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/ProjectListItem.cs b/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/ProjectListItem.cs index 8ef7a09270276..101086e302397 100644 --- a/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/ProjectListItem.cs +++ b/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/ProjectListItem.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; using Microsoft.VisualStudio.Language.Intellisense; diff --git a/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/SymbolListItem`1.cs b/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/SymbolListItem`1.cs index a5b9b7274b9cf..1da6015d840b8 100644 --- a/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/SymbolListItem`1.cs +++ b/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/SymbolListItem`1.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectBrowser.Lists; diff --git a/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/TypeListItem.cs b/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/TypeListItem.cs index 4cbd1a1cfde19..22317eb94dea2 100644 --- a/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/TypeListItem.cs +++ b/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/TypeListItem.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectBrowser.Lists; diff --git a/src/VisualStudio/Core/Def/Library/VsNavInfo/Extensions.cs b/src/VisualStudio/Core/Def/Library/VsNavInfo/Extensions.cs index 3a18805279743..91e299784c948 100644 --- a/src/VisualStudio/Core/Def/Library/VsNavInfo/Extensions.cs +++ b/src/VisualStudio/Core/Def/Library/VsNavInfo/Extensions.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using Microsoft.VisualStudio.Shell.Interop; diff --git a/src/VisualStudio/Core/Def/Library/VsNavInfo/NavInfoNode.cs b/src/VisualStudio/Core/Def/Library/VsNavInfo/NavInfoNode.cs index c3b2a10bc1671..709438a5ba91f 100644 --- a/src/VisualStudio/Core/Def/Library/VsNavInfo/NavInfoNode.cs +++ b/src/VisualStudio/Core/Def/Library/VsNavInfo/NavInfoNode.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.VisualStudio.Shell.Interop; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.VsNavInfo; diff --git a/src/VisualStudio/Core/Def/Library/VsNavInfo/NavInfoNodeEnum.cs b/src/VisualStudio/Core/Def/Library/VsNavInfo/NavInfoNodeEnum.cs index ce60f79f5e596..135f983c60754 100644 --- a/src/VisualStudio/Core/Def/Library/VsNavInfo/NavInfoNodeEnum.cs +++ b/src/VisualStudio/Core/Def/Library/VsNavInfo/NavInfoNodeEnum.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using Microsoft.VisualStudio.Shell.Interop; diff --git a/src/VisualStudio/Core/Def/Log/VisualStudioErrorLogger.cs b/src/VisualStudio/Core/Def/Log/VisualStudioErrorLogger.cs index f1becce9317c2..279b822a1e962 100644 --- a/src/VisualStudio/Core/Def/Log/VisualStudioErrorLogger.cs +++ b/src/VisualStudio/Core/Def/Log/VisualStudioErrorLogger.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.Composition; using Microsoft.CodeAnalysis.ErrorLogger; diff --git a/src/VisualStudio/Core/Def/Microsoft.VisualStudio.LanguageServices.csproj b/src/VisualStudio/Core/Def/Microsoft.VisualStudio.LanguageServices.csproj index 007c55fa569e3..7ecc7bdaa2455 100644 --- a/src/VisualStudio/Core/Def/Microsoft.VisualStudio.LanguageServices.csproj +++ b/src/VisualStudio/Core/Def/Microsoft.VisualStudio.LanguageServices.csproj @@ -51,9 +51,6 @@ - - - @@ -94,6 +91,7 @@ + diff --git a/src/VisualStudio/Core/Def/MoveStaticMembers/StaticMemberSelection.xaml b/src/VisualStudio/Core/Def/MoveStaticMembers/StaticMemberSelection.xaml index fb93072343c9f..3c1f17954669b 100644 --- a/src/VisualStudio/Core/Def/MoveStaticMembers/StaticMemberSelection.xaml +++ b/src/VisualStudio/Core/Def/MoveStaticMembers/StaticMemberSelection.xaml @@ -48,7 +48,9 @@ + Source="{Binding Glyph}" + Width="16" + Height="16"/> selectedNodeSymbols, LinkedList history, - IGlyphService? glyphService, + IGlyphService glyphService, IUIThreadOperationExecutor uiThreadOperationExecutor) { var membersInType = selectedType.GetMembers(). diff --git a/src/VisualStudio/Core/Def/MoveToNamespace/MoveToNamespaceDialog.xaml.cs b/src/VisualStudio/Core/Def/MoveToNamespace/MoveToNamespaceDialog.xaml.cs index b9e088ec6f740..fe13290217868 100644 --- a/src/VisualStudio/Core/Def/MoveToNamespace/MoveToNamespaceDialog.xaml.cs +++ b/src/VisualStudio/Core/Def/MoveToNamespace/MoveToNamespaceDialog.xaml.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.Windows; using System.Windows.Controls; using System.Windows.Input; diff --git a/src/VisualStudio/Core/Def/MoveToNamespace/NamespaceItem.cs b/src/VisualStudio/Core/Def/MoveToNamespace/NamespaceItem.cs index c37f845c58f9a..78bf6413b0e3a 100644 --- a/src/VisualStudio/Core/Def/MoveToNamespace/NamespaceItem.cs +++ b/src/VisualStudio/Core/Def/MoveToNamespace/NamespaceItem.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.VisualStudio.LanguageServices.Implementation.MoveToNamespace; internal class NamespaceItem diff --git a/src/VisualStudio/Core/Def/NavigateTo/RoslynSearchResultPreviewPanel.cs b/src/VisualStudio/Core/Def/NavigateTo/RoslynSearchResultPreviewPanel.cs index 0d368c51a3c4c..535834ed445cc 100644 --- a/src/VisualStudio/Core/Def/NavigateTo/RoslynSearchResultPreviewPanel.cs +++ b/src/VisualStudio/Core/Def/NavigateTo/RoslynSearchResultPreviewPanel.cs @@ -8,7 +8,6 @@ using Microsoft.VisualStudio.Search.Data; using Microsoft.VisualStudio.Search.UI.PreviewPanel.Models; using Microsoft.VisualStudio.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.NavigateTo; diff --git a/src/VisualStudio/Core/Def/NavigateTo/VisualStudioNavigateToPreviewService.cs b/src/VisualStudio/Core/Def/NavigateTo/VisualStudioNavigateToPreviewService.cs index 380e512b391be..fcec4b5135256 100644 --- a/src/VisualStudio/Core/Def/NavigateTo/VisualStudioNavigateToPreviewService.cs +++ b/src/VisualStudio/Core/Def/NavigateTo/VisualStudioNavigateToPreviewService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Implementation.NavigateTo; using Microsoft.CodeAnalysis.Navigation; diff --git a/src/VisualStudio/Core/Def/NavigateTo/VisualStudioNavigateToPreviewServiceFactory.cs b/src/VisualStudio/Core/Def/NavigateTo/VisualStudioNavigateToPreviewServiceFactory.cs index ff94e8f3e60bb..c0926b953e9e2 100644 --- a/src/VisualStudio/Core/Def/NavigateTo/VisualStudioNavigateToPreviewServiceFactory.cs +++ b/src/VisualStudio/Core/Def/NavigateTo/VisualStudioNavigateToPreviewServiceFactory.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.Composition; using Microsoft.CodeAnalysis.Editor.Implementation.NavigateTo; diff --git a/src/VisualStudio/Core/Def/NavigationBar/NavigationBarClient.cs b/src/VisualStudio/Core/Def/NavigationBar/NavigationBarClient.cs index 8597fe3e621cd..ce1819728e7cc 100644 --- a/src/VisualStudio/Core/Def/NavigationBar/NavigationBarClient.cs +++ b/src/VisualStudio/Core/Def/NavigationBar/NavigationBarClient.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Editor.Wpf; @@ -17,7 +18,6 @@ using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.TextManager.Interop; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.NavigationBar; diff --git a/src/VisualStudio/Core/Def/Options/FeatureFlagPersister.cs b/src/VisualStudio/Core/Def/Options/FeatureFlagPersister.cs index a15b51d241d7d..66621e6fd58fb 100644 --- a/src/VisualStudio/Core/Def/Options/FeatureFlagPersister.cs +++ b/src/VisualStudio/Core/Def/Options/FeatureFlagPersister.cs @@ -4,10 +4,10 @@ using System; using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Options; using Microsoft.Internal.VisualStudio.Shell.Interop; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Options; diff --git a/src/VisualStudio/Core/Def/Options/LocalUserRegistryOptionPersister.cs b/src/VisualStudio/Core/Def/Options/LocalUserRegistryOptionPersister.cs index 1e6dc3b3e4d9e..8387e52ae155a 100644 --- a/src/VisualStudio/Core/Def/Options/LocalUserRegistryOptionPersister.cs +++ b/src/VisualStudio/Core/Def/Options/LocalUserRegistryOptionPersister.cs @@ -4,10 +4,10 @@ using System; using System.Runtime.InteropServices; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.Win32; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Options; diff --git a/src/VisualStudio/Core/Def/Options/NamingPreferencesReadFallback.cs b/src/VisualStudio/Core/Def/Options/NamingPreferencesReadFallback.cs index 7fcb429cf1364..35813d7175eda 100644 --- a/src/VisualStudio/Core/Def/Options/NamingPreferencesReadFallback.cs +++ b/src/VisualStudio/Core/Def/Options/NamingPreferencesReadFallback.cs @@ -7,7 +7,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; -using Roslyn.Utilities; using Microsoft.CodeAnalysis.CodeStyle; namespace Microsoft.VisualStudio.LanguageServices.Options; diff --git a/src/VisualStudio/Core/Def/Options/VisualStudioOptionPersister.cs b/src/VisualStudio/Core/Def/Options/VisualStudioOptionPersister.cs index 4d5deb8bbcd9c..532b178e16347 100644 --- a/src/VisualStudio/Core/Def/Options/VisualStudioOptionPersister.cs +++ b/src/VisualStudio/Core/Def/Options/VisualStudioOptionPersister.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Threading.Tasks; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Options; using Roslyn.Utilities; diff --git a/src/VisualStudio/Core/Def/Options/VisualStudioOptionPersisterProvider.cs b/src/VisualStudio/Core/Def/Options/VisualStudioOptionPersisterProvider.cs index b7a78d2196971..496ddb9e0f5cf 100644 --- a/src/VisualStudio/Core/Def/Options/VisualStudioOptionPersisterProvider.cs +++ b/src/VisualStudio/Core/Def/Options/VisualStudioOptionPersisterProvider.cs @@ -8,6 +8,7 @@ using System.ComponentModel.Composition; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host.Mef; @@ -16,7 +17,6 @@ using Microsoft.VisualStudio.Settings; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Options; diff --git a/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs b/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs index b838cbd7a7fbf..3bf4c29fe1470 100644 --- a/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs +++ b/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs @@ -372,6 +372,7 @@ public bool TryFetch(LocalUserRegistryOptionPersister persister, OptionKey2 opti {"dotnet_unsupported_report_invalid_json_patterns", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.ReportInvalidJsonPatterns")}, {"visual_studio_enable_key_binding_reset", new FeatureFlagStorage("Roslyn.KeybindingResetEnabled")}, {"visual_studio_enable_semantic_search", new FeatureFlagStorage("Roslyn.SemanticSearchEnabled")}, + {"visual_studio_enable_semantic_search_prompt", new FeatureFlagStorage("Roslyn.ShowPromptInSemanticSearch")}, {"visual_studio_enable_copilot_rename_context", new FeatureFlagStorage("Roslyn.CopilotRenameGetContext")}, {"visual_studio_key_binding_needs_reset", new LocalUserProfileStorage(@"Roslyn\Internal\KeybindingsStatus", "NeedsReset")}, {"visual_studio_key_binding_reset_never_show_again", new LocalUserProfileStorage(@"Roslyn\Internal\KeybindingsStatus", "NeverShowAgain")}, diff --git a/src/VisualStudio/Core/Def/Packaging/Interop/SVsRemoteControlService.cs b/src/VisualStudio/Core/Def/Packaging/Interop/SVsRemoteControlService.cs index bd2fd0150e4ce..63e2bdff34baa 100644 --- a/src/VisualStudio/Core/Def/Packaging/Interop/SVsRemoteControlService.cs +++ b/src/VisualStudio/Core/Def/Packaging/Interop/SVsRemoteControlService.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.Runtime.InteropServices; namespace Microsoft.Internal.VisualStudio.Shell.Interop; diff --git a/src/VisualStudio/Core/Def/Packaging/PackageInstallerServiceFactory.cs b/src/VisualStudio/Core/Def/Packaging/PackageInstallerServiceFactory.cs index a602ba3b033f2..9e2c2a3b16ae2 100644 --- a/src/VisualStudio/Core/Def/Packaging/PackageInstallerServiceFactory.cs +++ b/src/VisualStudio/Core/Def/Packaging/PackageInstallerServiceFactory.cs @@ -26,6 +26,7 @@ using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.SymbolSearch; +using Microsoft.CodeAnalysis.Threading; using Microsoft.VisualStudio.Editor; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; using Microsoft.VisualStudio.LanguageServices.SymbolSearch; diff --git a/src/VisualStudio/Core/Def/PdbSourceDocument/PdbSourceDocumentOutputWindowLogger.cs b/src/VisualStudio/Core/Def/PdbSourceDocument/PdbSourceDocumentOutputWindowLogger.cs index 7a880dd52a724..9992c08ca693c 100644 --- a/src/VisualStudio/Core/Def/PdbSourceDocument/PdbSourceDocumentOutputWindowLogger.cs +++ b/src/VisualStudio/Core/Def/PdbSourceDocument/PdbSourceDocumentOutputWindowLogger.cs @@ -13,9 +13,9 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.PdbSourceDocument; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Threading; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.PdbSourceDocument; diff --git a/src/VisualStudio/Core/Def/PickMembers/PickMembersDialog.xaml b/src/VisualStudio/Core/Def/PickMembers/PickMembersDialog.xaml index 44227eb7eb4ec..bf7ef59468748 100644 --- a/src/VisualStudio/Core/Def/PickMembers/PickMembersDialog.xaml +++ b/src/VisualStudio/Core/Def/PickMembers/PickMembersDialog.xaml @@ -13,6 +13,7 @@ xmlns:imagecatalog="clr-namespace:Microsoft.VisualStudio.Imaging;assembly=Microsoft.VisualStudio.ImageCatalog" xmlns:vsshell="clr-namespace:Microsoft.VisualStudio.Shell;assembly=Microsoft.VisualStudio.Shell.15.0" xmlns:platformimaging="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Imaging" + xmlns:vsutil="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Utilities" mc:Ignorable="d" d:DesignHeight="380" d:DesignWidth="460" Height="380" Width="460" @@ -41,6 +42,7 @@ + @@ -95,9 +97,22 @@ Focusable="False" AutomationProperties.AutomationId="{Binding SymbolName}"> - + + + + + + + + + diff --git a/src/VisualStudio/Core/Def/PickMembers/PickMembersDialogViewModel.cs b/src/VisualStudio/Core/Def/PickMembers/PickMembersDialogViewModel.cs index 85a8a3558835c..b0b5cdefcbd34 100644 --- a/src/VisualStudio/Core/Def/PickMembers/PickMembersDialogViewModel.cs +++ b/src/VisualStudio/Core/Def/PickMembers/PickMembersDialogViewModel.cs @@ -12,7 +12,6 @@ using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; using Microsoft.VisualStudio.LanguageServices.Utilities; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.PickMembers; diff --git a/src/VisualStudio/Core/Def/Preview/ChangeList.cs b/src/VisualStudio/Core/Def/Preview/ChangeList.cs index 9ff78414a30cb..34d06f9f4a56b 100644 --- a/src/VisualStudio/Core/Def/Preview/ChangeList.cs +++ b/src/VisualStudio/Core/Def/Preview/ChangeList.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.VisualStudio.Shell.Interop; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Preview; diff --git a/src/VisualStudio/Core/Def/Preview/FileChange.cs b/src/VisualStudio/Core/Def/Preview/FileChange.cs index dd71eeab868a5..0a38e6c0e32ec 100644 --- a/src/VisualStudio/Core/Def/Preview/FileChange.cs +++ b/src/VisualStudio/Core/Def/Preview/FileChange.cs @@ -20,7 +20,6 @@ using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Differencing; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Preview; diff --git a/src/VisualStudio/Core/Def/Preview/PreviewService.cs b/src/VisualStudio/Core/Def/Preview/PreviewService.cs index 9a83d65e10c4b..d4d20ef8a6b97 100644 --- a/src/VisualStudio/Core/Def/Preview/PreviewService.cs +++ b/src/VisualStudio/Core/Def/Preview/PreviewService.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.Composition; using Microsoft.CodeAnalysis; diff --git a/src/VisualStudio/Core/Def/Preview/PreviewUpdater.PreviewDialogWorkspace.cs b/src/VisualStudio/Core/Def/Preview/PreviewUpdater.PreviewDialogWorkspace.cs index 4a168dfe7d816..e7a18aa7f34f0 100644 --- a/src/VisualStudio/Core/Def/Preview/PreviewUpdater.PreviewDialogWorkspace.cs +++ b/src/VisualStudio/Core/Def/Preview/PreviewUpdater.PreviewDialogWorkspace.cs @@ -2,14 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Shared.Preview; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Preview; diff --git a/src/VisualStudio/Core/Def/Preview/PreviewUpdater.cs b/src/VisualStudio/Core/Def/Preview/PreviewUpdater.cs index f80dc8360174a..99244c6d979db 100644 --- a/src/VisualStudio/Core/Def/Preview/PreviewUpdater.cs +++ b/src/VisualStudio/Core/Def/Preview/PreviewUpdater.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Preview; diff --git a/src/VisualStudio/Core/Def/Preview/ReferenceChange.AnalyzerReferenceChange.cs b/src/VisualStudio/Core/Def/Preview/ReferenceChange.AnalyzerReferenceChange.cs index 7bba3480ef1ed..c0b6fd7060341 100644 --- a/src/VisualStudio/Core/Def/Preview/ReferenceChange.AnalyzerReferenceChange.cs +++ b/src/VisualStudio/Core/Def/Preview/ReferenceChange.AnalyzerReferenceChange.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; diff --git a/src/VisualStudio/Core/Def/Preview/ReferenceChange.MetadataReferenceChange.cs b/src/VisualStudio/Core/Def/Preview/ReferenceChange.MetadataReferenceChange.cs index a087d716425ca..9e1217ac713b2 100644 --- a/src/VisualStudio/Core/Def/Preview/ReferenceChange.MetadataReferenceChange.cs +++ b/src/VisualStudio/Core/Def/Preview/ReferenceChange.MetadataReferenceChange.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Preview; diff --git a/src/VisualStudio/Core/Def/Preview/ReferenceChange.ProjectReferenceChange.cs b/src/VisualStudio/Core/Def/Preview/ReferenceChange.ProjectReferenceChange.cs index a21932897ee7a..0f0bd433282fd 100644 --- a/src/VisualStudio/Core/Def/Preview/ReferenceChange.ProjectReferenceChange.cs +++ b/src/VisualStudio/Core/Def/Preview/ReferenceChange.ProjectReferenceChange.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Preview; diff --git a/src/VisualStudio/Core/Def/Preview/SpanChange.cs b/src/VisualStudio/Core/Def/Preview/SpanChange.cs index af8464069f414..7930ef5276571 100644 --- a/src/VisualStudio/Core/Def/Preview/SpanChange.cs +++ b/src/VisualStudio/Core/Def/Preview/SpanChange.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Shell.Interop; diff --git a/src/VisualStudio/Core/Def/PreviewPane/PreviewPane.xaml.cs b/src/VisualStudio/Core/Def/PreviewPane/PreviewPane.xaml.cs index 764c706bcb21e..d0fbc450c5737 100644 --- a/src/VisualStudio/Core/Def/PreviewPane/PreviewPane.xaml.cs +++ b/src/VisualStudio/Core/Def/PreviewPane/PreviewPane.xaml.cs @@ -12,6 +12,7 @@ using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Navigation; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics.Log; using Microsoft.CodeAnalysis.Editor.Implementation.Preview; using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; diff --git a/src/VisualStudio/Core/Def/Progression/GraphNodeCreation.cs b/src/VisualStudio/Core/Def/Progression/GraphNodeCreation.cs index 75c528fd1ae66..7cbae5050f676 100644 --- a/src/VisualStudio/Core/Def/Progression/GraphNodeCreation.cs +++ b/src/VisualStudio/Core/Def/Progression/GraphNodeCreation.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Threading; using System.Threading.Tasks; diff --git a/src/VisualStudio/Core/Def/Progression/GraphQueries/ContainsChildrenGraphQuery.cs b/src/VisualStudio/Core/Def/Progression/GraphQueries/ContainsChildrenGraphQuery.cs index a6c6ab945d3ce..c116f6dcab525 100644 --- a/src/VisualStudio/Core/Def/Progression/GraphQueries/ContainsChildrenGraphQuery.cs +++ b/src/VisualStudio/Core/Def/Progression/GraphQueries/ContainsChildrenGraphQuery.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.Linq; using System.Threading; diff --git a/src/VisualStudio/Core/Def/Progression/GraphQueries/ContainsGraphQuery.cs b/src/VisualStudio/Core/Def/Progression/GraphQueries/ContainsGraphQuery.cs index 99ab25eac7c93..f115c3fc5e78f 100644 --- a/src/VisualStudio/Core/Def/Progression/GraphQueries/ContainsGraphQuery.cs +++ b/src/VisualStudio/Core/Def/Progression/GraphQueries/ContainsGraphQuery.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.Threading; using System.Threading.Tasks; diff --git a/src/VisualStudio/Core/Def/Progression/GraphQueries/ImplementedByGraphQuery.cs b/src/VisualStudio/Core/Def/Progression/GraphQueries/ImplementedByGraphQuery.cs index e654af1ef0fde..d6b6967233b7b 100644 --- a/src/VisualStudio/Core/Def/Progression/GraphQueries/ImplementedByGraphQuery.cs +++ b/src/VisualStudio/Core/Def/Progression/GraphQueries/ImplementedByGraphQuery.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; diff --git a/src/VisualStudio/Core/Def/Progression/GraphQueries/ImplementsGraphQuery.cs b/src/VisualStudio/Core/Def/Progression/GraphQueries/ImplementsGraphQuery.cs index 764bfc848b9c8..d165a54688759 100644 --- a/src/VisualStudio/Core/Def/Progression/GraphQueries/ImplementsGraphQuery.cs +++ b/src/VisualStudio/Core/Def/Progression/GraphQueries/ImplementsGraphQuery.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; diff --git a/src/VisualStudio/Core/Def/Progression/GraphQueries/InheritedByGraphQuery.cs b/src/VisualStudio/Core/Def/Progression/GraphQueries/InheritedByGraphQuery.cs index 8975ebbfe0215..d934a4ff21587 100644 --- a/src/VisualStudio/Core/Def/Progression/GraphQueries/InheritedByGraphQuery.cs +++ b/src/VisualStudio/Core/Def/Progression/GraphQueries/InheritedByGraphQuery.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Linq; using System.Threading; using System.Threading.Tasks; diff --git a/src/VisualStudio/Core/Def/Progression/GraphQueries/InheritsGraphQuery.cs b/src/VisualStudio/Core/Def/Progression/GraphQueries/InheritsGraphQuery.cs index ba7ec18af0d01..701e3ff4a2205 100644 --- a/src/VisualStudio/Core/Def/Progression/GraphQueries/InheritsGraphQuery.cs +++ b/src/VisualStudio/Core/Def/Progression/GraphQueries/InheritsGraphQuery.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.Linq; using System.Threading; diff --git a/src/VisualStudio/Core/Def/Progression/GraphQueries/IsCalledByGraphQuery.cs b/src/VisualStudio/Core/Def/Progression/GraphQueries/IsCalledByGraphQuery.cs index 7cb8ddb0f210b..837cc7c5a6e24 100644 --- a/src/VisualStudio/Core/Def/Progression/GraphQueries/IsCalledByGraphQuery.cs +++ b/src/VisualStudio/Core/Def/Progression/GraphQueries/IsCalledByGraphQuery.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Linq; using System.Threading; using System.Threading.Tasks; diff --git a/src/VisualStudio/Core/Def/Progression/GraphQueries/OverriddenByGraphQuery.cs b/src/VisualStudio/Core/Def/Progression/GraphQueries/OverriddenByGraphQuery.cs index 6790c969280ba..194e01b011904 100644 --- a/src/VisualStudio/Core/Def/Progression/GraphQueries/OverriddenByGraphQuery.cs +++ b/src/VisualStudio/Core/Def/Progression/GraphQueries/OverriddenByGraphQuery.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; diff --git a/src/VisualStudio/Core/Def/Progression/GraphQueries/OverridesGraphQuery.cs b/src/VisualStudio/Core/Def/Progression/GraphQueries/OverridesGraphQuery.cs index c968fb96c39ee..668e8915ba742 100644 --- a/src/VisualStudio/Core/Def/Progression/GraphQueries/OverridesGraphQuery.cs +++ b/src/VisualStudio/Core/Def/Progression/GraphQueries/OverridesGraphQuery.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; diff --git a/src/VisualStudio/Core/Def/Progression/GraphQueryManager.cs b/src/VisualStudio/Core/Def/Progression/GraphQueryManager.cs index 034074da3a89b..d9bcc816f68cf 100644 --- a/src/VisualStudio/Core/Def/Progression/GraphQueryManager.cs +++ b/src/VisualStudio/Core/Def/Progression/GraphQueryManager.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Threading; using Microsoft.VisualStudio.GraphModel; using Roslyn.Utilities; diff --git a/src/VisualStudio/Core/Def/Progression/IGraphQuery.cs b/src/VisualStudio/Core/Def/Progression/IGraphQuery.cs index cd4e71800219b..c5a9cf73b70d6 100644 --- a/src/VisualStudio/Core/Def/Progression/IGraphQuery.cs +++ b/src/VisualStudio/Core/Def/Progression/IGraphQuery.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; diff --git a/src/VisualStudio/Core/Def/Progression/IProgressionLanguageService.cs b/src/VisualStudio/Core/Def/Progression/IProgressionLanguageService.cs index 2fab33e49ce9f..1b548f7e86877 100644 --- a/src/VisualStudio/Core/Def/Progression/IProgressionLanguageService.cs +++ b/src/VisualStudio/Core/Def/Progression/IProgressionLanguageService.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.Threading; using Microsoft.CodeAnalysis; diff --git a/src/VisualStudio/Core/Def/Progression/IconHelper.cs b/src/VisualStudio/Core/Def/Progression/IconHelper.cs index 1ce8ab9a5528e..102705aa3875a 100644 --- a/src/VisualStudio/Core/Def/Progression/IconHelper.cs +++ b/src/VisualStudio/Core/Def/Progression/IconHelper.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using Microsoft.CodeAnalysis; diff --git a/src/VisualStudio/Core/Def/Progression/RoslynGraphCategories.cs b/src/VisualStudio/Core/Def/Progression/RoslynGraphCategories.cs index d723ac45f6f70..040f6671f1af3 100644 --- a/src/VisualStudio/Core/Def/Progression/RoslynGraphCategories.cs +++ b/src/VisualStudio/Core/Def/Progression/RoslynGraphCategories.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.VisualStudio.GraphModel; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Progression; diff --git a/src/VisualStudio/Core/Def/Progression/RoslynGraphProperties.cs b/src/VisualStudio/Core/Def/Progression/RoslynGraphProperties.cs index 87a47f5645376..4cdf37c577932 100644 --- a/src/VisualStudio/Core/Def/Progression/RoslynGraphProperties.cs +++ b/src/VisualStudio/Core/Def/Progression/RoslynGraphProperties.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 Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editing; diff --git a/src/VisualStudio/Core/Def/ProjectSystem/CPS/ICodeModelFactory.cs b/src/VisualStudio/Core/Def/ProjectSystem/CPS/ICodeModelFactory.cs index e87bb9c48000b..e6c24df439abc 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/CPS/ICodeModelFactory.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/CPS/ICodeModelFactory.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.VisualStudio.LanguageServices.ProjectSystem; /// diff --git a/src/VisualStudio/Core/Def/ProjectSystem/CPS/ITempPECompiler.cs b/src/VisualStudio/Core/Def/ProjectSystem/CPS/ITempPECompiler.cs index 220f54a9d31b4..193b8b1ab777f 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/CPS/ITempPECompiler.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/CPS/ITempPECompiler.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.Threading; using System.Threading.Tasks; diff --git a/src/VisualStudio/Core/Def/ProjectSystem/Extensions/ServiceProviderExtensions.cs b/src/VisualStudio/Core/Def/ProjectSystem/Extensions/ServiceProviderExtensions.cs index 40fb70e7289d4..3889c8391661d 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/Extensions/ServiceProviderExtensions.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/Extensions/ServiceProviderExtensions.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.VisualStudio.ComponentModelHost; diff --git a/src/VisualStudio/Core/Def/ProjectSystem/FileChangeTracker.cs b/src/VisualStudio/Core/Def/ProjectSystem/FileChangeTracker.cs index 34db1dfbb8256..ad0eaf96c4078 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/FileChangeTracker.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/FileChangeTracker.cs @@ -13,6 +13,7 @@ using IVsAsyncFileChangeEx2 = Microsoft.VisualStudio.Shell.IVsAsyncFileChangeEx2; using Microsoft.VisualStudio.Shell.Interop; using Roslyn.Utilities; +using Microsoft.CodeAnalysis; namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; diff --git a/src/VisualStudio/Core/Def/ProjectSystem/FileChangeWatcher.cs b/src/VisualStudio/Core/Def/ProjectSystem/FileChangeWatcher.cs index c4c5124e4bf76..d25c1736e9826 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/FileChangeWatcher.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/FileChangeWatcher.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.ProjectSystem; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Threading; using Microsoft.VisualStudio.Shell.Interop; using Roslyn.Utilities; using IVsAsyncFileChangeEx2 = Microsoft.VisualStudio.Shell.IVsAsyncFileChangeEx2; diff --git a/src/VisualStudio/Core/Def/ProjectSystem/Interop/IAnalyzerConfigFileHost.cs b/src/VisualStudio/Core/Def/ProjectSystem/Interop/IAnalyzerConfigFileHost.cs index cdaf44443a703..bdcd176f224c1 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/Interop/IAnalyzerConfigFileHost.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/Interop/IAnalyzerConfigFileHost.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.Runtime.InteropServices; diff --git a/src/VisualStudio/Core/Def/ProjectSystem/Interop/IAnalyzerHost.cs b/src/VisualStudio/Core/Def/ProjectSystem/Interop/IAnalyzerHost.cs index d4c9a366d34bb..13775754f18b8 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/Interop/IAnalyzerHost.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/Interop/IAnalyzerHost.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.Runtime.InteropServices; diff --git a/src/VisualStudio/Core/Def/ProjectSystem/Interop/ICompilerOptionsHostObject.cs b/src/VisualStudio/Core/Def/ProjectSystem/Interop/ICompilerOptionsHostObject.cs index 0087a7b12744f..ba6d0f49fa0e1 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/Interop/ICompilerOptionsHostObject.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/Interop/ICompilerOptionsHostObject.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.Runtime.InteropServices; diff --git a/src/VisualStudio/Core/Def/ProjectSystem/Interop/IIntPtrReturningVsInvisibleEditorManager.cs b/src/VisualStudio/Core/Def/ProjectSystem/Interop/IIntPtrReturningVsInvisibleEditorManager.cs index c68c19ea147fc..769f6ce0d2b43 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/Interop/IIntPtrReturningVsInvisibleEditorManager.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/Interop/IIntPtrReturningVsInvisibleEditorManager.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.Runtime.InteropServices; using Microsoft.VisualStudio.Shell.Interop; @@ -24,8 +22,8 @@ internal interface IIntPtrReturningVsInvisibleEditorManager { int RegisterInvisibleEditor( [MarshalAs(UnmanagedType.LPWStr)] string pszMkDocument, - IVsProject pProject, + IVsProject? pProject, uint dwFlags, - IVsSimpleDocFactory pFactory, + IVsSimpleDocFactory? pFactory, out IntPtr ppEditor); } diff --git a/src/VisualStudio/Core/Def/ProjectSystem/Interop/IIntellisenseBuildTarget.cs b/src/VisualStudio/Core/Def/ProjectSystem/Interop/IIntellisenseBuildTarget.cs index 45bdafca27a95..e594cc3161ff6 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/Interop/IIntellisenseBuildTarget.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/Interop/IIntellisenseBuildTarget.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.Runtime.InteropServices; diff --git a/src/VisualStudio/Core/Def/ProjectSystem/Interop/IProjectSiteEx.cs b/src/VisualStudio/Core/Def/ProjectSystem/Interop/IProjectSiteEx.cs index 01cd5c23e68a2..37bf1ebf9761e 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/Interop/IProjectSiteEx.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/Interop/IProjectSiteEx.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.Runtime.InteropServices; diff --git a/src/VisualStudio/Core/Def/ProjectSystem/Interop/IVsUndoState.cs b/src/VisualStudio/Core/Def/ProjectSystem/Interop/IVsUndoState.cs index ed9778fbb1c33..439453020f7bb 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/Interop/IVsUndoState.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/Interop/IVsUndoState.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.Runtime.CompilerServices; using System.Runtime.InteropServices; diff --git a/src/VisualStudio/Core/Def/ProjectSystem/InvisibleEditor.cs b/src/VisualStudio/Core/Def/ProjectSystem/InvisibleEditor.cs index 4a7e5a4639726..34a7c77ccc94a 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/InvisibleEditor.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/InvisibleEditor.cs @@ -5,6 +5,7 @@ using System; using System.Diagnostics; using System.Runtime.InteropServices; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ErrorReporting; @@ -14,7 +15,6 @@ using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.TextManager.Interop; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; diff --git a/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IAnalyzerConfigFileHost.cs b/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IAnalyzerConfigFileHost.cs index 49988ad22e182..882407eba9c5c 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IAnalyzerConfigFileHost.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IAnalyzerConfigFileHost.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.Interop; namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.Legacy; diff --git a/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_ICompilerOptionsHostObject.cs b/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_ICompilerOptionsHostObject.cs index 72b60e461378a..ee9f01b9b79a9 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_ICompilerOptionsHostObject.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_ICompilerOptionsHostObject.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.Interop; namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.Legacy; diff --git a/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IProjectSiteEx.cs b/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IProjectSiteEx.cs index f9fd883426a46..4972be79f793d 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IProjectSiteEx.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IProjectSiteEx.cs @@ -2,14 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Generic; using System.Runtime.InteropServices; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.Interop; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.Legacy; diff --git a/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IVsHierarchyEvents.cs b/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IVsHierarchyEvents.cs index 222b0a138c4bf..b585dd10e0da9 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IVsHierarchyEvents.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IVsHierarchyEvents.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.Diagnostics; using System.IO; diff --git a/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IVsReportExternalErrors.cs b/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IVsReportExternalErrors.cs index 714db3be20600..7c80eb5c5e185 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IVsReportExternalErrors.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IVsReportExternalErrors.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.Runtime.InteropServices; using Microsoft.VisualStudio.LanguageServices.Implementation.TaskList; using Microsoft.VisualStudio.Shell.Interop; diff --git a/src/VisualStudio/Core/Def/ProjectSystem/Legacy/SolutionEventsBatchScopeCreator.cs b/src/VisualStudio/Core/Def/ProjectSystem/Legacy/SolutionEventsBatchScopeCreator.cs index 9a78bcbae6dbf..f9bdeda04ad80 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/Legacy/SolutionEventsBatchScopeCreator.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/Legacy/SolutionEventsBatchScopeCreator.cs @@ -2,12 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.ComponentModel.Composition; using System.Linq; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; diff --git a/src/VisualStudio/Core/Def/ProjectSystem/MiscellaneousFilesWorkspace.cs b/src/VisualStudio/Core/Def/ProjectSystem/MiscellaneousFilesWorkspace.cs index dff438e9f3d47..81b34d0a5b3f7 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/MiscellaneousFilesWorkspace.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/MiscellaneousFilesWorkspace.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -48,11 +46,11 @@ internal sealed partial class MiscellaneousFilesWorkspace : Workspace, IOpenText /// The mapping of all monikers in the RDT and the of the project and of the open /// file we have created for that open buffer. An entry should only be in here if it's also already in . /// - private readonly Dictionary _monikersToProjectIdAndContainer = new Dictionary(); + private readonly Dictionary _monikersToProjectIdAndContainer = []; private readonly ImmutableArray _metadataReferences; - private IVsTextManager _textManager; + private IVsTextManager? _textManager; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] @@ -80,7 +78,7 @@ public async Task InitializeAsync() _textManager = await _textManagerService.GetValueAsync().ConfigureAwait(false); } - void IOpenTextBufferEventListener.OnOpenDocument(string moniker, ITextBuffer textBuffer, IVsHierarchy _) => TrackOpenedDocument(moniker, textBuffer); + void IOpenTextBufferEventListener.OnOpenDocument(string moniker, ITextBuffer textBuffer, IVsHierarchy? _) => TrackOpenedDocument(moniker, textBuffer); void IOpenTextBufferEventListener.OnCloseDocument(string moniker) => TryUntrackClosingDocument(moniker); @@ -116,11 +114,11 @@ void IOpenTextBufferEventListener.OnSaveDocument(string moniker) { } public void RegisterLanguage(Guid languageGuid, string languageName, string scriptExtension) => _languageInformationByLanguageGuid.Add(languageGuid, new LanguageInformation(languageName, scriptExtension)); - private LanguageInformation TryGetLanguageInformation(string filename) + private LanguageInformation? TryGetLanguageInformation(string filename) { - LanguageInformation languageInformation = null; + LanguageInformation? languageInformation = null; - if (ErrorHandler.Succeeded(_textManager.MapFilenameToLanguageSID(filename, out var fileLanguageGuid))) + if (_textManager != null && ErrorHandler.Succeeded(_textManager.MapFilenameToLanguageSID(filename, out var fileLanguageGuid))) { _languageInformationByLanguageGuid.TryGetValue(fileLanguageGuid, out languageInformation); } @@ -133,6 +131,9 @@ private IEnumerable CreateMetadataReferences() var manager = this.Services.GetService(); var searchPaths = VisualStudioMetadataReferenceManager.GetReferencePaths(); + if (manager == null) + return []; + return from fileName in new[] { "mscorlib.dll", "System.dll", "System.Core.dll" } let fullPath = FileUtilities.ResolveRelativePath(fileName, basePath: null, baseDirectory: null, searchPaths: searchPaths, fileExists: File.Exists) where fullPath != null diff --git a/src/VisualStudio/Core/Def/ProjectSystem/RuleSets/VisualStudioRuleSetManager.cs b/src/VisualStudio/Core/Def/ProjectSystem/RuleSets/VisualStudioRuleSetManager.cs index 9489914f731b3..3838497b1f843 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/RuleSets/VisualStudioRuleSetManager.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/RuleSets/VisualStudioRuleSetManager.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ProjectSystem; using Microsoft.CodeAnalysis.Shared.TestHooks; diff --git a/src/VisualStudio/Core/Def/ProjectSystem/ViewEventArgs.cs b/src/VisualStudio/Core/Def/ProjectSystem/ViewEventArgs.cs index f78229e628bd7..6bf2797710567 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/ViewEventArgs.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/ViewEventArgs.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.VisualStudio.TextManager.Interop; diff --git a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProjectFactory.cs b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProjectFactory.cs index 620d493be4cef..92da315daac29 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProjectFactory.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProjectFactory.cs @@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Workspaces.AnalyzerRedirecting; using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; using Microsoft.VisualStudio.LanguageServices.ExternalAccess.VSTypeScript.Api; using Microsoft.VisualStudio.LanguageServices.Implementation.Diagnostics; @@ -33,6 +34,7 @@ internal sealed class VisualStudioProjectFactory : IVsTypeScriptVisualStudioProj private readonly VisualStudioWorkspaceImpl _visualStudioWorkspaceImpl; private readonly ImmutableArray> _dynamicFileInfoProviders; private readonly IVisualStudioDiagnosticAnalyzerProviderFactory _vsixAnalyzerProviderFactory; + private readonly ImmutableArray _analyzerAssemblyRedirectors; private readonly IVsService _solution2; [ImportingConstructor] @@ -42,12 +44,14 @@ public VisualStudioProjectFactory( VisualStudioWorkspaceImpl visualStudioWorkspaceImpl, [ImportMany] IEnumerable> fileInfoProviders, IVisualStudioDiagnosticAnalyzerProviderFactory vsixAnalyzerProviderFactory, + [ImportMany] IEnumerable analyzerAssemblyRedirectors, IVsService solution2) { _threadingContext = threadingContext; _visualStudioWorkspaceImpl = visualStudioWorkspaceImpl; _dynamicFileInfoProviders = fileInfoProviders.AsImmutableOrEmpty(); _vsixAnalyzerProviderFactory = vsixAnalyzerProviderFactory; + _analyzerAssemblyRedirectors = analyzerAssemblyRedirectors.AsImmutableOrEmpty(); _solution2 = solution2; } @@ -93,7 +97,7 @@ public async Task CreateAndAddToWorkspaceAsync( _visualStudioWorkspaceImpl.ProjectSystemProjectFactory.SolutionPath = solutionFilePath; _visualStudioWorkspaceImpl.ProjectSystemProjectFactory.SolutionTelemetryId = GetSolutionSessionId(); - var hostInfo = new ProjectSystemHostInfo(_dynamicFileInfoProviders, vsixAnalyzerProvider); + var hostInfo = new ProjectSystemHostInfo(_dynamicFileInfoProviders, vsixAnalyzerProvider, _analyzerAssemblyRedirectors); 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/VisualStudioProjectManagementService.cs b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProjectManagementService.cs index 20f674aa70bab..99028232e90c0 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProjectManagementService.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProjectManagementService.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.Composition; diff --git a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.cs b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.cs index fe498f5cf0ee2..407464b3ea61e 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.cs @@ -22,7 +22,6 @@ using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.ProjectSystem; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -31,7 +30,6 @@ using Microsoft.CodeAnalysis.Telemetry; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; -using Microsoft.ServiceHub.Framework; using Microsoft.VisualStudio.ComponentModelHost; using Microsoft.VisualStudio.Composition; using Microsoft.VisualStudio.Editor; @@ -43,7 +41,6 @@ using Microsoft.VisualStudio.LanguageServices.Utilities; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudio.Shell.ServiceBroker; using Microsoft.VisualStudio.Telemetry; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Projection; @@ -305,7 +302,7 @@ public override EnvDTE.FileCodeModel GetFileCodeModel(DocumentId documentId) } else { - return _projectCodeModelFactory.Value.GetOrCreateFileCodeModel(documentId.ProjectId, document.FilePath); + return _projectCodeModelFactory.Value.GetOrCreateFileCodeModel(documentId.ProjectId, document.FilePath!); } } @@ -493,7 +490,7 @@ protected override void ApplyCompilationOptionsChanged(ProjectId projectId, Comp var originalProject = CurrentSolution.GetRequiredProject(projectId); var compilationOptionsService = originalProject.Services.GetRequiredService(); - var storage = ProjectPropertyStorage.Create(TryGetDTEProject(projectId), ServiceProvider.GlobalProvider); + var storage = ProjectPropertyStorage.Create(TryGetDTEProject(projectId)!, ServiceProvider.GlobalProvider); compilationOptionsService.Apply(originalProject.CompilationOptions!, options, storage); } @@ -510,7 +507,7 @@ protected override void ApplyParseOptionsChanged(ProjectId projectId, ParseOptio } var parseOptionsService = CurrentSolution.GetRequiredProject(projectId).Services.GetRequiredService(); - var storage = ProjectPropertyStorage.Create(TryGetDTEProject(projectId), ServiceProvider.GlobalProvider); + var storage = ProjectPropertyStorage.Create(TryGetDTEProject(projectId)!, ServiceProvider.GlobalProvider); parseOptionsService.Apply(options, storage); } diff --git a/src/VisualStudio/Core/Def/PullMemberUp/MainDialog/PullMemberUpDialog.xaml b/src/VisualStudio/Core/Def/PullMemberUp/MainDialog/PullMemberUpDialog.xaml index ab76938f5d0d4..f9aa2cc24ca60 100644 --- a/src/VisualStudio/Core/Def/PullMemberUp/MainDialog/PullMemberUpDialog.xaml +++ b/src/VisualStudio/Core/Def/PullMemberUp/MainDialog/PullMemberUpDialog.xaml @@ -3,8 +3,10 @@ x:Name="dialog" x:Class="Microsoft.VisualStudio.LanguageServices.Implementation.PullMemberUp.MainDialog.PullMemberUpDialog" x:ClassModifier="internal" + xmlns:platformimaging="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Imaging" xmlns:vs="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.15.0" xmlns:vsshell="clr-namespace:Microsoft.VisualStudio.Shell;assembly=Microsoft.VisualStudio.Shell.15.0" + xmlns:vsutil="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Utilities" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" @@ -21,7 +23,8 @@ ShowInTaskbar="False" ResizeMode="CanResizeWithGrip" Title="{Binding ElementName=dialog, Path=PullMembersUpTitle}" - Background="{DynamicResource {x:Static vs:ThemedDialogColors.WindowPanelBrushKey}}"> + Background="{DynamicResource {x:Static vs:ThemedDialogColors.WindowPanelBrushKey}}" + platformimaging:ImageThemingUtilities.ImageBackgroundColor="{StaticResource {x:Static vsshell:VsColors.ToolWindowBackgroundKey}}"> @@ -48,6 +51,7 @@ + @@ -90,7 +94,21 @@ HorizontalAlignment="Stretch" Focusable="False" VerticalAlignment="Stretch"> - + + + + + + + + + , IEventListenerStoppable + IAsynchronousOperationListenerProvider listenerProvider) : IEventListener { private readonly IAsynchronousOperationListenerProvider _listenerProvider = listenerProvider; private readonly CancellationTokenSource _disposalCancellationSource = new(); @@ -30,7 +30,7 @@ internal sealed class VisualStudioWorkspaceServiceHubConnector( private Task? _remoteClientInitializationTask; private SolutionChecksumUpdater? _checksumUpdater; - public void StartListening(Workspace workspace, object serviceOpt) + public void StartListening(Workspace workspace) { if (workspace is not VisualStudioWorkspace) { diff --git a/src/VisualStudio/Core/Def/RoslynActivityLogger.cs b/src/VisualStudio/Core/Def/RoslynActivityLogger.cs index c8aa1ca25a30f..cdf5d6d629753 100644 --- a/src/VisualStudio/Core/Def/RoslynActivityLogger.cs +++ b/src/VisualStudio/Core/Def/RoslynActivityLogger.cs @@ -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. -#nullable disable - using System.Diagnostics; using System.Threading; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Internal.Log; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices; diff --git a/src/VisualStudio/Core/Def/RoslynPackage.cs b/src/VisualStudio/Core/Def/RoslynPackage.cs index d0980fe34b761..9742018a5ac9a 100644 --- a/src/VisualStudio/Core/Def/RoslynPackage.cs +++ b/src/VisualStudio/Core/Def/RoslynPackage.cs @@ -9,6 +9,7 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.ColorSchemes; using Microsoft.CodeAnalysis.Common; using Microsoft.CodeAnalysis.EditAndContinue; @@ -59,11 +60,11 @@ internal sealed class RoslynPackage : AbstractPackage private const string BackgroundAnalysisScopeOptionKey = "AnalysisScope-DCE33A29A768"; private const byte BackgroundAnalysisScopeOptionVersion = 1; - private static RoslynPackage? _lazyInstance; + private static RoslynPackage? s_lazyInstance; private RuleSetEventHandler? _ruleSetEventHandler; private ColorSchemeApplier? _colorSchemeApplier; - private IDisposable? _solutionEventMonitor; + private SolutionEventMonitor? _solutionEventMonitor; private BackgroundAnalysisScope? _analysisScope; @@ -94,7 +95,7 @@ public BackgroundAnalysisScope? AnalysisScope internal static async ValueTask GetOrLoadAsync(IThreadingContext threadingContext, IAsyncServiceProvider serviceProvider, CancellationToken cancellationToken) { - if (_lazyInstance is null) + if (s_lazyInstance is null) { await threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); @@ -104,11 +105,11 @@ public BackgroundAnalysisScope? AnalysisScope if (ErrorHandler.Succeeded(((IVsShell)shell).IsPackageLoaded(typeof(RoslynPackage).GUID, out var package))) { - _lazyInstance = (RoslynPackage)package; + s_lazyInstance = (RoslynPackage)package; } } - return _lazyInstance; + return s_lazyInstance; } protected override void OnLoadOptions(string key, Stream stream) diff --git a/src/VisualStudio/Core/Def/SemanticSearch/ISemanticSearchCopilotUIProvider.cs b/src/VisualStudio/Core/Def/SemanticSearch/ISemanticSearchCopilotUIProvider.cs new file mode 100644 index 0000000000000..2c29f61682813 --- /dev/null +++ b/src/VisualStudio/Core/Def/SemanticSearch/ISemanticSearchCopilotUIProvider.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.Windows.Controls; +using Microsoft.VisualStudio.OLE.Interop; +using Microsoft.VisualStudio.Text.Editor; + +namespace Microsoft.CodeAnalysis.SemanticSearch; + +/// +/// Abstraction over Copilot prompt text box UI. +/// +internal interface ITextBoxControl +{ + Control Control { get; } + string Text { get; set; } + IOleCommandTarget CommandTarget { get; } + IWpfTextView View { get; } +} + +/// +/// Abstraction over Copilot prompt UI. +/// +internal interface ISemanticSearchCopilotUIProvider +{ + bool IsAvailable { get; } + ITextBoxControl GetTextBox(); +} diff --git a/src/VisualStudio/Core/Def/SemanticSearch/SemanticSearchFeatureFlag.cs b/src/VisualStudio/Core/Def/SemanticSearch/SemanticSearchFeatureFlag.cs index 4b5e4cadb7d7d..caf12828d2004 100644 --- a/src/VisualStudio/Core/Def/SemanticSearch/SemanticSearchFeatureFlag.cs +++ b/src/VisualStudio/Core/Def/SemanticSearch/SemanticSearchFeatureFlag.cs @@ -9,6 +9,7 @@ namespace Microsoft.VisualStudio.LanguageServices; internal static class SemanticSearchFeatureFlag { public static readonly Option2 Enabled = new("visual_studio_enable_semantic_search", defaultValue: false); + public static readonly Option2 PromptEnabled = new("visual_studio_enable_semantic_search_prompt", defaultValue: false); /// /// Context id that indicates that Semantic Search feature is enabled. diff --git a/src/VisualStudio/Core/Def/Shared/LogicalStringComparer.cs b/src/VisualStudio/Core/Def/Shared/LogicalStringComparer.cs index 2573efd699996..735e72a1800db 100644 --- a/src/VisualStudio/Core/Def/Shared/LogicalStringComparer.cs +++ b/src/VisualStudio/Core/Def/Shared/LogicalStringComparer.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.Runtime.InteropServices; diff --git a/src/VisualStudio/Core/Def/Shared/VisualStudioImageIdService.cs b/src/VisualStudio/Core/Def/Shared/VisualStudioImageIdService.cs index 93e8e460d6340..3150255b82c79 100644 --- a/src/VisualStudio/Core/Def/Shared/VisualStudioImageIdService.cs +++ b/src/VisualStudio/Core/Def/Shared/VisualStudioImageIdService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.Immutable; diff --git a/src/VisualStudio/Core/Def/Snippets/AbstractSnippetInfoService.cs b/src/VisualStudio/Core/Def/Snippets/AbstractSnippetInfoService.cs index e27406337e8d3..2ac13d3aa2c81 100644 --- a/src/VisualStudio/Core/Def/Snippets/AbstractSnippetInfoService.cs +++ b/src/VisualStudio/Core/Def/Snippets/AbstractSnippetInfoService.cs @@ -94,7 +94,7 @@ public IEnumerable GetSnippetsIfAvailable() } } - public bool SnippetShortcutExists_NonBlocking(string shortcut) + public bool SnippetShortcutExists_NonBlocking(string? shortcut) { if (shortcut == null) { diff --git a/src/VisualStudio/Core/Def/Snippets/IVsContainedLanguageHostInternal.cs b/src/VisualStudio/Core/Def/Snippets/IVsContainedLanguageHostInternal.cs index c4f6d4e787a46..4a3a1f6ef1f85 100644 --- a/src/VisualStudio/Core/Def/Snippets/IVsContainedLanguageHostInternal.cs +++ b/src/VisualStudio/Core/Def/Snippets/IVsContainedLanguageHostInternal.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.Runtime.InteropServices; diff --git a/src/VisualStudio/Core/Def/Snippets/IVsExpansionSessionInternal.cs b/src/VisualStudio/Core/Def/Snippets/IVsExpansionSessionInternal.cs index c4319f83f5d7c..d1908ba191a23 100644 --- a/src/VisualStudio/Core/Def/Snippets/IVsExpansionSessionInternal.cs +++ b/src/VisualStudio/Core/Def/Snippets/IVsExpansionSessionInternal.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.Runtime.InteropServices; @@ -32,7 +30,7 @@ internal interface IVsExpansionSessionInternal /// before leaving the calling method. /// [PreserveSig] - int GetSnippetNode([MarshalAs(UnmanagedType.BStr)] string bstrNode, out IntPtr pNode); + int GetSnippetNode([MarshalAs(UnmanagedType.BStr)] string? bstrNode, out IntPtr pNode); void Reserved9(); void Reserved10(); diff --git a/src/VisualStudio/Core/Def/Snippets/SnippetExpansionClientFactory.cs b/src/VisualStudio/Core/Def/Snippets/SnippetExpansionClientFactory.cs index ce6220f86dc6e..7deebb2a1fbca 100644 --- a/src/VisualStudio/Core/Def/Snippets/SnippetExpansionClientFactory.cs +++ b/src/VisualStudio/Core/Def/Snippets/SnippetExpansionClientFactory.cs @@ -18,7 +18,6 @@ using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Editor.Commanding; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Snippets; diff --git a/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/AbstractSnippetFunction.IVsExpansionFunction.cs b/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/AbstractSnippetFunction.IVsExpansionFunction.cs index e0ead9738835c..b013eb9190dae 100644 --- a/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/AbstractSnippetFunction.IVsExpansionFunction.cs +++ b/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/AbstractSnippetFunction.IVsExpansionFunction.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.Runtime.InteropServices; using System.Threading; using Microsoft.VisualStudio.TextManager.Interop; diff --git a/src/VisualStudio/Core/Def/SolutionEventMonitor.cs b/src/VisualStudio/Core/Def/SolutionEventMonitor.cs index 18d960b371a7e..5011b4542c63d 100644 --- a/src/VisualStudio/Core/Def/SolutionEventMonitor.cs +++ b/src/VisualStudio/Core/Def/SolutionEventMonitor.cs @@ -4,9 +4,9 @@ using System; using System.Collections.Generic; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Notification; using Microsoft.VisualStudio.Shell; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices; diff --git a/src/VisualStudio/Core/Def/StackTraceExplorer/StackFrameViewModel.cs b/src/VisualStudio/Core/Def/StackTraceExplorer/StackFrameViewModel.cs index b97644aa038cc..bc18e7a50097c 100644 --- a/src/VisualStudio/Core/Def/StackTraceExplorer/StackFrameViewModel.cs +++ b/src/VisualStudio/Core/Def/StackTraceExplorer/StackFrameViewModel.cs @@ -28,31 +28,22 @@ namespace Microsoft.VisualStudio.LanguageServices.StackTraceExplorer; using StackFrameToken = EmbeddedSyntaxToken; using StackFrameTrivia = EmbeddedSyntaxTrivia; -internal class StackFrameViewModel : FrameViewModel +internal class StackFrameViewModel( + ParsedStackFrame frame, + IThreadingContext threadingContext, + Workspace workspace, + IClassificationFormatMap formatMap, + ClassificationTypeMap typeMap) : FrameViewModel(formatMap, typeMap) { - private readonly ParsedStackFrame _frame; - private readonly IThreadingContext _threadingContext; - private readonly Workspace _workspace; - private readonly IStackTraceExplorerService _stackExplorerService; + private readonly ParsedStackFrame _frame = frame; + private readonly IThreadingContext _threadingContext = threadingContext; + private readonly Workspace _workspace = workspace; + private readonly IStackTraceExplorerService _stackExplorerService = workspace.Services.GetRequiredService(); private readonly Dictionary _definitionCache = []; - private Document? _cachedDocument; + private TextDocument? _cachedDocument; private int _cachedLineNumber; - public StackFrameViewModel( - ParsedStackFrame frame, - IThreadingContext threadingContext, - Workspace workspace, - IClassificationFormatMap formatMap, - ClassificationTypeMap typeMap) - : base(formatMap, typeMap) - { - _frame = frame; - _threadingContext = threadingContext; - _workspace = workspace; - _stackExplorerService = workspace.Services.GetRequiredService(); - } - public override bool ShowMouseOver => true; public void NavigateToClass() @@ -112,14 +103,11 @@ public async Task NavigateToFileAsync(CancellationToken cancellationToken) { try { - var (document, lineNumber) = GetDocumentAndLine(); + var (textDocument, lineNumber) = GetDocumentAndLine(); - if (document is not null) + if (textDocument is not null) { - // While navigating do not activate the tab, which will change focus from the tool window - var options = new NavigationOptions(PreferProvisionalTab: true, ActivateTab: false); - - var sourceText = await document.GetValueTextAsync(cancellationToken).ConfigureAwait(false); + var sourceText = await textDocument.GetValueTextAsync(cancellationToken).ConfigureAwait(false); // If the line number is larger than the total lines in the file // then just go to the end of the file (lines count). This can happen @@ -131,8 +119,12 @@ public async Task NavigateToFileAsync(CancellationToken cancellationToken) if (navigationService is null) return; - var location = await navigationService.TryNavigateToLineAndOffsetAsync( - _threadingContext, _workspace, document.Id, lineNumber - 1, offset: 0, options, cancellationToken).ConfigureAwait(false); + // While navigating do not activate the tab, which will change focus from the tool window + var options = new NavigationOptions(PreferProvisionalTab: true, ActivateTab: false); + + await navigationService.TryNavigateToLineAndOffsetAsync( + _threadingContext, _workspace, textDocument.Id, lineNumber - 1, offset: 0, options, cancellationToken) + .ConfigureAwait(false); } } catch (Exception ex) when (FatalError.ReportAndCatchUnlessCanceled(ex, cancellationToken)) @@ -208,7 +200,7 @@ protected override IEnumerable CreateInlines() yield return MakeClassifiedRun(ClassificationTypeNames.Text, _frame.Root.EndOfLineToken.ToFullString()); } - private (Document? document, int lineNumber) GetDocumentAndLine() + private (TextDocument? document, int lineNumber) GetDocumentAndLine() { if (_cachedDocument is not null) { diff --git a/src/VisualStudio/Core/Def/StackTraceExplorer/StackTraceExplorerCommandHandler.cs b/src/VisualStudio/Core/Def/StackTraceExplorer/StackTraceExplorerCommandHandler.cs index 610808ca0e25a..e9bad085d3c3f 100644 --- a/src/VisualStudio/Core/Def/StackTraceExplorer/StackTraceExplorerCommandHandler.cs +++ b/src/VisualStudio/Core/Def/StackTraceExplorer/StackTraceExplorerCommandHandler.cs @@ -4,7 +4,7 @@ using System; using System.ComponentModel.Design; -using System.Linq; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Options; diff --git a/src/VisualStudio/Core/Def/StackTraceExplorer/StackTraceExplorerViewModel.cs b/src/VisualStudio/Core/Def/StackTraceExplorer/StackTraceExplorerViewModel.cs index 8bc9c79daab03..303e06c91a5ee 100644 --- a/src/VisualStudio/Core/Def/StackTraceExplorer/StackTraceExplorerViewModel.cs +++ b/src/VisualStudio/Core/Def/StackTraceExplorer/StackTraceExplorerViewModel.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.VisualStudio.LanguageServices.Utilities; using Microsoft.VisualStudio.Text.Classification; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.StackTraceExplorer; diff --git a/src/VisualStudio/Core/Def/SymbolSearch/AbstractDelayStartedService.cs b/src/VisualStudio/Core/Def/SymbolSearch/AbstractDelayStartedService.cs index df77fde5013ba..73455ee6880d2 100644 --- a/src/VisualStudio/Core/Def/SymbolSearch/AbstractDelayStartedService.cs +++ b/src/VisualStudio/Core/Def/SymbolSearch/AbstractDelayStartedService.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Threading; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; using Roslyn.Utilities; diff --git a/src/VisualStudio/Core/Def/SyncNamespaces/SyncNamespacesCommandHandler.cs b/src/VisualStudio/Core/Def/SyncNamespaces/SyncNamespacesCommandHandler.cs index bbf961860df10..42aa50a166bea 100644 --- a/src/VisualStudio/Core/Def/SyncNamespaces/SyncNamespacesCommandHandler.cs +++ b/src/VisualStudio/Core/Def/SyncNamespaces/SyncNamespacesCommandHandler.cs @@ -10,11 +10,9 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Progress; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SyncNamespaces; diff --git a/src/VisualStudio/Core/Def/TableDataSource/Suppression/VisualStudioSuppressionFixService.cs b/src/VisualStudio/Core/Def/TableDataSource/Suppression/VisualStudioSuppressionFixService.cs index 083a2fc3c2efa..b2992e2b257d0 100644 --- a/src/VisualStudio/Core/Def/TableDataSource/Suppression/VisualStudioSuppressionFixService.cs +++ b/src/VisualStudio/Core/Def/TableDataSource/Suppression/VisualStudioSuppressionFixService.cs @@ -18,12 +18,10 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Progress; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; using Microsoft.VisualStudio.LanguageServices.Implementation.TableDataSource; -using Microsoft.VisualStudio.LanguageServices.Implementation.TaskList; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Shell.TableControl; @@ -267,9 +265,9 @@ private async Task ApplySuppressionFixAsync( if (!documentDiagnosticsPerLanguage.IsEmpty) { var suppressionFixer = GetSuppressionFixer(documentDiagnosticsPerLanguage.SelectMany(kvp => kvp.Value), language, _codeFixService); - if (suppressionFixer != null) + var suppressionFixAllProvider = suppressionFixer?.GetFixAllProvider(); + if (suppressionFixer != null && suppressionFixAllProvider != null) { - var suppressionFixAllProvider = suppressionFixer.GetFixAllProvider(); newSolution = await _fixMultipleOccurencesService.GetFixAsync( documentDiagnosticsPerLanguage, _workspace, @@ -292,9 +290,9 @@ private async Task ApplySuppressionFixAsync( if (!projectDiagnosticsPerLanguage.IsEmpty) { var suppressionFixer = GetSuppressionFixer(projectDiagnosticsPerLanguage.SelectMany(kvp => kvp.Value), language, _codeFixService); - if (suppressionFixer != null) + var suppressionFixAllProvider = suppressionFixer?.GetFixAllProvider(); + if (suppressionFixer != null && suppressionFixAllProvider != null) { - var suppressionFixAllProvider = suppressionFixer.GetFixAllProvider(); newSolution = await _fixMultipleOccurencesService.GetFixAsync( projectDiagnosticsPerLanguage, _workspace, @@ -486,7 +484,7 @@ private async Task>> Ge RoslynDebug.AssertNotNull(latestDocumentDiagnosticsMap); var uniqueDiagnosticIds = group.SelectMany(kvp => kvp.Value.Select(d => d.Id)).ToImmutableHashSet(); - var latestProjectDiagnostics = (await _diagnosticService.GetDiagnosticsForIdsAsync(project.Solution, project.Id, documentId: null, + var latestProjectDiagnostics = (await _diagnosticService.GetDiagnosticsForIdsAsync(project, documentId: null, diagnosticIds: uniqueDiagnosticIds, shouldIncludeAnalyzer: null, includeLocalDocumentDiagnostics: true, includeNonLocalDocumentDiagnostics: true, cancellationToken) .ConfigureAwait(false)).Where(IsDocumentDiagnostic); @@ -576,7 +574,7 @@ private async Task>> Get RoslynDebug.AssertNotNull(latestDiagnosticsToFix); var uniqueDiagnosticIds = diagnostics.Select(d => d.Id).ToImmutableHashSet(); - var latestDiagnosticsFromDiagnosticService = (await _diagnosticService.GetDiagnosticsForIdsAsync(project.Solution, project.Id, documentId: null, + var latestDiagnosticsFromDiagnosticService = (await _diagnosticService.GetDiagnosticsForIdsAsync(project, documentId: null, diagnosticIds: uniqueDiagnosticIds, shouldIncludeAnalyzer: null, includeLocalDocumentDiagnostics: true, includeNonLocalDocumentDiagnostics: true, cancellationToken) .ConfigureAwait(false)); diff --git a/src/VisualStudio/Core/Def/TaskList/ExternalErrorDiagnosticUpdateSource.cs b/src/VisualStudio/Core/Def/TaskList/ExternalErrorDiagnosticUpdateSource.cs index e370f5eee08c0..7fd735634876b 100644 --- a/src/VisualStudio/Core/Def/TaskList/ExternalErrorDiagnosticUpdateSource.cs +++ b/src/VisualStudio/Core/Def/TaskList/ExternalErrorDiagnosticUpdateSource.cs @@ -19,12 +19,12 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Threading; using Microsoft.ServiceHub.Framework; using Microsoft.VisualStudio.RpcContracts.DiagnosticManagement; using Microsoft.VisualStudio.RpcContracts.Utilities; using Microsoft.VisualStudio.Shell.ServiceBroker; using Roslyn.Utilities; -using static Microsoft.ServiceHub.Framework.ServiceBrokerClient; namespace Microsoft.VisualStudio.LanguageServices.Implementation.TaskList; /// diff --git a/src/VisualStudio/Core/Def/TaskList/ProjectExternalErrorReporter.cs b/src/VisualStudio/Core/Def/TaskList/ProjectExternalErrorReporter.cs index 6347f04d86a89..13bbdb9b5203f 100644 --- a/src/VisualStudio/Core/Def/TaskList/ProjectExternalErrorReporter.cs +++ b/src/VisualStudio/Core/Def/TaskList/ProjectExternalErrorReporter.cs @@ -5,7 +5,6 @@ #nullable disable using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Globalization; @@ -19,7 +18,6 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; -using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.Extensions; using Microsoft.VisualStudio.LanguageServices.Implementation.Venus; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.TextManager.Interop; diff --git a/src/VisualStudio/Core/Def/Telemetry/AbstractWorkspaceTelemetryService.cs b/src/VisualStudio/Core/Def/Telemetry/AbstractWorkspaceTelemetryService.cs index cb1ef8c812cbd..7921adfd5ddae 100644 --- a/src/VisualStudio/Core/Def/Telemetry/AbstractWorkspaceTelemetryService.cs +++ b/src/VisualStudio/Core/Def/Telemetry/AbstractWorkspaceTelemetryService.cs @@ -5,11 +5,11 @@ using System; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Telemetry; using Microsoft.VisualStudio.Telemetry; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Telemetry; diff --git a/src/VisualStudio/Core/Def/Telemetry/CodeMarkerLogger.cs b/src/VisualStudio/Core/Def/Telemetry/CodeMarkerLogger.cs index 8e5b190021260..b146356ef20ab 100644 --- a/src/VisualStudio/Core/Def/Telemetry/CodeMarkerLogger.cs +++ b/src/VisualStudio/Core/Def/Telemetry/CodeMarkerLogger.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.Threading; diff --git a/src/VisualStudio/Core/Def/Telemetry/FileLogger.cs b/src/VisualStudio/Core/Def/Telemetry/FileLogger.cs index 916429085c48e..d6105f7e74e74 100644 --- a/src/VisualStudio/Core/Def/Telemetry/FileLogger.cs +++ b/src/VisualStudio/Core/Def/Telemetry/FileLogger.cs @@ -5,7 +5,6 @@ using System; using System.Globalization; using System.IO; -using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; @@ -17,6 +16,7 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Shared.Utilities; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Telemetry; diff --git a/src/VisualStudio/Core/Def/Telemetry/Shared/AggregatingHistogramLog.cs b/src/VisualStudio/Core/Def/Telemetry/Shared/AggregatingHistogramLog.cs index 11e4a262cb250..72bcb15a2c9b9 100644 --- a/src/VisualStudio/Core/Def/Telemetry/Shared/AggregatingHistogramLog.cs +++ b/src/VisualStudio/Core/Def/Telemetry/Shared/AggregatingHistogramLog.cs @@ -7,7 +7,6 @@ using Microsoft.VisualStudio.Telemetry; using Microsoft.VisualStudio.Telemetry.Metrics; using Microsoft.VisualStudio.Telemetry.Metrics.Events; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Telemetry; diff --git a/src/VisualStudio/Core/Def/Telemetry/VisualStudioWorkspaceTelemetryService.cs b/src/VisualStudio/Core/Def/Telemetry/VisualStudioWorkspaceTelemetryService.cs index 3b3a85b6b5fe4..2fa4f7ad2c105 100644 --- a/src/VisualStudio/Core/Def/Telemetry/VisualStudioWorkspaceTelemetryService.cs +++ b/src/VisualStudio/Core/Def/Telemetry/VisualStudioWorkspaceTelemetryService.cs @@ -6,16 +6,15 @@ using System.Composition; using System.Diagnostics; using System.Threading.Tasks; +using Microsoft.CodeAnalysis; 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; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Telemetry; using Microsoft.VisualStudio.Telemetry; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Telemetry; diff --git a/src/VisualStudio/Core/Def/UnusedReferences/Dialog/UnusedReferencesTableProvider.ColumnDefinitions.cs b/src/VisualStudio/Core/Def/UnusedReferences/Dialog/UnusedReferencesTableProvider.ColumnDefinitions.cs index 17a2da8e24bab..863e7f7ecf99c 100644 --- a/src/VisualStudio/Core/Def/UnusedReferences/Dialog/UnusedReferencesTableProvider.ColumnDefinitions.cs +++ b/src/VisualStudio/Core/Def/UnusedReferences/Dialog/UnusedReferencesTableProvider.ColumnDefinitions.cs @@ -17,7 +17,6 @@ using Microsoft.VisualStudio.Shell.TableControl; using Microsoft.VisualStudio.Shell.TableManager; using Microsoft.VisualStudio.Utilities; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.UnusedReferences.Dialog; diff --git a/src/VisualStudio/Core/Def/UnusedReferences/UnusedReferenceExtensions.cs b/src/VisualStudio/Core/Def/UnusedReferences/UnusedReferenceExtensions.cs index 5c6251c350a89..0206b8e26a775 100644 --- a/src/VisualStudio/Core/Def/UnusedReferences/UnusedReferenceExtensions.cs +++ b/src/VisualStudio/Core/Def/UnusedReferences/UnusedReferenceExtensions.cs @@ -2,10 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Immutable; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.UnusedReferences; using Microsoft.VisualStudio.LanguageServices.ExternalAccess.ProjectSystem.Api; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.UnusedReferences; diff --git a/src/VisualStudio/Core/Def/Utilities/BooleanReverseConverter.cs b/src/VisualStudio/Core/Def/Utilities/BooleanReverseConverter.cs index da84c8bc5311d..c7bf9df1a6140 100644 --- a/src/VisualStudio/Core/Def/Utilities/BooleanReverseConverter.cs +++ b/src/VisualStudio/Core/Def/Utilities/BooleanReverseConverter.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.Globalization; using System.Windows.Data; diff --git a/src/VisualStudio/Core/Def/Utilities/ComEventSink.cs b/src/VisualStudio/Core/Def/Utilities/ComEventSink.cs index c3182f8e4fcce..4f73e0227e462 100644 --- a/src/VisualStudio/Core/Def/Utilities/ComEventSink.cs +++ b/src/VisualStudio/Core/Def/Utilities/ComEventSink.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.VisualStudio.OLE.Interop; diff --git a/src/VisualStudio/Core/Def/Utilities/EnumBoolConverter.cs b/src/VisualStudio/Core/Def/Utilities/EnumBoolConverter.cs index c196e60fbea82..8213827dbd0ed 100644 --- a/src/VisualStudio/Core/Def/Utilities/EnumBoolConverter.cs +++ b/src/VisualStudio/Core/Def/Utilities/EnumBoolConverter.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.Globalization; using System.Windows; diff --git a/src/VisualStudio/Core/Def/Utilities/GlyphExtensions.cs b/src/VisualStudio/Core/Def/Utilities/GlyphExtensions.cs index 1e3e92e780ef8..69ca9501c8372 100644 --- a/src/VisualStudio/Core/Def/Utilities/GlyphExtensions.cs +++ b/src/VisualStudio/Core/Def/Utilities/GlyphExtensions.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.Windows.Media; using Microsoft.CodeAnalysis; diff --git a/src/VisualStudio/Core/Def/Utilities/IVsEnumDebugName.cs b/src/VisualStudio/Core/Def/Utilities/IVsEnumDebugName.cs index 6e07fc874fd38..66c64a14fbf5a 100644 --- a/src/VisualStudio/Core/Def/Utilities/IVsEnumDebugName.cs +++ b/src/VisualStudio/Core/Def/Utilities/IVsEnumDebugName.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.Runtime.InteropServices; using Microsoft.VisualStudio.TextManager.Interop; diff --git a/src/VisualStudio/Core/Def/Utilities/IVsLanguageDebugInfo.cs b/src/VisualStudio/Core/Def/Utilities/IVsLanguageDebugInfo.cs index bed87a9436ee4..037e3060804e6 100644 --- a/src/VisualStudio/Core/Def/Utilities/IVsLanguageDebugInfo.cs +++ b/src/VisualStudio/Core/Def/Utilities/IVsLanguageDebugInfo.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.Runtime.InteropServices; using Microsoft.VisualStudio.TextManager.Interop; @@ -16,7 +14,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; internal interface IVsLanguageDebugInfo { [PreserveSig] - int GetProximityExpressions(IVsTextBuffer pBuffer, int iLine, int iCol, int cLines, out IVsEnumBSTR ppEnum); + int GetProximityExpressions(IVsTextBuffer pBuffer, int iLine, int iCol, int cLines, out IVsEnumBSTR? ppEnum); [PreserveSig] int ValidateBreakpointLocation( @@ -26,16 +24,16 @@ int ValidateBreakpointLocation( [In, Out, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Struct)] TextSpan[] pCodeSpan); [PreserveSig] - int GetNameOfLocation(IVsTextBuffer pBuffer, int iLine, int iCol, [MarshalAs(UnmanagedType.BStr)] out string pbstrName, out int piLineOffset); + int GetNameOfLocation(IVsTextBuffer pBuffer, int iLine, int iCol, [MarshalAs(UnmanagedType.BStr)] out string? pbstrName, out int piLineOffset); [PreserveSig] int GetLocationOfName( [MarshalAs(UnmanagedType.LPWStr)] string pszName, - [MarshalAs(UnmanagedType.BStr)] out string pbstrMkDoc, + [MarshalAs(UnmanagedType.BStr)] out string? pbstrMkDoc, out TextSpan pspanLocation); [PreserveSig] - int ResolveName([MarshalAs(UnmanagedType.LPWStr)] string pszName, uint dwFlags, out IVsEnumDebugName ppNames); + int ResolveName([MarshalAs(UnmanagedType.LPWStr)] string? pszName, uint dwFlags, out IVsEnumDebugName? ppNames); [PreserveSig] int GetLanguageID(IVsTextBuffer pBuffer, int iLine, int iCol, out Guid pguidLanguageID); diff --git a/src/VisualStudio/Core/Def/Utilities/IVsShellExtensions.cs b/src/VisualStudio/Core/Def/Utilities/IVsShellExtensions.cs index 13486e307cffb..167641cbcdb2a 100644 --- a/src/VisualStudio/Core/Def/Utilities/IVsShellExtensions.cs +++ b/src/VisualStudio/Core/Def/Utilities/IVsShellExtensions.cs @@ -2,12 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; -using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudio.Threading; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; @@ -19,30 +15,21 @@ internal static class IVsShellExtensions /// /// Returns true if devenv is invoked in command line mode for build, e.g. devenv /rebuild MySolution.sln /// - public static bool IsInCommandLineMode(JoinableTaskFactory joinableTaskFactory) + public static bool IsInCommandLineMode(this IVsShell shell) { - var result = s_isInCommandLineMode; - if (result == 0) + if (s_isInCommandLineMode == 0) { - s_isInCommandLineMode = result = joinableTaskFactory.Run(async () => - { - await joinableTaskFactory.SwitchToMainThreadAsync(); - - var shell = ServiceProvider.GlobalProvider.GetService(joinableTaskFactory); - return - (shell != null) && - ErrorHandler.Succeeded(shell.GetProperty((int)__VSSPROPID.VSSPROPID_IsInCommandLineMode, out var result)) && - (bool)result ? 1 : -1; - }); + s_isInCommandLineMode = + ErrorHandler.Succeeded(shell.GetProperty((int)__VSSPROPID.VSSPROPID_IsInCommandLineMode, out var result)) && + (bool)result ? 1 : -1; } - return result == 1; + return s_isInCommandLineMode == 1; } public static bool TryGetPropertyValue(this IVsShell shell, __VSSPROPID id, out IntPtr value) { - var hresult = shell.GetProperty((int)id, out var objValue); - if (ErrorHandler.Succeeded(hresult) && objValue != null) + if (ErrorHandler.Succeeded(shell.GetProperty((int)id, out var objValue)) && objValue != null) { value = (IntPtr.Size == 4) ? (IntPtr)(int)objValue : (IntPtr)(long)objValue; return true; diff --git a/src/VisualStudio/Core/Def/Utilities/ProjectPropertyStorage.cs b/src/VisualStudio/Core/Def/Utilities/ProjectPropertyStorage.cs index 6a5f8b95e45a3..54bde706b1a77 100644 --- a/src/VisualStudio/Core/Def/Utilities/ProjectPropertyStorage.cs +++ b/src/VisualStudio/Core/Def/Utilities/ProjectPropertyStorage.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.Globalization; using EnvDTE; diff --git a/src/VisualStudio/Core/Def/Utilities/SymbolViewModel.cs b/src/VisualStudio/Core/Def/Utilities/SymbolViewModel.cs index 6f35b512ea03e..2f2a1d961cb27 100644 --- a/src/VisualStudio/Core/Def/Utilities/SymbolViewModel.cs +++ b/src/VisualStudio/Core/Def/Utilities/SymbolViewModel.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.Windows.Media; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/VisualStudio/Core/Def/Utilities/TaskItemsEnum.cs b/src/VisualStudio/Core/Def/Utilities/TaskItemsEnum.cs index f1609915e81bf..d0874bcf7d470 100644 --- a/src/VisualStudio/Core/Def/Utilities/TaskItemsEnum.cs +++ b/src/VisualStudio/Core/Def/Utilities/TaskItemsEnum.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.VisualStudio.Shell.Interop; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; diff --git a/src/VisualStudio/Core/Def/Utilities/VisualStudioNavigateToLinkService.cs b/src/VisualStudio/Core/Def/Utilities/VisualStudioNavigateToLinkService.cs index f6f78cbb0a273..d3f2763c361c1 100644 --- a/src/VisualStudio/Core/Def/Utilities/VisualStudioNavigateToLinkService.cs +++ b/src/VisualStudio/Core/Def/Utilities/VisualStudioNavigateToLinkService.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.Composition; using System.Threading; diff --git a/src/VisualStudio/Core/Def/Utilities/VsCodeWindowViewTracker.cs b/src/VisualStudio/Core/Def/Utilities/VsCodeWindowViewTracker.cs index 5f98a5145219a..23c46561cc095 100644 --- a/src/VisualStudio/Core/Def/Utilities/VsCodeWindowViewTracker.cs +++ b/src/VisualStudio/Core/Def/Utilities/VsCodeWindowViewTracker.cs @@ -6,13 +6,13 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.VisualStudio.Editor; using Microsoft.VisualStudio.LanguageServices.Implementation; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.TextManager.Interop; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Utilities; diff --git a/src/VisualStudio/Core/Def/Utilities/VsDebugName.cs b/src/VisualStudio/Core/Def/Utilities/VsDebugName.cs index f6edca0ccebef..1702f78798740 100644 --- a/src/VisualStudio/Core/Def/Utilities/VsDebugName.cs +++ b/src/VisualStudio/Core/Def/Utilities/VsDebugName.cs @@ -2,19 +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. -#nullable disable - using Microsoft.VisualStudio.TextManager.Interop; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; internal class VsDebugName : IVsDebugName { - private readonly string _name; + private readonly string? _name; private readonly string _document; private readonly TextSpan _textSpan; - public VsDebugName(string name, string document, TextSpan textSpan) + public VsDebugName(string? name, string document, TextSpan textSpan) { _name = name; _document = document; @@ -33,7 +31,7 @@ public int GetLocation(out string pbstrMkDoc, TextSpan[] pspanLocation) return VSConstants.S_OK; } - public int GetName(out string pbstrName) + public int GetName(out string? pbstrName) { pbstrName = _name; return VSConstants.S_OK; diff --git a/src/VisualStudio/Core/Def/Utilities/VsEnumBSTR.cs b/src/VisualStudio/Core/Def/Utilities/VsEnumBSTR.cs index 54bda28c7fafa..689ef82adc426 100644 --- a/src/VisualStudio/Core/Def/Utilities/VsEnumBSTR.cs +++ b/src/VisualStudio/Core/Def/Utilities/VsEnumBSTR.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 Microsoft.VisualStudio.TextManager.Interop; diff --git a/src/VisualStudio/Core/Def/Utilities/VsEnumDebugName.cs b/src/VisualStudio/Core/Def/Utilities/VsEnumDebugName.cs index d2c30793082db..c08137d33c7aa 100644 --- a/src/VisualStudio/Core/Def/Utilities/VsEnumDebugName.cs +++ b/src/VisualStudio/Core/Def/Utilities/VsEnumDebugName.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 Microsoft.VisualStudio.TextManager.Interop; diff --git a/src/VisualStudio/Core/Def/ValueTracking/ValueTrackingCommandHandler.cs b/src/VisualStudio/Core/Def/ValueTracking/ValueTrackingCommandHandler.cs index ccf51298a64f2..c45464fba450b 100644 --- a/src/VisualStudio/Core/Def/ValueTracking/ValueTrackingCommandHandler.cs +++ b/src/VisualStudio/Core/Def/ValueTracking/ValueTrackingCommandHandler.cs @@ -25,7 +25,6 @@ using Microsoft.VisualStudio.Text.Classification; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Utilities; -using Roslyn.Utilities; using IAsyncServiceProvider = Microsoft.VisualStudio.Shell.IAsyncServiceProvider; using Task = System.Threading.Tasks.Task; diff --git a/src/VisualStudio/Core/Def/ValueTracking/ValueTrackingToolWindow.cs b/src/VisualStudio/Core/Def/ValueTracking/ValueTrackingToolWindow.cs index 88420dc2c84f2..0fa4cac845d65 100644 --- a/src/VisualStudio/Core/Def/ValueTracking/ValueTrackingToolWindow.cs +++ b/src/VisualStudio/Core/Def/ValueTracking/ValueTrackingToolWindow.cs @@ -5,7 +5,6 @@ using System; using System.Runtime.InteropServices; using Microsoft.VisualStudio.Shell; -using Roslyn.Utilities; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using System.Diagnostics.CodeAnalysis; diff --git a/src/VisualStudio/Core/Def/ValueTracking/ValueTrackingTree.xaml b/src/VisualStudio/Core/Def/ValueTracking/ValueTrackingTree.xaml index d7986f75defb8..76a779300bac0 100644 --- a/src/VisualStudio/Core/Def/ValueTracking/ValueTrackingTree.xaml +++ b/src/VisualStudio/Core/Def/ValueTracking/ValueTrackingTree.xaml @@ -6,13 +6,18 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:Microsoft.VisualStudio.LanguageServices.ValueTracking" xmlns:utils="clr-namespace:Microsoft.VisualStudio.LanguageServices.Utilities" + xmlns:platformimaging="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Imaging" + xmlns:vsshell="clr-namespace:Microsoft.VisualStudio.Shell;assembly=Microsoft.VisualStudio.Shell.15.0" + xmlns:vsutil="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Utilities" mc:Ignorable="d" xmlns:vs="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.15.0" + platformimaging:ImageThemingUtilities.ImageBackgroundColor="{StaticResource {x:Static vsshell:VsColors.ToolWindowBackgroundKey}}" d:DesignHeight="450" d:DesignWidth="800" x:Name="control"> + @@ -59,7 +64,20 @@ - + + + + + + + + + diff --git a/src/VisualStudio/Core/Def/Venus/CodeBlockEnumerator.cs b/src/VisualStudio/Core/Def/Venus/CodeBlockEnumerator.cs index 29cfe6e20be64..d1907892a28e1 100644 --- a/src/VisualStudio/Core/Def/Venus/CodeBlockEnumerator.cs +++ b/src/VisualStudio/Core/Def/Venus/CodeBlockEnumerator.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using Microsoft.VisualStudio.TextManager.Interop; diff --git a/src/VisualStudio/Core/Def/Venus/ContainedLanguage.cs b/src/VisualStudio/Core/Def/Venus/ContainedLanguage.cs index d4757ab3baa21..cf11ec5068991 100644 --- a/src/VisualStudio/Core/Def/Venus/ContainedLanguage.cs +++ b/src/VisualStudio/Core/Def/Venus/ContainedLanguage.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Formatting.Rules; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; using Microsoft.VisualStudio.ComponentModelHost; @@ -139,8 +138,6 @@ internal ContainedLanguage( this.DataBuffer.Changed += OnDataBufferChanged; } - public IGlobalOptionService GlobalOptions => _diagnosticAnalyzerService.GlobalOptions; - private void OnDisconnect() { this.DataBuffer.Changed -= OnDataBufferChanged; diff --git a/src/VisualStudio/Core/Def/Venus/ContainedLanguageCodeSupport.cs b/src/VisualStudio/Core/Def/Venus/ContainedLanguageCodeSupport.cs index 749fec43366db..bd85f1ad6d873 100644 --- a/src/VisualStudio/Core/Def/Venus/ContainedLanguageCodeSupport.cs +++ b/src/VisualStudio/Core/Def/Venus/ContainedLanguageCodeSupport.cs @@ -20,7 +20,6 @@ using Microsoft.CodeAnalysis.Formatting.Rules; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.LanguageService; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Rename; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; diff --git a/src/VisualStudio/Core/Def/Venus/IAdditionalFormattingRuleLanguageService.cs b/src/VisualStudio/Core/Def/Venus/IAdditionalFormattingRuleLanguageService.cs index 9a89c262a487a..eb13ec245e2d6 100644 --- a/src/VisualStudio/Core/Def/Venus/IAdditionalFormattingRuleLanguageService.cs +++ b/src/VisualStudio/Core/Def/Venus/IAdditionalFormattingRuleLanguageService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Formatting.Rules; using Microsoft.CodeAnalysis.Host; diff --git a/src/VisualStudio/Core/Def/Venus/IVsContainedLanguageCodeSupport.cs b/src/VisualStudio/Core/Def/Venus/IVsContainedLanguageCodeSupport.cs index 2634d7722e98b..b590955da3c58 100644 --- a/src/VisualStudio/Core/Def/Venus/IVsContainedLanguageCodeSupport.cs +++ b/src/VisualStudio/Core/Def/Venus/IVsContainedLanguageCodeSupport.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.Runtime.CompilerServices; using System.Runtime.InteropServices; diff --git a/src/VisualStudio/Core/Def/Venus/IVsContainedLanguageStaticEventBinding.cs b/src/VisualStudio/Core/Def/Venus/IVsContainedLanguageStaticEventBinding.cs index b6a2b88e5fcd9..eebcb233eda55 100644 --- a/src/VisualStudio/Core/Def/Venus/IVsContainedLanguageStaticEventBinding.cs +++ b/src/VisualStudio/Core/Def/Venus/IVsContainedLanguageStaticEventBinding.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.Runtime.CompilerServices; using System.Runtime.InteropServices; diff --git a/src/VisualStudio/Core/Def/Venus/VenusCommandFilter.cs b/src/VisualStudio/Core/Def/Venus/VenusCommandFilter.cs index 4749f29b355ae..3a14dc0bf351d 100644 --- a/src/VisualStudio/Core/Def/Venus/VenusCommandFilter.cs +++ b/src/VisualStudio/Core/Def/Venus/VenusCommandFilter.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.Linq; using System.Threading.Tasks; +using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.ComponentModelHost; using Microsoft.VisualStudio.Editor; using Microsoft.VisualStudio.LanguageServices.Implementation.Extensions; @@ -14,7 +15,6 @@ using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.TextManager.Interop; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Venus; diff --git a/src/VisualStudio/Core/Def/Venus/VenusCommandFilter`2.cs b/src/VisualStudio/Core/Def/Venus/VenusCommandFilter`2.cs index f173f52e49bc5..b9fa500c66751 100644 --- a/src/VisualStudio/Core/Def/Venus/VenusCommandFilter`2.cs +++ b/src/VisualStudio/Core/Def/Venus/VenusCommandFilter`2.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.Editor; using Microsoft.VisualStudio.Editor; diff --git a/src/VisualStudio/Core/Def/Venus/VenusTaskExtensions.cs b/src/VisualStudio/Core/Def/Venus/VenusTaskExtensions.cs index b63c065b23669..6295692ae8c28 100644 --- a/src/VisualStudio/Core/Def/Venus/VenusTaskExtensions.cs +++ b/src/VisualStudio/Core/Def/Venus/VenusTaskExtensions.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Threading.Tasks; using Roslyn.Utilities; using System.Threading; diff --git a/src/VisualStudio/Core/Def/Workspace/GlobalUndoServiceFactory.WorkspaceGlobalUndoTransaction.cs b/src/VisualStudio/Core/Def/Workspace/GlobalUndoServiceFactory.WorkspaceGlobalUndoTransaction.cs index 3b12e746f5205..2fa2e31e63ba5 100644 --- a/src/VisualStudio/Core/Def/Workspace/GlobalUndoServiceFactory.WorkspaceGlobalUndoTransaction.cs +++ b/src/VisualStudio/Core/Def/Workspace/GlobalUndoServiceFactory.WorkspaceGlobalUndoTransaction.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.Diagnostics; using System.Runtime.InteropServices; @@ -15,7 +13,6 @@ using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text.Operations; using Microsoft.VisualStudio.TextManager.Interop; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation; diff --git a/src/VisualStudio/Core/Def/Workspace/GlobalUndoServiceFactory.cs b/src/VisualStudio/Core/Def/Workspace/GlobalUndoServiceFactory.cs index fcdcd0707d1c5..8da33360a1c82 100644 --- a/src/VisualStudio/Core/Def/Workspace/GlobalUndoServiceFactory.cs +++ b/src/VisualStudio/Core/Def/Workspace/GlobalUndoServiceFactory.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.Composition; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; diff --git a/src/VisualStudio/Core/Def/Workspace/SourceGeneratedFileManager.cs b/src/VisualStudio/Core/Def/Workspace/SourceGeneratedFileManager.cs index 0af0d25e5fda4..2f9c4cde491f2 100644 --- a/src/VisualStudio/Core/Def/Workspace/SourceGeneratedFileManager.cs +++ b/src/VisualStudio/Core/Def/Workspace/SourceGeneratedFileManager.cs @@ -18,6 +18,7 @@ using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text.Shared.Extensions; +using Microsoft.CodeAnalysis.Threading; using Microsoft.VisualStudio.Editor; using Microsoft.VisualStudio.Imaging; using Microsoft.VisualStudio.Imaging.Interop; diff --git a/src/VisualStudio/Core/Def/Workspace/VisualStudioAddMetadataReferenceCodeActionOperationFactoryWorkspaceService.cs b/src/VisualStudio/Core/Def/Workspace/VisualStudioAddMetadataReferenceCodeActionOperationFactoryWorkspaceService.cs index ffce08637e1bb..a8269bd3e3cd4 100644 --- a/src/VisualStudio/Core/Def/Workspace/VisualStudioAddMetadataReferenceCodeActionOperationFactoryWorkspaceService.cs +++ b/src/VisualStudio/Core/Def/Workspace/VisualStudioAddMetadataReferenceCodeActionOperationFactoryWorkspaceService.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.Composition; using System.Threading; diff --git a/src/VisualStudio/Core/Def/Workspace/VisualStudioDocumentNavigationService.cs b/src/VisualStudio/Core/Def/Workspace/VisualStudioDocumentNavigationService.cs index 97ec5a757a3ab..ced22ef8af18a 100644 --- a/src/VisualStudio/Core/Def/Workspace/VisualStudioDocumentNavigationService.cs +++ b/src/VisualStudio/Core/Def/Workspace/VisualStudioDocumentNavigationService.cs @@ -189,35 +189,30 @@ static VsTextSpan GetVsTextSpanFromPosition(SourceText text, int position, int v documentId = workspace.GetDocumentIdInCurrentContext(documentId); var solution = workspace.CurrentSolution; - var document = solution.GetDocument(documentId); - if (document == null) - { - var project = solution.GetProject(documentId.ProjectId); - if (project is null) - { - // This is a source generated document shown in Solution Explorer, but is no longer valid since - // the configuration and/or platform changed since the last generation completed. - return null; - } + var textDocument = await solution.GetTextDocumentAsync(documentId, cancellationToken).ConfigureAwait(false); - var generatedDocument = await project.GetSourceGeneratedDocumentAsync(documentId, cancellationToken).ConfigureAwait(false); - if (generatedDocument == null) - return null; + if (textDocument is null) + { + return null; + } + if (textDocument is SourceGeneratedDocument generatedDocument) + { return _sourceGeneratedFileManager.Value.GetNavigationCallback( generatedDocument, await getTextSpanForMappingAsync(generatedDocument).ConfigureAwait(false)); } // Before attempting to open the document, check if the location maps to a different file that should be opened instead. - var spanMappingService = document.DocumentServiceProvider.GetService(); - if (spanMappingService != null) + if (textDocument is Document document && + textDocument.DocumentServiceProvider.GetService() is ISpanMappingService spanMappingService) { var mappedSpanResult = await GetMappedSpanAsync( spanMappingService, document, await getTextSpanForMappingAsync(document).ConfigureAwait(false), cancellationToken).ConfigureAwait(false); + if (mappedSpanResult is { IsDefault: false } mappedSpan) { // Check if the mapped file matches one already in the workspace. diff --git a/src/VisualStudio/Core/Def/Workspace/VisualStudioFormattingRuleFactoryServiceFactory.cs b/src/VisualStudio/Core/Def/Workspace/VisualStudioFormattingRuleFactoryServiceFactory.cs index b51b31da8c863..284dbb6c5f45c 100644 --- a/src/VisualStudio/Core/Def/Workspace/VisualStudioFormattingRuleFactoryServiceFactory.cs +++ b/src/VisualStudio/Core/Def/Workspace/VisualStudioFormattingRuleFactoryServiceFactory.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.Composition; diff --git a/src/VisualStudio/Core/Def/Workspace/VisualStudioSymbolNavigationService.cs b/src/VisualStudio/Core/Def/Workspace/VisualStudioSymbolNavigationService.cs index 6de40fd0dc600..dd9fd0caf3f98 100644 --- a/src/VisualStudio/Core/Def/Workspace/VisualStudioSymbolNavigationService.cs +++ b/src/VisualStudio/Core/Def/Workspace/VisualStudioSymbolNavigationService.cs @@ -154,7 +154,13 @@ internal sealed partial class VisualStudioSymbolNavigationService( ErrorHandler.ThrowOnFailure(windowFrame.SetProperty((int)__VSFPROPID5.VSFPROPID_OverrideToolTip, result.DocumentTooltip)); } + // Subtle issue. We may already be in a provisional-tab. 'Showing' the window frame here will cause it to + // to take over the curren provisional-tab, cause a wait-indicators in the original to be dismissed (causing + // cancellation). To avoid that problem, we disable cancellation from this point. While not ideal, it is + // not problematic as we already forced the document to be opened here. So actually navigating to the + // location in it is effectively free. windowFrame.Show(); + cancellationToken = default; var openedDocument = textBuffer?.AsTextContainer().GetRelatedDocuments().FirstOrDefault(); if (openedDocument != null) diff --git a/src/VisualStudio/Core/Def/Workspace/VisualStudioSymbolRenamedCodeActionOperationFactoryWorkspaceService.cs b/src/VisualStudio/Core/Def/Workspace/VisualStudioSymbolRenamedCodeActionOperationFactoryWorkspaceService.cs index 84ea08267b0c5..f263ac5d89f50 100644 --- a/src/VisualStudio/Core/Def/Workspace/VisualStudioSymbolRenamedCodeActionOperationFactoryWorkspaceService.cs +++ b/src/VisualStudio/Core/Def/Workspace/VisualStudioSymbolRenamedCodeActionOperationFactoryWorkspaceService.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.Composition; diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf index cb949d5aa9915..97046c67471af 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf @@ -74,7 +74,7 @@ _Always add new line on enter - _Always add new line on enter + _Při stisku Enter vždy přidat nový řádek @@ -139,7 +139,7 @@ Automatically reload updated analyzers and generators (requires restart) - Automatically reload updated analyzers and generators (requires restart) + Automaticky znovu načíst aktualizované analyzátory a generátory (vyžaduje restartování) @@ -394,7 +394,7 @@ Editor Help - Editor Help + Nápověda k editoru @@ -434,12 +434,12 @@ Enter key behavior - Enter key behavior + Chování klávesy Enter Enter key behavior: - Enter key behavior: + Chování klávesy Enter: @@ -464,7 +464,7 @@ Experimental feature - Experimental feature + Experimentální funkce @@ -484,7 +484,7 @@ Fade out unused members - Fade out unused members + Setmít nepoužité členy @@ -539,12 +539,12 @@ Highlight matching portions of completion list items - Highlight matching portions of completion list items + Zvýraznit odpovídající části položek seznamu pro doplňování _Highlight references to symbol under cursor - _Highlight references to symbol under cursor + Z_výrazňovat odkazy na symbol pod kurzorem @@ -554,12 +554,12 @@ Highlight related _keywords under cursor - Highlight related _keywords under cursor + Zvýrazňovat související _klíčová slova pod kurzorem Highlighting - Highlighting + Zvýraznění @@ -619,7 +619,7 @@ Insert Snippet - Insert Snippet + Vložit fragment @@ -664,7 +664,7 @@ Large - Large + Velké @@ -914,12 +914,12 @@ Never - Never + Nikdy _Never add new line on enter - _Never add new line on enter + _Při stisku Enter nikdy nepřidávat nový řádek @@ -929,7 +929,7 @@ Never include snippets - Never include snippets + Nikdy nezahrnovat fragmenty @@ -979,7 +979,7 @@ Only add new line on enter after end of fully typed word - Only add new line on enter after end of fully typed word + Při stisku Enter přidat nový řádek jenom po dopsání celého slova @@ -994,7 +994,7 @@ Optimize for solution size - Optimize for solution size + Optimalizovat pro velikost řešení @@ -1079,7 +1079,7 @@ Performance - Performance + Výkon @@ -1189,7 +1189,7 @@ Prefer unbound generic type in 'nameof' - Prefer unbound generic type in 'nameof' + Preferovat nevázaný obecný typ v nameof @@ -1214,7 +1214,7 @@ Regular - Regular + Normální @@ -1384,7 +1384,7 @@ Show "Remove Unused References" command in Solution Explorer - Show "Remove Unused References" command in Solution Explorer + Zobrazit příkaz Odebrat nepoužívané odkazy v Průzkumníkovi řešení @@ -1404,12 +1404,12 @@ Show completion item _filters - Show completion item _filters + Zobrazit _filtry položek dokončení Show completion item filters - Show completion item filters + Zobrazit filtry položek pro doplňování @@ -1419,17 +1419,17 @@ Show completion list after a character is _deleted - Show completion list after a character is _deleted + _Zobrazit seznam dokončení po odstranění znaku Show completion list after a character is deleted - Show completion list after a character is deleted + Zobrazit seznam doplňování po odstranění znaku Show completion list after a character is typed - Show completion list after a character is typed + Zobrazit seznam dokončení po zadání znaku @@ -1479,22 +1479,22 @@ Show items from unimported namespaces - Show items from unimported namespaces + Zobrazit položky z neimportovaných oborů názvů Show preview for rename _tracking - Show preview for rename _tracking + Zobrazit náhled pro sledování _rename _Show procedure line separators - _Show procedure line separators + Zob_razit oddělovače řádků procedur Show remarks in Quick Info - Show remarks in Quick Info + Zobrazit poznámky v Rychlých informacích @@ -1504,12 +1504,12 @@ Small - Small + Malé Snippets behavior - Snippets behavior + Chování fragmentů @@ -1579,12 +1579,12 @@ Tab twice to insert arguments - Stisknout dvakrát tabulátor, aby se vložily argumenty (experimentální) + Dvojím stisknutím klávesy Tab vložíte argumenty Tab twice to insert arguments (experimental) - Tab twice to insert arguments (experimental) + Stisknout dvakrát tabulátor, aby se vložily argumenty (experimentální) @@ -1629,7 +1629,7 @@ Title - Title + Název @@ -1659,7 +1659,7 @@ Unused local - Unused local + Nepoužitá místní @@ -1884,17 +1884,17 @@ _Highlight matching portions of completion list items - _Highlight matching portions of completion list items + _Zvýraznit odpovídající části položek seznamu dokončení _Only add new line on enter after end of fully typed word - _Only add new line on enter after end of fully typed word + _Při stisku Enter přidat nový řádek jenom po dopsání celého slova _Show completion list after a character is typed - _Show completion list after a character is typed + _Zobrazovat seznam dokončení po zadání znaku diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf index 5d35cdb853a91..7986a4b478ccb 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf @@ -74,7 +74,7 @@ _Always add new line on enter - _Always add new line on enter + _Immer neue Zeile beim Drücken der EINGABETASTE einfügen @@ -139,7 +139,7 @@ Automatically reload updated analyzers and generators (requires restart) - Automatically reload updated analyzers and generators (requires restart) + Aktualisierte Analysetools und Generatoren automatisch neu laden (Neustart erforderlich) @@ -394,7 +394,7 @@ Editor Help - Editor Help + Editor-Hilfe @@ -434,12 +434,12 @@ Enter key behavior - Enter key behavior + Eingabetastenverhalten Enter key behavior: - Enter key behavior: + Verhalten der EINGABETASTE: @@ -464,7 +464,7 @@ Experimental feature - Experimental feature + Experimentelles Feature @@ -484,7 +484,7 @@ Fade out unused members - Fade out unused members + Ausblenden nicht verwendeter Elemente @@ -539,12 +539,12 @@ Highlight matching portions of completion list items - Highlight matching portions of completion list items + Markieren übereinstimmender Teile von Vervollständigungslistenelementen _Highlight references to symbol under cursor - _Highlight references to symbol under cursor + _Verweise auf Symbol unter Cursor hervorheben @@ -554,12 +554,12 @@ Highlight related _keywords under cursor - Highlight related _keywords under cursor + Verwandte _Schlüsselbegriffe unter Cursor anzeigen Highlighting - Highlighting + Hervorheben @@ -619,7 +619,7 @@ Insert Snippet - Insert Snippet + Schnipsel einfügen @@ -664,7 +664,7 @@ Large - Large + Groß @@ -914,12 +914,12 @@ Never - Never + Nie _Never add new line on enter - _Never add new line on enter + _Nie neue Zeile beim Drücken der EINGABETASTE einfügen @@ -929,7 +929,7 @@ Never include snippets - Never include snippets + Schnipsel nie einschließen @@ -979,7 +979,7 @@ Only add new line on enter after end of fully typed word - Only add new line on enter after end of fully typed word + Nach Drücken der EINGABETASTE nur nach dem Ende eines vollständigen Worts neue Zeile hinzufügen @@ -994,7 +994,7 @@ Optimize for solution size - Optimize for solution size + Für Lösungsgröße optimieren @@ -1079,7 +1079,7 @@ Performance - Performance + Leistung @@ -1189,7 +1189,7 @@ Prefer unbound generic type in 'nameof' - Prefer unbound generic type in 'nameof' + Ungebundenen generischen Typ in "nameof" bevorzugen @@ -1214,7 +1214,7 @@ Regular - Regular + Regulär @@ -1384,7 +1384,7 @@ Show "Remove Unused References" command in Solution Explorer - Show "Remove Unused References" command in Solution Explorer + Befehl „Nicht verwendete Verweise entfernen“ in Projektmappen-Explorer anzeigen @@ -1404,12 +1404,12 @@ Show completion item _filters - Show completion item _filters + Vervollständigungselement_filter anzeigen Show completion item filters - Show completion item filters + Vervollständigungselementfilter anzeigen @@ -1419,17 +1419,17 @@ Show completion list after a character is _deleted - Show completion list after a character is _deleted + Vervollstän_digungsliste nach Löschen eines Zeichens anzeigen Show completion list after a character is deleted - Show completion list after a character is deleted + Vervollständigungsliste nach Löschen eines Zeichens anzeigen Show completion list after a character is typed - Show completion list after a character is typed + Vervollständigungsliste nach Eingabe eines Zeichens anzeigen @@ -1479,22 +1479,22 @@ Show items from unimported namespaces - Show items from unimported namespaces + Elemente aus nicht importierten Namespaces anzeigen Show preview for rename _tracking - Show preview for rename _tracking + Vorschau für Nachverfolgung beim _Umbenennen anzeigen _Show procedure line separators - _Show procedure line separators + _Zeilentrennzeichen in Prozeduren anzeigen Show remarks in Quick Info - Show remarks in Quick Info + Hinweise in QuickInfo anzeigen @@ -1504,12 +1504,12 @@ Small - Small + Klein Snippets behavior - Snippets behavior + Schnipselverhalten @@ -1579,12 +1579,12 @@ Tab twice to insert arguments - Zweimaliges Drücken der TAB-Taste zum Einfügen von Argumenten (experimentell) + Drücken Sie zweimal die TAB-TASTE, um Argumente einzufügen. Tab twice to insert arguments (experimental) - Tab twice to insert arguments (experimental) + Zweimaliges Drücken der TAB-Taste zum Einfügen von Argumenten (experimentell) @@ -1629,7 +1629,7 @@ Title - Title + Titel @@ -1659,7 +1659,7 @@ Unused local - Unused local + Nicht verwendete lokale Variable @@ -1884,17 +1884,17 @@ _Highlight matching portions of completion list items - _Highlight matching portions of completion list items + _Übereinstimmende Teile der Vervollständigungslistenelemente anzeigen _Only add new line on enter after end of fully typed word - _Only add new line on enter after end of fully typed word + Neue _Zeile beim Drücken der EINGABETASTE nur nach einem vollständig eingegebenen Wort einfügen _Show completion list after a character is typed - _Show completion list after a character is typed + _Vervoll­ständigungsliste nach Eingabe eines Zeichens anzeigen diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf index 8c855ec9741af..b8925fa996154 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf @@ -74,7 +74,7 @@ _Always add new line on enter - _Always add new line on enter + _Agregar siempre una nueva línea al presionar Entrar @@ -139,7 +139,7 @@ Automatically reload updated analyzers and generators (requires restart) - Automatically reload updated analyzers and generators (requires restart) + Recargar automáticamente los analizadores y generadores actualizados (requiere reiniciar) @@ -394,7 +394,7 @@ Editor Help - Editor Help + Ayuda de editor @@ -434,12 +434,12 @@ Enter key behavior - Enter key behavior + Especificar el comportamiento de la clave Enter key behavior: - Enter key behavior: + Comportamiento de la tecla Entrar: @@ -464,7 +464,7 @@ Experimental feature - Experimental feature + Característica experimental @@ -484,7 +484,7 @@ Fade out unused members - Fade out unused members + Atenuar miembros no usados @@ -539,12 +539,12 @@ Highlight matching portions of completion list items - Highlight matching portions of completion list items + Resaltar partes coincidentes de elementos de la lista de finalización _Highlight references to symbol under cursor - _Highlight references to symbol under cursor + _Resaltar referencias al símbolo bajo el cursor @@ -554,12 +554,12 @@ Highlight related _keywords under cursor - Highlight related _keywords under cursor + Resaltar palabras cla_ve relacionadas bajo el cursor Highlighting - Highlighting + Resaltar @@ -619,7 +619,7 @@ Insert Snippet - Insert Snippet + Insertar fragmento de código @@ -664,7 +664,7 @@ Large - Large + Grande @@ -914,12 +914,12 @@ Never - Never + Nunca _Never add new line on enter - _Never add new line on enter + _No agregar nunca una nueva línea al presionar Entrar @@ -929,7 +929,7 @@ Never include snippets - Never include snippets + No incluir nunca fragmentos de código @@ -979,7 +979,7 @@ Only add new line on enter after end of fully typed word - Only add new line on enter after end of fully typed word + Solo agregar una nueva línea al pulsar Intro cuando se haya terminado de escribir completamente una palabra @@ -994,7 +994,7 @@ Optimize for solution size - Optimize for solution size + Optimizar para tamaño de la solución @@ -1079,7 +1079,7 @@ Performance - Performance + Rendimiento @@ -1189,7 +1189,7 @@ Prefer unbound generic type in 'nameof' - Prefer unbound generic type in 'nameof' + Preferir tipo genérico no enlazado en 'nameof' @@ -1214,7 +1214,7 @@ Regular - Regular + Normal @@ -1384,7 +1384,7 @@ Show "Remove Unused References" command in Solution Explorer - Show "Remove Unused References" command in Solution Explorer + Mostrar el comando "Quitar referencias sin usar" en Explorador de soluciones @@ -1404,12 +1404,12 @@ Show completion item _filters - Show completion item _filters + Mostrar _filtros de elementos de finalización Show completion item filters - Show completion item filters + Mostrar filtros de los elementos de finalización @@ -1419,17 +1419,17 @@ Show completion list after a character is _deleted - Show completion list after a character is _deleted + Mostrar lista de finalización después de _eliminar un carácter Show completion list after a character is deleted - Show completion list after a character is deleted + Mostrar lista de finalización después de eliminar un carácter Show completion list after a character is typed - Show completion list after a character is typed + Mostrar lista de finalización después de que se escriba un carácter @@ -1479,22 +1479,22 @@ Show items from unimported namespaces - Show items from unimported namespaces + Mostrar elementos de espacios de nombres no importados Show preview for rename _tracking - Show preview for rename _tracking + Mostrar vista previa para _seguimiento de cambio de nombre _Show procedure line separators - _Show procedure line separators + Mo_strar separadores de líneas de procedimientos Show remarks in Quick Info - Show remarks in Quick Info + Mostrar comentarios en Información rápida @@ -1504,12 +1504,12 @@ Small - Small + Pequeño Snippets behavior - Snippets behavior + Comportamiento de los fragmentos de código @@ -1579,12 +1579,12 @@ Tab twice to insert arguments - Presionar dos veces la tecla Tab para insertar argumentos (experimental) + Tabulación dos veces para insertar argumentos Tab twice to insert arguments (experimental) - Tab twice to insert arguments (experimental) + Presionar dos veces la tecla Tab para insertar argumentos (experimental) @@ -1629,7 +1629,7 @@ Title - Title + Título @@ -1659,7 +1659,7 @@ Unused local - Unused local + Local sin uso @@ -1884,17 +1884,17 @@ _Highlight matching portions of completion list items - _Highlight matching portions of completion list items + _Resaltar partes coincidentes de elementos de lista de finalización _Only add new line on enter after end of fully typed word - _Only add new line on enter after end of fully typed word + _Agregar solo una nueva línea con Entrar al final de palabras _Show completion list after a character is typed - _Show completion list after a character is typed + _Mostrar lista de finalización después de escribir un carácter diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf index 2c76bcd834834..c18156cf26e74 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf @@ -74,7 +74,7 @@ _Always add new line on enter - _Always add new line on enter + Toujours _ajouter une nouvelle ligne après Entrée @@ -139,7 +139,7 @@ Automatically reload updated analyzers and generators (requires restart) - Automatically reload updated analyzers and generators (requires restart) + Recharger automatiquement les analyseurs et les générateurs mis à jour (redémarrage nécessaire) @@ -394,7 +394,7 @@ Editor Help - Editor Help + Aide de l'éditeur @@ -434,12 +434,12 @@ Enter key behavior - Enter key behavior + Entrer le comportement de la touche Enter key behavior: - Enter key behavior: + Comportement de la touche Entrée : @@ -464,7 +464,7 @@ Experimental feature - Experimental feature + Fonctionnalité expérimentale @@ -484,7 +484,7 @@ Fade out unused members - Fade out unused members + Supprimer les membres inutilisés @@ -539,12 +539,12 @@ Highlight matching portions of completion list items - Highlight matching portions of completion list items + Mettre en surbrillance les parties correspondantes des éléments de liste de saisie semi-automatique _Highlight references to symbol under cursor - _Highlight references to symbol under cursor + _Surligner les références jusqu'au symbole sous le curseur @@ -554,12 +554,12 @@ Highlight related _keywords under cursor - Highlight related _keywords under cursor + Surligner les mots clés liés sous le _curseur Highlighting - Highlighting + Mise en surbrillance @@ -619,7 +619,7 @@ Insert Snippet - Insert Snippet + Insérer un extrait @@ -664,7 +664,7 @@ Large - Large + Grande @@ -914,12 +914,12 @@ Never - Never + Jamais _Never add new line on enter - _Never add new line on enter + _Ne jamais ajouter de nouvelle ligne après Entrée @@ -929,7 +929,7 @@ Never include snippets - Never include snippets + Ne jamais inclure d'extrait de code @@ -979,7 +979,7 @@ Only add new line on enter after end of fully typed word - Only add new line on enter after end of fully typed word + Ajouter une nouvelle ligne en appuyant sur Entrée seulement après la fin d'un mot entièrement tapé @@ -994,7 +994,7 @@ Optimize for solution size - Optimize for solution size + Optimiser pour la taille de la solution @@ -1079,7 +1079,7 @@ Performance - Performance + Performances @@ -1189,7 +1189,7 @@ Prefer unbound generic type in 'nameof' - Prefer unbound generic type in 'nameof' + Préférer le type générique indépendant dans 'nameof' @@ -1214,7 +1214,7 @@ Regular - Regular + Normal @@ -1384,7 +1384,7 @@ Show "Remove Unused References" command in Solution Explorer - Show "Remove Unused References" command in Solution Explorer + Afficher la commande « Supprimer les références inutilisées » dans l’Explorateur de solutions @@ -1404,12 +1404,12 @@ Show completion item _filters - Show completion item _filters + Afficher les _filtres d'éléments de saisie semi-automatique Show completion item filters - Show completion item filters + Afficher les filtres d'éléments de complétion @@ -1419,17 +1419,17 @@ Show completion list after a character is _deleted - Show completion list after a character is _deleted + Afficher la liste de saisie semi-automatique après la suppression d'un _caractère Show completion list after a character is deleted - Show completion list after a character is deleted + Afficher la liste de complétion après la suppression d'un caractère Show completion list after a character is typed - Show completion list after a character is typed + Afficher la liste de saisie semi-automatique après l'entrée d'un caractère @@ -1479,22 +1479,22 @@ Show items from unimported namespaces - Show items from unimported namespaces + Afficher les éléments des espaces de noms qui ne sont pas importés Show preview for rename _tracking - Show preview for rename _tracking + Affiche_r un aperçu pour le suivi des renommages _Show procedure line separators - _Show procedure line separators + _Afficher les séparateurs de ligne de procédure Show remarks in Quick Info - Show remarks in Quick Info + Afficher les notes dans Info express @@ -1504,12 +1504,12 @@ Small - Small + Petite Snippets behavior - Snippets behavior + Comportement des extraits de code @@ -1579,12 +1579,12 @@ Tab twice to insert arguments - Appuyer deux fois sur Tab pour insérer des arguments (expérimental) + Appuyez deux fois sur Tabulation pour insérer des arguments Tab twice to insert arguments (experimental) - Tab twice to insert arguments (experimental) + Appuyer deux fois sur Tab pour insérer des arguments (expérimental) @@ -1629,7 +1629,7 @@ Title - Title + Titre @@ -1659,7 +1659,7 @@ Unused local - Unused local + Local inutilisé @@ -1884,17 +1884,17 @@ _Highlight matching portions of completion list items - _Highlight matching portions of completion list items + _Mettre en surbrillance les parties correspondantes des éléments de liste de saisie semi-automatique _Only add new line on enter after end of fully typed word - _Only add new line on enter after end of fully typed word + Aj_outer uniquement une nouvelle ligne après Entrée à la fin d'un mot complet tapé _Show completion list after a character is typed - _Show completion list after a character is typed + _Afficher la liste de saisie semi-automatique après la saisie d'un caractère diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf index 6376f171c2eea..e52a2c0d8bfab 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf @@ -74,7 +74,7 @@ _Always add new line on enter - _Always add new line on enter + _Aggiungi sempre una nuova riga dopo INVIO @@ -139,7 +139,7 @@ Automatically reload updated analyzers and generators (requires restart) - Automatically reload updated analyzers and generators (requires restart) + Ricarica automaticamente analizzatori e generatori aggiornati (richiede il riavvio) @@ -394,7 +394,7 @@ Editor Help - Editor Help + Guida Editor @@ -434,12 +434,12 @@ Enter key behavior - Enter key behavior + Comportamento del tasto INVIO Enter key behavior: - Enter key behavior: + Comportamento del tasto INVIO: @@ -464,7 +464,7 @@ Experimental feature - Experimental feature + Funzionalità sperimentale @@ -484,7 +484,7 @@ Fade out unused members - Fade out unused members + Applica dissolvenza a direttive non usate @@ -539,12 +539,12 @@ Highlight matching portions of completion list items - Highlight matching portions of completion list items + Evidenzia le parti corrispondenti di voci dell'elenco di completamento _Highlight references to symbol under cursor - _Highlight references to symbol under cursor + _Evidenzia riferimenti a simbolo sotto il cursore @@ -554,12 +554,12 @@ Highlight related _keywords under cursor - Highlight related _keywords under cursor + Evidenzia _parole chiave correlate sotto il cursore Highlighting - Highlighting + Evidenziazione @@ -619,7 +619,7 @@ Insert Snippet - Insert Snippet + Inserisci frammento @@ -664,7 +664,7 @@ Large - Large + Grande @@ -914,12 +914,12 @@ Never - Never + Mai _Never add new line on enter - _Never add new line on enter + _Non aggiungere mai una nuova riga dopo INVIO @@ -929,7 +929,7 @@ Never include snippets - Never include snippets + Non includere mai i frammenti @@ -979,7 +979,7 @@ Only add new line on enter after end of fully typed word - Only add new line on enter after end of fully typed word + Aggiungi una nuova riga dopo INVIO solo alla fine della parola digitata @@ -994,7 +994,7 @@ Optimize for solution size - Optimize for solution size + Ottimizza in base alle dimensioni della soluzione @@ -1079,7 +1079,7 @@ Performance - Performance + Prestazioni @@ -1189,7 +1189,7 @@ Prefer unbound generic type in 'nameof' - Prefer unbound generic type in 'nameof' + Preferisci il tipo generico non associato in 'nameof' @@ -1214,7 +1214,7 @@ Regular - Regular + Normale @@ -1384,7 +1384,7 @@ Show "Remove Unused References" command in Solution Explorer - Show "Remove Unused References" command in Solution Explorer + Mostra il comando "Rimuovi riferimenti inutilizzati" in Esplora soluzioni @@ -1404,12 +1404,12 @@ Show completion item _filters - Show completion item _filters + Mostra i _filtri per le voci di completamento Show completion item filters - Show completion item filters + Mostra i filtri per le voci di completamento @@ -1419,17 +1419,17 @@ Show completion list after a character is _deleted - Show completion list after a character is _deleted + Mostra _elenco di completamento dopo l'eliminazione di un carattere Show completion list after a character is deleted - Show completion list after a character is deleted + Mostra elenco di completamento dopo l'eliminazione di un carattere Show completion list after a character is typed - Show completion list after a character is typed + Mostra elenco di completamento dopo la digitazione di un carattere @@ -1479,22 +1479,22 @@ Show items from unimported namespaces - Show items from unimported namespaces + Mostra elementi da spazi dei nomi non importati Show preview for rename _tracking - Show preview for rename _tracking + Mostra anteprima per verifica _ridenominazione _Show procedure line separators - _Show procedure line separators + _Mostra separatori di riga routine Show remarks in Quick Info - Show remarks in Quick Info + Mostra i commenti in Informazioni rapide @@ -1504,12 +1504,12 @@ Small - Small + Piccola Snippets behavior - Snippets behavior + Comportamento dei frammenti @@ -1579,12 +1579,12 @@ Tab twice to insert arguments - Premi due volte TAB per inserire gli argomenti (sperimentale) + Premi due volte TAB per inserire gli argomenti Tab twice to insert arguments (experimental) - Tab twice to insert arguments (experimental) + Premi due volte TAB per inserire gli argomenti (sperimentale) @@ -1629,7 +1629,7 @@ Title - Title + Titolo @@ -1659,7 +1659,7 @@ Unused local - Unused local + Variabile locale inutilizzata @@ -1884,17 +1884,17 @@ _Highlight matching portions of completion list items - _Highlight matching portions of completion list items + _Evidenzia le parti corrispondenti di voci dell'elenco di completamento _Only add new line on enter after end of fully typed word - _Only add new line on enter after end of fully typed word + Aggi_ungi una nuova riga dopo INVIO alla fine della parola digitata _Show completion list after a character is typed - _Show completion list after a character is typed + Mo_stra elenco di completamento dopo la digitazione di un carattere diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf index 5a23e1b1d3b8b..896b4913ef45a 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf @@ -74,7 +74,7 @@ _Always add new line on enter - _Always add new line on enter + Enter キーで常に新しい行を追加する(_A) @@ -139,7 +139,7 @@ Automatically reload updated analyzers and generators (requires restart) - Automatically reload updated analyzers and generators (requires restart) + 更新されたアナライザーとジェネレーターを自動的に再読み込みする (再起動が必要) @@ -394,7 +394,7 @@ Editor Help - Editor Help + エディターのヘルプ @@ -434,12 +434,12 @@ Enter key behavior - Enter key behavior + Enter キー入力時動作 Enter key behavior: - Enter key behavior: + Enter キー入力時動作: @@ -464,7 +464,7 @@ Experimental feature - Experimental feature + 試験的な機能 @@ -484,7 +484,7 @@ Fade out unused members - Fade out unused members + 未使用のメンバーをフェードアウトする @@ -539,12 +539,12 @@ Highlight matching portions of completion list items - Highlight matching portions of completion list items + 入力候補一覧の項目の一致している部分を強調表示する _Highlight references to symbol under cursor - _Highlight references to symbol under cursor + カーソルの下にあるシンボルへの参照をハイライトする(_H) @@ -554,12 +554,12 @@ Highlight related _keywords under cursor - Highlight related _keywords under cursor + カーソルの下にあるキーワードの関連キーワードをハイライトする(_K) Highlighting - Highlighting + 強調表示 @@ -619,7 +619,7 @@ Insert Snippet - Insert Snippet + スニペットの挿入 @@ -664,7 +664,7 @@ Large - Large + @@ -914,12 +914,12 @@ Never - Never + 行わない _Never add new line on enter - _Never add new line on enter + Enter キーで新しい行を追加しない(_N) @@ -929,7 +929,7 @@ Never include snippets - Never include snippets + スニペットを含めない @@ -979,7 +979,7 @@ Only add new line on enter after end of fully typed word - Only add new line on enter after end of fully typed word + 単語を完全に入力した後 Enter キーで新しい行のみを追加する @@ -994,7 +994,7 @@ Optimize for solution size - Optimize for solution size + ソリューションのサイズを最適化します @@ -1079,7 +1079,7 @@ Performance - Performance + パフォーマンス @@ -1189,7 +1189,7 @@ Prefer unbound generic type in 'nameof' - Prefer unbound generic type in 'nameof' + 'nameof' でバインドされていないジェネリック型を優先する @@ -1214,7 +1214,7 @@ Regular - Regular + 標準 @@ -1384,7 +1384,7 @@ Show "Remove Unused References" command in Solution Explorer - Show "Remove Unused References" command in Solution Explorer + ソリューション エクスプローラーで [未使用の参照を削除する] コマンドを表示する @@ -1404,12 +1404,12 @@ Show completion item _filters - Show completion item _filters + 入力候補の項目フィルターを表示する(_F) Show completion item filters - Show completion item filters + 入力候補の項目フィルターを表示する @@ -1419,17 +1419,17 @@ Show completion list after a character is _deleted - Show completion list after a character is _deleted + 文字が削除された後に入力候補一覧を表示する(_D) Show completion list after a character is deleted - Show completion list after a character is deleted + 文字が削除された後に入力候補一覧を表示する Show completion list after a character is typed - Show completion list after a character is typed + 文字入力後に入力候補一覧を表示する @@ -1479,22 +1479,22 @@ Show items from unimported namespaces - Show items from unimported namespaces + インポートされていない名前空間の項目を表示する Show preview for rename _tracking - Show preview for rename _tracking + 名前変更追跡のプレビューの表示(_T) _Show procedure line separators - _Show procedure line separators + プロシージャ行の区切り記号を表示する(_S) Show remarks in Quick Info - Show remarks in Quick Info + クイック ヒントに注釈を表示する @@ -1504,12 +1504,12 @@ Small - Small + Snippets behavior - Snippets behavior + スニペットの動作 @@ -1579,12 +1579,12 @@ Tab twice to insert arguments - タブを 2 回押して引数を挿入する (試験段階) + Tab キーを 2 回押して引数を挿入する Tab twice to insert arguments (experimental) - Tab twice to insert arguments (experimental) + タブを 2 回押して引数を挿入する (試験段階) @@ -1629,7 +1629,7 @@ Title - Title + タイトル @@ -1659,7 +1659,7 @@ Unused local - Unused local + 未使用のローカル @@ -1884,17 +1884,17 @@ _Highlight matching portions of completion list items - _Highlight matching portions of completion list items + 入力候補一覧の項目の一致している部分を強調表示する(_H) _Only add new line on enter after end of fully typed word - _Only add new line on enter after end of fully typed word + 単語を完全に入力した後 Enter キーで新しい行のみを追加する(_O) _Show completion list after a character is typed - _Show completion list after a character is typed + 文字が入力された後に入力候補一覧を表示する(_S) diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf index d026bc64ebfd6..d34d467819399 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf @@ -74,7 +74,7 @@ _Always add new line on enter - _Always add new line on enter + Enter 키를 누르면 항상 새 줄 추가(_A) @@ -139,7 +139,7 @@ Automatically reload updated analyzers and generators (requires restart) - Automatically reload updated analyzers and generators (requires restart) + 업데이트된 분석기 및 생성기를 자동으로 다시 로드(다시 시작해야 함) @@ -394,7 +394,7 @@ Editor Help - Editor Help + 편집기 도움말 @@ -434,12 +434,12 @@ Enter key behavior - Enter key behavior + 키 동작 입력 Enter key behavior: - Enter key behavior: + Enter 키 기능: @@ -464,7 +464,7 @@ Experimental feature - Experimental feature + 실험적 기능 @@ -484,7 +484,7 @@ Fade out unused members - Fade out unused members + 사용되지 않는 멤버 페이드 아웃 @@ -539,12 +539,12 @@ Highlight matching portions of completion list items - Highlight matching portions of completion list items + 완성 목록 항목의 일치하는 부분 강조 표시 _Highlight references to symbol under cursor - _Highlight references to symbol under cursor + 커서 아래의 기호에 대한 참조 강조(_H) @@ -554,12 +554,12 @@ Highlight related _keywords under cursor - Highlight related _keywords under cursor + 커서 아래의 관련 키워드 강조(_K) Highlighting - Highlighting + 강조 표시 @@ -619,7 +619,7 @@ Insert Snippet - Insert Snippet + 조각 삽입 @@ -664,7 +664,7 @@ Large - Large + 크게 @@ -914,12 +914,12 @@ Never - Never + 안 함 _Never add new line on enter - _Never add new line on enter + Enter 키를 누르면 새 줄 추가 안 함(_N) @@ -929,7 +929,7 @@ Never include snippets - Never include snippets + 코드 조각 포함 안 함 @@ -979,7 +979,7 @@ Only add new line on enter after end of fully typed word - Only add new line on enter after end of fully typed word + 단어를 모두 입력하고 Enter 키를 누르는 경우에만 새 줄 추가 @@ -994,7 +994,7 @@ Optimize for solution size - Optimize for solution size + 솔루션 크기에 맞게 최적화 @@ -1079,7 +1079,7 @@ Performance - Performance + 성능 @@ -1189,7 +1189,7 @@ Prefer unbound generic type in 'nameof' - Prefer unbound generic type in 'nameof' + 'nameof'에서 바인딩되지 않은 제네릭 형식 선호 @@ -1214,7 +1214,7 @@ Regular - Regular + 일반 @@ -1384,7 +1384,7 @@ Show "Remove Unused References" command in Solution Explorer - Show "Remove Unused References" command in Solution Explorer + 솔루션 탐색기에서 "사용하지 않는 참조 제거" 명령 표시 @@ -1404,12 +1404,12 @@ Show completion item _filters - Show completion item _filters + 완성 항목 필터 표시(_F) Show completion item filters - Show completion item filters + 완성 항목 필터 표시 @@ -1419,17 +1419,17 @@ Show completion list after a character is _deleted - Show completion list after a character is _deleted + 문자를 삭제하면 완성 목록 표시(_D) Show completion list after a character is deleted - Show completion list after a character is deleted + 문자를 삭제하면 완성 목록 표시 Show completion list after a character is typed - Show completion list after a character is typed + 문자를 입력하면 완성 목록 표시 @@ -1479,22 +1479,22 @@ Show items from unimported namespaces - Show items from unimported namespaces + 가져오지 않은 네임스페이스의 항목 표시 Show preview for rename _tracking - Show preview for rename _tracking + 이름 바꾸기 추적 미리 보기 표시(_T) _Show procedure line separators - _Show procedure line separators + 프로시저 줄 구분선 표시(_S) Show remarks in Quick Info - Show remarks in Quick Info + 요약 정보에 설명 표시 @@ -1504,12 +1504,12 @@ Small - Small + 작게 Snippets behavior - Snippets behavior + 코드 조각 동작 @@ -1579,12 +1579,12 @@ Tab twice to insert arguments - 두 번 탭하여 인수 삽입(실험적) + 탭을 두 번 탭하여 인수 삽입 Tab twice to insert arguments (experimental) - Tab twice to insert arguments (experimental) + 두 번 탭하여 인수 삽입(실험적) @@ -1629,7 +1629,7 @@ Title - Title + 제목 @@ -1659,7 +1659,7 @@ Unused local - Unused local + 사용하지 않는 로컬 @@ -1884,17 +1884,17 @@ _Highlight matching portions of completion list items - _Highlight matching portions of completion list items + 완성 목록 항목에서 일치하는 부분 강조 표시(_H) _Only add new line on enter after end of fully typed word - _Only add new line on enter after end of fully typed word + 단어를 모두 입력한 후 Enter 키를 누르면 새 줄 추가(_O) _Show completion list after a character is typed - _Show completion list after a character is typed + 문자를 입력하면 완성 목록 표시(_S) diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf index 06e0d25def339..55e1647cdf606 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf @@ -74,7 +74,7 @@ _Always add new line on enter - _Always add new line on enter + _Zawsze dodawaj nowy wiersz po naciśnięciu klawisza Enter @@ -139,7 +139,7 @@ Automatically reload updated analyzers and generators (requires restart) - Automatically reload updated analyzers and generators (requires restart) + Automatycznie załaduj ponownie zaktualizowane analizatory i generatory (wymaga ponownego uruchomienia) @@ -394,7 +394,7 @@ Editor Help - Editor Help + Pomoc edytora @@ -434,12 +434,12 @@ Enter key behavior - Enter key behavior + Zachowanie klawisza Enter Enter key behavior: - Enter key behavior: + Zachowanie klawisza Enter: @@ -464,7 +464,7 @@ Experimental feature - Experimental feature + Funkcja eksperymentalna @@ -484,7 +484,7 @@ Fade out unused members - Fade out unused members + Zanikanie nieużywanych elementów członkowskich @@ -539,12 +539,12 @@ Highlight matching portions of completion list items - Highlight matching portions of completion list items + Wyróżnij pasujące fragmenty elementów listy uzupełnień _Highlight references to symbol under cursor - _Highlight references to symbol under cursor + _Wyróżnij odwołania do symbolu pod kursorem @@ -554,12 +554,12 @@ Highlight related _keywords under cursor - Highlight related _keywords under cursor + Wyróżnij powiązane _słowa kluczowe pod kursorem Highlighting - Highlighting + Wyróżnianie @@ -619,7 +619,7 @@ Insert Snippet - Insert Snippet + Wstaw fragment kodu @@ -664,7 +664,7 @@ Large - Large + Duży @@ -914,12 +914,12 @@ Never - Never + Nigdy _Never add new line on enter - _Never add new line on enter + _Nigdy nie dodawaj nowego wiersza po naciśnięciu klawisza Enter @@ -929,7 +929,7 @@ Never include snippets - Never include snippets + Nigdy nie dołączaj fragmentów kodu @@ -979,7 +979,7 @@ Only add new line on enter after end of fully typed word - Only add new line on enter after end of fully typed word + Dodaj nowy wiersz tylko po naciśnięciu klawisza Enter na końcu w pełni wpisanego wyrazu @@ -994,7 +994,7 @@ Optimize for solution size - Optimize for solution size + Optymalizuj pod kątem rozmiaru rozwiązania @@ -1079,7 +1079,7 @@ Performance - Performance + Wydajność @@ -1189,7 +1189,7 @@ Prefer unbound generic type in 'nameof' - Prefer unbound generic type in 'nameof' + Preferuj niepowiązany typ ogólny w elem. "nameof" @@ -1214,7 +1214,7 @@ Regular - Regular + Standardowy @@ -1384,7 +1384,7 @@ Show "Remove Unused References" command in Solution Explorer - Show "Remove Unused References" command in Solution Explorer + Pokaż polecenie „Usuń nieużywane odwołania” w Eksploratorze rozwiązań @@ -1404,12 +1404,12 @@ Show completion item _filters - Show completion item _filters + Pokaż _filtry elementów uzupełniania Show completion item filters - Show completion item filters + Pokaż filtry elementów uzupełniania @@ -1419,17 +1419,17 @@ Show completion list after a character is _deleted - Show completion list after a character is _deleted + Pokaż listę _uzupełniania po usunięciu znaku Show completion list after a character is deleted - Show completion list after a character is deleted + Pokaż listę uzupełniania po usunięciu znaku Show completion list after a character is typed - Show completion list after a character is typed + Pokaż listę uzupełniania po wpisaniu znaku @@ -1479,22 +1479,22 @@ Show items from unimported namespaces - Show items from unimported namespaces + Pokaż elementy z nieimportowanych przestrzeni nazw Show preview for rename _tracking - Show preview for rename _tracking + Pokaż podgląd śledzenia _zmian nazw _Show procedure line separators - _Show procedure line separators + _Pokaż separatory wierszy procedury Show remarks in Quick Info - Show remarks in Quick Info + Pokaż uwagi w szybkich podpowiedziach @@ -1504,12 +1504,12 @@ Small - Small + Mały Snippets behavior - Snippets behavior + Zachowanie fragmentów kodu @@ -1579,12 +1579,12 @@ Tab twice to insert arguments - Dwukrotnie naciśnij klawisz Tab, aby wstawić argumenty (eksperymentalna) + Naciśnij dwukrotnie klawisz Tab, aby wstawić argumenty Tab twice to insert arguments (experimental) - Tab twice to insert arguments (experimental) + Dwukrotnie naciśnij klawisz Tab, aby wstawić argumenty (eksperymentalna) @@ -1629,7 +1629,7 @@ Title - Title + Tytuł @@ -1659,7 +1659,7 @@ Unused local - Unused local + Nieużywane zmienne lokalne @@ -1884,17 +1884,17 @@ _Highlight matching portions of completion list items - _Highlight matching portions of completion list items + _Wyróżnij pasujące fragmenty elementów listy uzupełniania _Only add new line on enter after end of fully typed word - _Only add new line on enter after end of fully typed word + _Dodaj nowy wiersz po naciśnięciu klawisza Enter tylko po zakończeniu pełnego wpisanego wyrazu _Show completion list after a character is typed - _Show completion list after a character is typed + _Pokaż listę uzupełniania po wpisaniu znaku diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf index e6f0b4637e8ac..a2d7f4d6e089c 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf @@ -74,7 +74,7 @@ _Always add new line on enter - _Always add new line on enter + _Sempre adicionar nova linha ao inserir @@ -139,7 +139,7 @@ Automatically reload updated analyzers and generators (requires restart) - Automatically reload updated analyzers and generators (requires restart) + Recarregar automaticamente os analisadores e geradores atualizados (requer reinicialização) @@ -394,7 +394,7 @@ Editor Help - Editor Help + Ajuda do Editor @@ -434,12 +434,12 @@ Enter key behavior - Enter key behavior + Inserir comportamento da tecla Enter key behavior: - Enter key behavior: + Insira o comportamento da tecla: @@ -464,7 +464,7 @@ Experimental feature - Experimental feature + Recurso experimental @@ -484,7 +484,7 @@ Fade out unused members - Fade out unused members + Esmaecer membros não utilizados @@ -539,12 +539,12 @@ Highlight matching portions of completion list items - Highlight matching portions of completion list items + Realçar partes correspondentes dos itens da lista de conclusão _Highlight references to symbol under cursor - _Highlight references to symbol under cursor + _Realçar referências a símbolo sob o cursor @@ -554,12 +554,12 @@ Highlight related _keywords under cursor - Highlight related _keywords under cursor + Realçar _palavras-chave relacionadas usando o cursor Highlighting - Highlighting + Destaque @@ -619,7 +619,7 @@ Insert Snippet - Insert Snippet + Inserir Snippet @@ -664,7 +664,7 @@ Large - Large + Grande @@ -914,12 +914,12 @@ Never - Never + Nunca _Never add new line on enter - _Never add new line on enter + _Nunca adicionar nova linha ao inserir @@ -929,7 +929,7 @@ Never include snippets - Never include snippets + Nunca incluir snippets @@ -979,7 +979,7 @@ Only add new line on enter after end of fully typed word - Only add new line on enter after end of fully typed word + Somente adiciona uma nova linha após digitar toda palavra @@ -994,7 +994,7 @@ Optimize for solution size - Optimize for solution size + Otimizar para o tamanho de solução @@ -1079,7 +1079,7 @@ Performance - Performance + Desempenho @@ -1189,7 +1189,7 @@ Prefer unbound generic type in 'nameof' - Prefer unbound generic type in 'nameof' + Preferir tipo genérico não associado em 'nameof' @@ -1214,7 +1214,7 @@ Regular - Regular + Normal @@ -1384,7 +1384,7 @@ Show "Remove Unused References" command in Solution Explorer - Show "Remove Unused References" command in Solution Explorer + Mostrar o comando "Remover Referências Não Utilizadas" no Gerenciador de Soluções @@ -1404,12 +1404,12 @@ Show completion item _filters - Show completion item _filters + Mostrar _filtros de itens de conclusão Show completion item filters - Show completion item filters + Mostrar filtros de itens de conclusão @@ -1419,17 +1419,17 @@ Show completion list after a character is _deleted - Show completion list after a character is _deleted + Mostrar lista de conclusão após um caractere ser _excluído Show completion list after a character is deleted - Show completion list after a character is deleted + Mostrar a lista de conclusão após um caractere ser excluído Show completion list after a character is typed - Show completion list after a character is typed + Mostrar lista de conclusão após um caractere ser digitado @@ -1479,22 +1479,22 @@ Show items from unimported namespaces - Show items from unimported namespaces + Mostrar os itens de namespaces não importados Show preview for rename _tracking - Show preview for rename _tracking + Mostrar visualização para acompanhamento de _renomeação _Show procedure line separators - _Show procedure line separators + _Mostrar separadores de linha de procedimento Show remarks in Quick Info - Show remarks in Quick Info + Mostrar os comentários nas Informações Rápidas @@ -1504,12 +1504,12 @@ Small - Small + Pequeno Snippets behavior - Snippets behavior + Comportamento de snippets @@ -1579,12 +1579,12 @@ Tab twice to insert arguments - Pressione Tab duas vezes para inserir argumentos (experimental) + Pressione Tab duas vezes para inserir argumentos Tab twice to insert arguments (experimental) - Tab twice to insert arguments (experimental) + Pressione Tab duas vezes para inserir argumentos (experimental) @@ -1629,7 +1629,7 @@ Title - Title + Título @@ -1659,7 +1659,7 @@ Unused local - Unused local + Local não usado @@ -1884,17 +1884,17 @@ _Highlight matching portions of completion list items - _Highlight matching portions of completion list items + _Realçar partes correspondentes dos itens da lista de conclusão _Only add new line on enter after end of fully typed word - _Only add new line on enter after end of fully typed word + _Só adicionar nova linha ao inserir depois do final de uma palavra totalmente digitada _Show completion list after a character is typed - _Show completion list after a character is typed + _Mostrar lista de conclusão depois que um caractere é digitado diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf index 06069b6ebb974..cfc4689581714 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf @@ -74,7 +74,7 @@ _Always add new line on enter - _Always add new line on enter + _Всегда добавлять символ новой строки при нажатии клавиши ВВОД @@ -139,7 +139,7 @@ Automatically reload updated analyzers and generators (requires restart) - Automatically reload updated analyzers and generators (requires restart) + Автоматически перезагружать обновленные анализаторы и генераторы (требуется перезагрузка) @@ -394,7 +394,7 @@ Editor Help - Editor Help + Справка по редактору @@ -434,12 +434,12 @@ Enter key behavior - Enter key behavior + Действие при нажатии клавиши ВВОД Enter key behavior: - Enter key behavior: + Поведение при нажатии клавиши ВВОД: @@ -464,7 +464,7 @@ Experimental feature - Experimental feature + Экспериментальная функция @@ -484,7 +484,7 @@ Fade out unused members - Fade out unused members + Постепенное исчезание неиспользуемых @@ -539,12 +539,12 @@ Highlight matching portions of completion list items - Highlight matching portions of completion list items + Выделять совпадающие части элементов списка завершения _Highlight references to symbol under cursor - _Highlight references to symbol under cursor + _Выделить ссылки на символ под курсором @@ -554,12 +554,12 @@ Highlight related _keywords under cursor - Highlight related _keywords under cursor + Выделить связанные _ключевые слова под курсором Highlighting - Highlighting + Выделение @@ -619,7 +619,7 @@ Insert Snippet - Insert Snippet + Вставить фрагмент @@ -664,7 +664,7 @@ Large - Large + Большой @@ -914,12 +914,12 @@ Never - Never + Никогда _Never add new line on enter - _Never add new line on enter + _Никогда не добавлять новую строку при нажатии клавиши ВВОД @@ -929,7 +929,7 @@ Never include snippets - Never include snippets + Никогда не включать фрагменты кода @@ -979,7 +979,7 @@ Only add new line on enter after end of fully typed word - Only add new line on enter after end of fully typed word + Добавлять только новую строку при нажатии клавиши ВВОД после полностью введенного слова @@ -994,7 +994,7 @@ Optimize for solution size - Optimize for solution size + Оптимизировать под размер решения @@ -1079,7 +1079,7 @@ Performance - Performance + Производительность @@ -1189,7 +1189,7 @@ Prefer unbound generic type in 'nameof' - Prefer unbound generic type in 'nameof' + Предпочитать не привязанный универсальный тип в "nameof" @@ -1214,7 +1214,7 @@ Regular - Regular + обычный @@ -1384,7 +1384,7 @@ Show "Remove Unused References" command in Solution Explorer - Show "Remove Unused References" command in Solution Explorer + Показывать команду "Удалить неиспользуемые ссылки" в Обозревателе решений @@ -1404,12 +1404,12 @@ Show completion item _filters - Show completion item _filters + Показывать фильтр_ы элементов завершения Show completion item filters - Show completion item filters + Показывать фильтры элементов завершения @@ -1419,17 +1419,17 @@ Show completion list after a character is _deleted - Show completion list after a character is _deleted + Показывать список завершения после удалени_я знака Show completion list after a character is deleted - Show completion list after a character is deleted + Показывать список завершения после удаления символа Show completion list after a character is typed - Show completion list after a character is typed + Показывать список завершения после ввода знака @@ -1479,22 +1479,22 @@ Show items from unimported namespaces - Show items from unimported namespaces + Отображать элементы из неимпортированных пространств имен Show preview for rename _tracking - Show preview for rename _tracking + Показывать предпросмотр для _отслеживания переименований _Show procedure line separators - _Show procedure line separators + _Показывать разделительные линии процедур Show remarks in Quick Info - Show remarks in Quick Info + Показать заметки в кратких сведениях @@ -1504,12 +1504,12 @@ Small - Small + Малый Snippets behavior - Snippets behavior + Поведение фрагментов кода @@ -1579,12 +1579,12 @@ Tab twice to insert arguments - Дважды нажмите клавишу TAB, чтобы вставить аргументы (экспериментальная функция) + Дважды нажмите клавишу TAB для вставки аргументов Tab twice to insert arguments (experimental) - Tab twice to insert arguments (experimental) + Дважды нажмите клавишу TAB, чтобы вставить аргументы (экспериментальная функция) @@ -1629,7 +1629,7 @@ Title - Title + Название @@ -1659,7 +1659,7 @@ Unused local - Unused local + Не использовать локальный аргумент @@ -1884,17 +1884,17 @@ _Highlight matching portions of completion list items - _Highlight matching portions of completion list items + _Выделять совпадающие части элементов списка завершения _Only add new line on enter after end of fully typed word - _Only add new line on enter after end of fully typed word + До_бавлять новую строку при нажатии клавиши ВВОД только в конце полностью введенного слова _Show completion list after a character is typed - _Show completion list after a character is typed + _Показывать список завершения после ввода знака diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf index 261bb85b7eee9..9ce8cfde61364 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf @@ -74,7 +74,7 @@ _Always add new line on enter - _Always add new line on enter + _Enter tuşuna basıldığında her zaman yeni satır ekle @@ -139,7 +139,7 @@ Automatically reload updated analyzers and generators (requires restart) - Automatically reload updated analyzers and generators (requires restart) + Güncelleştirilmiş çözümleyicileri ve oluşturucuları otomatik olarak yeniden yükle (yeniden başlatma gerektirir) @@ -394,7 +394,7 @@ Editor Help - Editor Help + Düzenleyici Yardımı @@ -434,12 +434,12 @@ Enter key behavior - Enter key behavior + Enter tuşu davranışı Enter key behavior: - Enter key behavior: + Enter tuşu davranışı: @@ -464,7 +464,7 @@ Experimental feature - Experimental feature + Deneysel özellik @@ -484,7 +484,7 @@ Fade out unused members - Fade out unused members + Kullanılmayan üyeleri soluklaştır @@ -539,12 +539,12 @@ Highlight matching portions of completion list items - Highlight matching portions of completion list items + Tamamlama listesi öğelerinin eşleşen bölümlerini vurgulayın _Highlight references to symbol under cursor - _Highlight references to symbol under cursor + İmlecin altındaki sembole başvuruları _vurgula @@ -554,12 +554,12 @@ Highlight related _keywords under cursor - Highlight related _keywords under cursor + İmlecin altında ilgili ana_htar sözcükleri vurgula Highlighting - Highlighting + Vurgulama @@ -619,7 +619,7 @@ Insert Snippet - Insert Snippet + Kod Parçacığı Ekle @@ -664,7 +664,7 @@ Large - Large + Büyük @@ -914,12 +914,12 @@ Never - Never + Hiçbir zaman _Never add new line on enter - _Never add new line on enter + Enter tuşuna basıldığında _hiçbir zaman yeni satır ekleme @@ -929,7 +929,7 @@ Never include snippets - Never include snippets + Kod parçacıklarını hiçbir zaman dahil etme @@ -979,7 +979,7 @@ Only add new line on enter after end of fully typed word - Only add new line on enter after end of fully typed word + Yalnızca tam olarak yazılmış bir kelimeden sonra Enter'a basıldığında yeni satır ekle @@ -994,7 +994,7 @@ Optimize for solution size - Optimize for solution size + Çözüm boyutunu iyileştir @@ -1079,7 +1079,7 @@ Performance - Performance + Performans @@ -1189,7 +1189,7 @@ Prefer unbound generic type in 'nameof' - Prefer unbound generic type in 'nameof' + 'nameof' içinde bağlı olmayan genel türü tercih eder @@ -1214,7 +1214,7 @@ Regular - Regular + Normal @@ -1384,7 +1384,7 @@ Show "Remove Unused References" command in Solution Explorer - Show "Remove Unused References" command in Solution Explorer + Çözüm Gezgini'nde "Kullanılmayan Başvuruları Kaldır" komutunu göster @@ -1404,12 +1404,12 @@ Show completion item _filters - Show completion item _filters + Tamamlanma öğesi _filtrelerini göster Show completion item filters - Show completion item filters + Tamamlanma öğesi filtrelerini göster @@ -1419,17 +1419,17 @@ Show completion list after a character is _deleted - Show completion list after a character is _deleted + Bir karakter _silindikten sonra tamamlanma listesini göster Show completion list after a character is deleted - Show completion list after a character is deleted + Bir karakter silindikten sonra tamamlanma listesini göster Show completion list after a character is typed - Show completion list after a character is typed + Bir karakter girildikten sonra tamamlama listesini göster @@ -1479,22 +1479,22 @@ Show items from unimported namespaces - Show items from unimported namespaces + İçeri aktarılmayan ad alanlarındaki öğeleri göster Show preview for rename _tracking - Show preview for rename _tracking + Yeniden adlandırma i_zlemesi için önizleme göster _Show procedure line separators - _Show procedure line separators + Yordam satır ayıraçlarını _göster Show remarks in Quick Info - Show remarks in Quick Info + Hızlı Bilgi notlarını göster @@ -1504,12 +1504,12 @@ Small - Small + Küçük Snippets behavior - Snippets behavior + Kod parçacığı davranışı @@ -1579,12 +1579,12 @@ Tab twice to insert arguments - Bağımsız değişkenleri eklemek için iki kez dokunun (deneysel) + Bağımsız değişkenleri eklemek için iki kez dokunun Tab twice to insert arguments (experimental) - Tab twice to insert arguments (experimental) + Bağımsız değişkenleri eklemek için iki kez dokunun (deneysel) @@ -1629,7 +1629,7 @@ Title - Title + Başlık @@ -1659,7 +1659,7 @@ Unused local - Unused local + Kullanılmayan yerel @@ -1884,17 +1884,17 @@ _Highlight matching portions of completion list items - _Highlight matching portions of completion list items + Tamamlanma listesi öğelerinin eşleşen bölümlerini _vurgula _Only add new line on enter after end of fully typed word - _Only add new line on enter after end of fully typed word + _Enter tuşuna basıldığında yalnızca tam bir kelime yazılmışsa sonuna yeni satır ekle _Show completion list after a character is typed - _Show completion list after a character is typed + Bir karakter yazıldıktan sonra tamamlanma listesini _göster diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf index 7888cc5d17df1..ff48e337c2b3a 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf @@ -74,7 +74,7 @@ _Always add new line on enter - _Always add new line on enter + 始终在按下 Enter 时添加新行(_A) @@ -139,7 +139,7 @@ Automatically reload updated analyzers and generators (requires restart) - Automatically reload updated analyzers and generators (requires restart) + 自动重新加载更新的分析器和生成器 (需要重启) @@ -394,7 +394,7 @@ Editor Help - Editor Help + 编辑器帮助 @@ -434,12 +434,12 @@ Enter key behavior - Enter key behavior + 回车键的行为 Enter key behavior: - Enter key behavior: + 输入关键行为: @@ -464,7 +464,7 @@ Experimental feature - Experimental feature + 实验性功能 @@ -484,7 +484,7 @@ Fade out unused members - Fade out unused members + 淡出未使用的成员 @@ -539,12 +539,12 @@ Highlight matching portions of completion list items - Highlight matching portions of completion list items + 突出显示完成列表项的匹配部分 _Highlight references to symbol under cursor - _Highlight references to symbol under cursor + 突出显示对光标下符号的引用(_H) @@ -554,12 +554,12 @@ Highlight related _keywords under cursor - Highlight related _keywords under cursor + 突出显示光标下相关的关键字(_K) Highlighting - Highlighting + 突出显示 @@ -619,7 +619,7 @@ Insert Snippet - Insert Snippet + 插入片段 @@ -664,7 +664,7 @@ Large - Large + @@ -914,12 +914,12 @@ Never - Never + 从不 _Never add new line on enter - _Never add new line on enter + 按下 Enter 时不添加新行(_N) @@ -929,7 +929,7 @@ Never include snippets - Never include snippets + 从不包含片段 @@ -979,7 +979,7 @@ Only add new line on enter after end of fully typed word - Only add new line on enter after end of fully typed word + 只在键入完整的单词后点击回车后才添加新行 @@ -994,7 +994,7 @@ Optimize for solution size - Optimize for solution size + 优化解决方案大小 @@ -1079,7 +1079,7 @@ Performance - Performance + 性能 @@ -1189,7 +1189,7 @@ Prefer unbound generic type in 'nameof' - Prefer unbound generic type in 'nameof' + 首选 “nameof” 中的未绑定泛型类型 @@ -1214,7 +1214,7 @@ Regular - Regular + 常规 @@ -1384,7 +1384,7 @@ Show "Remove Unused References" command in Solution Explorer - Show "Remove Unused References" command in Solution Explorer + 在解决方案资源管理器中显示“删除未使用的引用”命令 @@ -1404,12 +1404,12 @@ Show completion item _filters - Show completion item _filters + 显示完成项筛选器(_F) Show completion item filters - Show completion item filters + 显示完成项筛选器 @@ -1419,17 +1419,17 @@ Show completion list after a character is _deleted - Show completion list after a character is _deleted + 删除字符后显示完成列表(_D) Show completion list after a character is deleted - Show completion list after a character is deleted + 删除字符后显示完成列表 Show completion list after a character is typed - Show completion list after a character is typed + 键入字符后显示完成列表 @@ -1479,22 +1479,22 @@ Show items from unimported namespaces - Show items from unimported namespaces + 显示 unimported 命名空间中的项 Show preview for rename _tracking - Show preview for rename _tracking + 显示重命名跟踪的预览(_T) _Show procedure line separators - _Show procedure line separators + 显示过程行分隔符(_S) Show remarks in Quick Info - Show remarks in Quick Info + 在快速信息中显示备注 @@ -1504,12 +1504,12 @@ Small - Small + Snippets behavior - Snippets behavior + 片段行为 @@ -1579,12 +1579,12 @@ Tab twice to insert arguments - 按两次 Tab 以插入参数(实验性) + 按两次 Tab 键以插入参数 Tab twice to insert arguments (experimental) - Tab twice to insert arguments (experimental) + 按两次 Tab 以插入参数(实验性) @@ -1629,7 +1629,7 @@ Title - Title + 标题 @@ -1659,7 +1659,7 @@ Unused local - Unused local + 未使用的本地 @@ -1884,17 +1884,17 @@ _Highlight matching portions of completion list items - _Highlight matching portions of completion list items + 突出显示完成列表项的匹配部分(_H) _Only add new line on enter after end of fully typed word - _Only add new line on enter after end of fully typed word + _只有在完整键入的单词结尾后按下回车键时才添加新行 _Show completion list after a character is typed - _Show completion list after a character is typed + 键入字符后显示完成列表(_S) diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf index 0d7c6d13f70c1..56d0e84396116 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf @@ -74,7 +74,7 @@ _Always add new line on enter - _Always add new line on enter + 一律在按下 Enter 鍵時加入新行(_A) @@ -139,7 +139,7 @@ Automatically reload updated analyzers and generators (requires restart) - Automatically reload updated analyzers and generators (requires restart) + 自動重載更新的分析器和產生器 (需要重新啟動) @@ -394,7 +394,7 @@ Editor Help - Editor Help + 編輯器說明 @@ -434,12 +434,12 @@ Enter key behavior - Enter key behavior + ENTER 鍵行為 Enter key behavior: - Enter key behavior: + Enter 鍵行為: @@ -464,7 +464,7 @@ Experimental feature - Experimental feature + 實驗性功能 @@ -484,7 +484,7 @@ Fade out unused members - Fade out unused members + 淡出未使用的成員 @@ -539,12 +539,12 @@ Highlight matching portions of completion list items - Highlight matching portions of completion list items + 醒目提示自動完成清單項目的相符部分 _Highlight references to symbol under cursor - _Highlight references to symbol under cursor + 反白顯示資料指標下符號的參考項目(_H) @@ -554,12 +554,12 @@ Highlight related _keywords under cursor - Highlight related _keywords under cursor + 反白資料指標下的相關關鍵字(_K) Highlighting - Highlighting + 反白 @@ -619,7 +619,7 @@ Insert Snippet - Insert Snippet + 插入程式碼片段 @@ -664,7 +664,7 @@ Large - Large + @@ -914,12 +914,12 @@ Never - Never + 永不 _Never add new line on enter - _Never add new line on enter + 永不在按下 Enter 鍵時加入新行(_N) @@ -929,7 +929,7 @@ Never include snippets - Never include snippets + 一律不包含程式碼片段 @@ -979,7 +979,7 @@ Only add new line on enter after end of fully typed word - Only add new line on enter after end of fully typed word + 只在完整鍵入字的結尾處按 ENTER 來新增新行 @@ -994,7 +994,7 @@ Optimize for solution size - Optimize for solution size + 最佳化方案大小 @@ -1079,7 +1079,7 @@ Performance - Performance + 效能 @@ -1189,7 +1189,7 @@ Prefer unbound generic type in 'nameof' - Prefer unbound generic type in 'nameof' + 優先使用 『nameof』 中的未系結泛型型別 @@ -1214,7 +1214,7 @@ Regular - Regular + 一般 @@ -1384,7 +1384,7 @@ Show "Remove Unused References" command in Solution Explorer - Show "Remove Unused References" command in Solution Explorer + 在方案總管中顯示「移除未使用的參考」命令 @@ -1404,12 +1404,12 @@ Show completion item _filters - Show completion item _filters + 顯示完成項目篩選(_F) Show completion item filters - Show completion item filters + 顯示完成項目篩選 @@ -1419,17 +1419,17 @@ Show completion list after a character is _deleted - Show completion list after a character is _deleted + 刪除一個字元後顯示完成清單(_D) Show completion list after a character is deleted - Show completion list after a character is deleted + 刪除字元後顯示自動完成清單 Show completion list after a character is typed - Show completion list after a character is typed + 在輸入的字元後方顯示完成清單 @@ -1479,22 +1479,22 @@ Show items from unimported namespaces - Show items from unimported namespaces + 顯示來自未匯入命名空間的項目 Show preview for rename _tracking - Show preview for rename _tracking + 顯示預覽以追蹤重新命名(_T) _Show procedure line separators - _Show procedure line separators + 顯示程序行分隔符號(_S) Show remarks in Quick Info - Show remarks in Quick Info + 在快速諮詢中顯示備註 @@ -1504,12 +1504,12 @@ Small - Small + Snippets behavior - Snippets behavior + 程式碼片段行為 @@ -1579,12 +1579,12 @@ Tab twice to insert arguments - 按 Tab 鍵兩次可插入引數 (實驗性) + 按鍵兩次以插入引數 Tab twice to insert arguments (experimental) - Tab twice to insert arguments (experimental) + 按 Tab 鍵兩次可插入引數 (實驗性) @@ -1629,7 +1629,7 @@ Title - Title + 標題 @@ -1659,7 +1659,7 @@ Unused local - Unused local + 未使用的區域函式 @@ -1884,17 +1884,17 @@ _Highlight matching portions of completion list items - _Highlight matching portions of completion list items + 反白完成清單項目的相符部分(_H) _Only add new line on enter after end of fully typed word - _Only add new line on enter after end of fully typed word + 僅在完整輸入的字結尾處按 Enter 鍵時加入新行(_O) _Show completion list after a character is typed - _Show completion list after a character is typed + 輸入一個字元後顯示完成清單(_S) diff --git a/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelObject_CodeGen.cs b/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelObject_CodeGen.cs index e3dee51e8da54..b14e52da56eb4 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelObject_CodeGen.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelObject_CodeGen.cs @@ -7,7 +7,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editing; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel { diff --git a/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs b/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs index 5fd11bf5fc331..ea55acb4d8aad 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; diff --git a/src/VisualStudio/Core/Impl/CodeModel/Collections/ExternalNamespaceCollection.cs b/src/VisualStudio/Core/Impl/CodeModel/Collections/ExternalNamespaceCollection.cs index 744f0fd55967e..a9e38b50e94e5 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/Collections/ExternalNamespaceCollection.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/Collections/ExternalNamespaceCollection.cs @@ -6,7 +6,6 @@ using System.Collections.Immutable; using System.Runtime.InteropServices; -using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel.Interop; diff --git a/src/VisualStudio/Core/Impl/CodeModel/Collections/InheritsImplementsCollection.cs b/src/VisualStudio/Core/Impl/CodeModel/Collections/InheritsImplementsCollection.cs index 6cbdce8d418bb..7573eb4ac4957 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/Collections/InheritsImplementsCollection.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/Collections/InheritsImplementsCollection.cs @@ -8,7 +8,6 @@ using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; -using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel.InternalElements; using Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel.Interop; diff --git a/src/VisualStudio/Core/Impl/CodeModel/Collections/NamespaceCollection.cs b/src/VisualStudio/Core/Impl/CodeModel/Collections/NamespaceCollection.cs index 99fa14ff50151..a0ba0527b6bb9 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/Collections/NamespaceCollection.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/Collections/NamespaceCollection.cs @@ -8,7 +8,6 @@ using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; -using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel.InternalElements; using Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel.Interop; diff --git a/src/VisualStudio/Core/Impl/CodeModel/Collections/TypeCollection.cs b/src/VisualStudio/Core/Impl/CodeModel/Collections/TypeCollection.cs index c083e1a7863be..afad54777d0da 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/Collections/TypeCollection.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/Collections/TypeCollection.cs @@ -8,7 +8,6 @@ using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; -using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel.InternalElements; using Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel.Interop; diff --git a/src/VisualStudio/Core/Impl/CodeModel/FileCodeModel.cs b/src/VisualStudio/Core/Impl/CodeModel/FileCodeModel.cs index d4de1304ce2e1..b0f2fbbc027e7 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/FileCodeModel.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/FileCodeModel.cs @@ -15,7 +15,6 @@ using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.LanguageService; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; using Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel.Collections; diff --git a/src/VisualStudio/Core/Impl/CodeModel/FileCodeModel_CodeGen.cs b/src/VisualStudio/Core/Impl/CodeModel/FileCodeModel_CodeGen.cs index d0658ab9ef87e..424e20e536cea 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/FileCodeModel_CodeGen.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/FileCodeModel_CodeGen.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Diagnostics; using System.Runtime.InteropServices; using System.Threading; @@ -13,7 +12,6 @@ using Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel.Interop; using Microsoft.VisualStudio.LanguageServices.Implementation.Interop; using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel { diff --git a/src/VisualStudio/Core/Impl/CodeModel/InternalElements/AbstractCodeElement.cs b/src/VisualStudio/Core/Impl/CodeModel/InternalElements/AbstractCodeElement.cs index de85623793764..5bb1f6c9100c8 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/InternalElements/AbstractCodeElement.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/InternalElements/AbstractCodeElement.cs @@ -10,7 +10,6 @@ using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.LanguageServices.Implementation.Interop; using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; diff --git a/src/VisualStudio/Core/Impl/CodeModel/ProjectCodeModelFactory.cs b/src/VisualStudio/Core/Impl/CodeModel/ProjectCodeModelFactory.cs index e27de36eb5a39..a857e351523db 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/ProjectCodeModelFactory.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/ProjectCodeModelFactory.cs @@ -15,8 +15,8 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageService; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Threading; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Threading; using Roslyn.Utilities; diff --git a/src/VisualStudio/Core/Impl/Options/Style/EnumCodeStyleOptionViewModel.cs b/src/VisualStudio/Core/Impl/Options/Style/EnumCodeStyleOptionViewModel.cs index b8156f7ce1f45..2943777c92018 100644 --- a/src/VisualStudio/Core/Impl/Options/Style/EnumCodeStyleOptionViewModel.cs +++ b/src/VisualStudio/Core/Impl/Options/Style/EnumCodeStyleOptionViewModel.cs @@ -8,9 +8,9 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Linq; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Options; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options { 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 c9c3231aa5756..91a28bdbf9061 100644 --- a/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/NamingStyleOptionPageControl.xaml.cs +++ b/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/NamingStyleOptionPageControl.xaml.cs @@ -5,7 +5,6 @@ #nullable disable using System; -using System.Collections.ObjectModel; using System.Linq; using System.Windows; using System.Windows.Controls; diff --git a/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/NamingStyleOptionPageViewModel.cs b/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/NamingStyleOptionPageViewModel.cs index f4c3f6d972b2c..cd049428c31f7 100644 --- a/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/NamingStyleOptionPageViewModel.cs +++ b/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/NamingStyleOptionPageViewModel.cs @@ -5,7 +5,6 @@ #nullable disable using System.Collections.Generic; -using System.Collections.Immutable; using System.Collections.ObjectModel; using System.Linq; using Microsoft.CodeAnalysis.CodeStyle; diff --git a/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/SymbolSpecification/SymbolSpecificationViewModel.cs b/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/SymbolSpecification/SymbolSpecificationViewModel.cs index 31f4331490dc8..1784abcef5595 100644 --- a/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/SymbolSpecification/SymbolSpecificationViewModel.cs +++ b/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/SymbolSpecification/SymbolSpecificationViewModel.cs @@ -6,7 +6,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItem/AnalyzerItemSource.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItem/AnalyzerItemSource.cs index 7db53244947e0..53641c4e9701c 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItem/AnalyzerItemSource.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItem/AnalyzerItemSource.cs @@ -5,7 +5,6 @@ using System.Collections; using System.Collections.Generic; using System.Collections.Immutable; -using System.ComponentModel; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -16,6 +15,7 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.SourceGeneration; +using Microsoft.CodeAnalysis.Threading; using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Shell; using Roslyn.Utilities; diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerReferenceManager.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerReferenceManager.cs index 453f8f4ed10d1..0a1e4f4097683 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerReferenceManager.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerReferenceManager.cs @@ -4,11 +4,11 @@ using System; using System.ComponentModel.Composition; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; -using Roslyn.Utilities; using VSLangProj140; namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/BaseDiagnosticAndGeneratorItemSource.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/BaseDiagnosticAndGeneratorItemSource.cs index 09c14500e946e..2197f03fa4d48 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/BaseDiagnosticAndGeneratorItemSource.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/BaseDiagnosticAndGeneratorItemSource.cs @@ -15,6 +15,7 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.SourceGeneration; +using Microsoft.CodeAnalysis.Threading; using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Shell; using Roslyn.Utilities; diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/DiagnosticItem.BrowseObject.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/DiagnosticItem.BrowseObject.cs index 14e0d8ba9f9c8..4c1ba0a29a603 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/DiagnosticItem.BrowseObject.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/DiagnosticItem.BrowseObject.cs @@ -7,7 +7,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.VisualStudio.Shell; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer; diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/SourceGeneratedFileItems/SourceGeneratedFileItemSource.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/SourceGeneratedFileItems/SourceGeneratedFileItemSource.cs index 96bc24025d51c..216cf417590c7 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/SourceGeneratedFileItems/SourceGeneratedFileItemSource.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/SourceGeneratedFileItems/SourceGeneratedFileItemSource.cs @@ -12,9 +12,9 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Threading; using Microsoft.Internal.VisualStudio.PlatformUI; using Microsoft.VisualStudio.Language.Intellisense; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer; diff --git a/src/VisualStudio/Core/Test.Next/Remote/SnapshotSerializationTests.cs b/src/VisualStudio/Core/Test.Next/Remote/SnapshotSerializationTests.cs index 95062848499db..dddf16ee0e17a 100644 --- a/src/VisualStudio/Core/Test.Next/Remote/SnapshotSerializationTests.cs +++ b/src/VisualStudio/Core/Test.Next/Remote/SnapshotSerializationTests.cs @@ -701,12 +701,13 @@ private static AnalyzerFileReference CreateShadowCopiedAnalyzerReference(TempRoo return new AnalyzerFileReference(original, new MockShadowCopyAnalyzerAssemblyLoader(ImmutableDictionary.Empty.Add(original, shadow.Path))); } - private class MissingAnalyzerLoader() : AnalyzerAssemblyLoader([]) + private class MissingAnalyzerLoader() : IAnalyzerAssemblyLoader { - protected override string PreparePathToLoad(string fullPath) - => throw new FileNotFoundException(fullPath); + public void AddDependencyLocation(string fullPath) + { + } - protected override string PrepareSatelliteAssemblyToLoad(string fullPath, string cultureName) + public Assembly LoadFromPath(string fullPath) => throw new FileNotFoundException(fullPath); } diff --git a/src/VisualStudio/Core/Test.Next/Roslyn.VisualStudio.Next.UnitTests.csproj b/src/VisualStudio/Core/Test.Next/Roslyn.VisualStudio.Next.UnitTests.csproj index ffd478efc1217..3573c500702b9 100644 --- a/src/VisualStudio/Core/Test.Next/Roslyn.VisualStudio.Next.UnitTests.csproj +++ b/src/VisualStudio/Core/Test.Next/Roslyn.VisualStudio.Next.UnitTests.csproj @@ -71,8 +71,4 @@ - - - - \ No newline at end of file diff --git a/src/VisualStudio/Core/Test.Next/Services/AssetProviderTests.cs b/src/VisualStudio/Core/Test.Next/Services/AssetProviderTests.cs index 06f61fddcb5f2..b9908670866a8 100644 --- a/src/VisualStudio/Core/Test.Next/Services/AssetProviderTests.cs +++ b/src/VisualStudio/Core/Test.Next/Services/AssetProviderTests.cs @@ -17,6 +17,7 @@ using Microsoft.CodeAnalysis.Remote.Testing; using Microsoft.CodeAnalysis.Serialization; using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Utilities; using Xunit; diff --git a/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs b/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs index 2626d6f12bbf8..f061e876b2ab5 100644 --- a/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs +++ b/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs @@ -95,7 +95,7 @@ public async Task TestRemoteHostTextSynchronize() // sync await client.TryInvokeAsync( - (service, cancellationToken) => service.SynchronizeTextChangesAsync([(oldDocument.Id, oldState.Text, newText.GetTextChanges(oldText).AsImmutable(), newState.Text)], cancellationToken), + (service, cancellationToken) => service.SynchronizeTextChangesAsync(oldDocument.Id, oldState.Text, newText.GetTextChanges(oldText).AsImmutable(), newState.Text, cancellationToken), CancellationToken.None); // check that text already exist in remote side diff --git a/src/VisualStudio/Core/Test.Next/Services/SolutionServiceTests.cs b/src/VisualStudio/Core/Test.Next/Services/SolutionServiceTests.cs index 80ffa6718ef66..a744a24102c82 100644 --- a/src/VisualStudio/Core/Test.Next/Services/SolutionServiceTests.cs +++ b/src/VisualStudio/Core/Test.Next/Services/SolutionServiceTests.cs @@ -15,7 +15,6 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.Test; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Remote.Testing; using Microsoft.CodeAnalysis.Serialization; diff --git a/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs b/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs index b5c05e9dfb7c7..425004234ef26 100644 --- a/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs +++ b/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs @@ -62,8 +62,7 @@ void Method() Assert.Equal(isHostAnalyzer ? DiagnosticSeverity.Info : DiagnosticSeverity.Hidden, diagnostics[0].Severity); } - [Theory] - [CombinatorialData] + [Theory, CombinatorialData] public async Task TestVisualBasicAnalyzerOptions(bool isHostAnalyzer) { var code = @"Class Test @@ -83,7 +82,7 @@ End Sub ImmutableArray diagnostics; if (isHostAnalyzer) { - Assert.True(analyzerResult.IsEmpty); + Assert.True(analyzerResult.GetAllDiagnostics().IsEmpty); } else { diff --git a/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Input.cs b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Input.cs index fd4cb12b0bb53..e48091aca7ab9 100644 --- a/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Input.cs +++ b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Input.cs @@ -5,7 +5,6 @@ using System.Text.Json.Serialization; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Options; -using Roslyn.Utilities; using Xunit; using static Microsoft.VisualStudio.LanguageServices.Options.VisualStudioOptionStorage; diff --git a/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Utilities.cs b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Utilities.cs index 01a816265e1c2..1287a12ab69bc 100644 --- a/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Utilities.cs +++ b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Utilities.cs @@ -4,9 +4,9 @@ using System; using System.Globalization; +using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.LanguageServices; using Microsoft.VisualStudio.LanguageServices.CSharp; -using Roslyn.Utilities; using CSharpPackage = Microsoft.VisualStudio.LanguageServices.CSharp.VSPackage; using VisualBasicPackage = Microsoft.VisualStudio.LanguageServices.VisualBasic.VSPackage; diff --git a/src/VisualStudio/Core/Test/ClassView/MockVsServiceProvider.vb b/src/VisualStudio/Core/Test/ClassView/MockVsServiceProvider.vb index 10b5a08695ac7..0921df8013f73 100644 --- a/src/VisualStudio/Core/Test/ClassView/MockVsServiceProvider.vb +++ b/src/VisualStudio/Core/Test/ClassView/MockVsServiceProvider.vb @@ -2,9 +2,9 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. +Imports Microsoft.CodeAnalysis Imports Microsoft.VisualStudio.Shell Imports Microsoft.VisualStudio.Shell.Interop -Imports Roslyn.Utilities Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ClassView Friend Class MockServiceProvider diff --git a/src/VisualStudio/Core/Test/DebuggerIntelliSense/CSharpDebuggerIntellisenseTests.vb b/src/VisualStudio/Core/Test/DebuggerIntelliSense/CSharpDebuggerIntellisenseTests.vb index ad273f10ae86a..30999902e27b7 100644 --- a/src/VisualStudio/Core/Test/DebuggerIntelliSense/CSharpDebuggerIntellisenseTests.vb +++ b/src/VisualStudio/Core/Test/DebuggerIntelliSense/CSharpDebuggerIntellisenseTests.vb @@ -315,6 +315,52 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.DebuggerIntelliSense End Using End Function + + Public Async Function SingleStatementBlock() As Task + Dim text = + + class Program +{ + static void Main() + { + for (int variable1 = 0; variable1 < 10; variable1++) + [|Console.Write(0);|] + int variable2 = 0; + } +} + + + + Using state = TestState.CreateCSharpTestState(text, False) + state.SendTypeChars("variable") + Await state.WaitForAsynchronousOperationsAsync() + Await state.AssertCompletionItemsContainAll("variable1", "variable2") + End Using + End Function + + + Public Async Function SingleStatementBlockInvokeCompletion() As Task + Dim text = + + class Program +{ + static void Main() + { + for (int variable1 = 0; variable1 < 10; variable1++) + [|Console.Write(0);|] + int variable2 = 0; + } +} + + + + Using state = TestState.CreateCSharpTestState(text, False) + Await state.WaitForAsynchronousOperationsAsync() + state.SendInvokeCompletionList() + Await state.AssertCompletionItemsContainAll("variable1") + End Using + End Function + Public Async Function SignatureHelpInParameterizedConstructor() As Task Dim text = diff --git a/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb b/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb index 71428bfca2712..9476f840de109 100644 --- a/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb +++ b/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb @@ -52,7 +52,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics Dim threadingContext = workspace.ExportProvider.GetExport(Of IThreadingContext).Value - Dim service = New TestDiagnosticAnalyzerService(workspace.GlobalOptions) + Dim service = New TestDiagnosticAnalyzerService() Dim vsWorkspace = workspace.ExportProvider.GetExportedValue(Of MockVisualStudioWorkspace)() vsWorkspace.SetWorkspace(workspace) Using source = workspace.ExportProvider.GetExportedValue(Of ExternalErrorDiagnosticUpdateSource)() @@ -71,7 +71,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics Public Async Function TestExternalDiagnostics_SupportedDiagnosticId_Concurrent() As Task Using workspace = EditorTestWorkspace.CreateCSharp(String.Empty, composition:=s_composition) Dim waiter = workspace.GetService(Of AsynchronousOperationListenerProvider)().GetWaiter(FeatureAttribute.ErrorList) - Dim service = New TestDiagnosticAnalyzerService(workspace.GlobalOptions) + Dim service = New TestDiagnosticAnalyzerService() Dim vsWorkspace = workspace.ExportProvider.GetExportedValue(Of MockVisualStudioWorkspace)() vsWorkspace.SetWorkspace(workspace) Using source = workspace.ExportProvider.GetExportedValue(Of ExternalErrorDiagnosticUpdateSource)() @@ -98,7 +98,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics Dim threadingContext = workspace.ExportProvider.GetExport(Of IThreadingContext).Value - Dim service = New TestDiagnosticAnalyzerService(workspace.GlobalOptions) + Dim service = New TestDiagnosticAnalyzerService() Dim vsWorkspace = workspace.ExportProvider.GetExportedValue(Of MockVisualStudioWorkspace)() vsWorkspace.SetWorkspace(workspace) Using source = workspace.ExportProvider.GetExportedValue(Of ExternalErrorDiagnosticUpdateSource)() @@ -119,7 +119,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics Dim project = workspace.CurrentSolution.Projects.First() Dim diagnostic = GetDiagnosticData(project.Id) - Dim service = New TestDiagnosticAnalyzerService(workspace.GlobalOptions) + Dim service = New TestDiagnosticAnalyzerService() Dim threadingContext = workspace.ExportProvider.GetExportedValue(Of IThreadingContext) Dim testServiceBroker = workspace.ExportProvider.GetExportedValue(Of TestServiceBroker) Dim vsWorkspace = workspace.ExportProvider.GetExportedValue(Of MockVisualStudioWorkspace)() @@ -154,7 +154,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics Dim project = workspace.CurrentSolution.Projects.First() - Dim service = New TestDiagnosticAnalyzerService(workspace.GlobalOptions) + Dim service = New TestDiagnosticAnalyzerService() Dim threadingContext = workspace.ExportProvider.GetExportedValue(Of IThreadingContext) Dim testServiceBroker = workspace.ExportProvider.GetExportedValue(Of TestServiceBroker) Dim vsWorkspace = workspace.ExportProvider.GetExportedValue(Of MockVisualStudioWorkspace)() @@ -195,7 +195,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics Dim project = workspace.CurrentSolution.Projects.First() Dim diagnostic = GetDiagnosticData(project.Id) - Dim service = New TestDiagnosticAnalyzerService(globalOptions) + Dim service = New TestDiagnosticAnalyzerService() Dim threadingContext = workspace.ExportProvider.GetExportedValue(Of IThreadingContext) Dim testServiceBroker = workspace.ExportProvider.GetExportedValue(Of TestServiceBroker) Dim vsWorkspace = workspace.ExportProvider.GetExportedValue(Of MockVisualStudioWorkspace)() @@ -233,8 +233,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics Dim project = workspace.CurrentSolution.Projects.First() - Dim service = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) - Dim registration = service.CreateIncrementalAnalyzer(workspace) + Dim service = workspace.GetService(Of IDiagnosticAnalyzerService)() Dim threadingContext = workspace.ExportProvider.GetExportedValue(Of IThreadingContext) Dim testServiceBroker = workspace.ExportProvider.GetExportedValue(Of TestServiceBroker) Dim vsWorkspace = workspace.ExportProvider.GetExportedValue(Of MockVisualStudioWorkspace)() @@ -300,11 +299,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics Private ReadOnly _analyzerInfoCache As DiagnosticAnalyzerInfoCache - Public ReadOnly Property GlobalOptions As IGlobalOptionService Implements IDiagnosticAnalyzerService.GlobalOptions - - Public Sub New(globalOptions As IGlobalOptionService, Optional data As ImmutableArray(Of DiagnosticData) = Nothing) + Public Sub New() _analyzerInfoCache = New DiagnosticAnalyzerInfoCache() - Me.GlobalOptions = globalOptions End Sub Public ReadOnly Property AnalyzerInfoCache As DiagnosticAnalyzerInfoCache Implements IDiagnosticAnalyzerService.AnalyzerInfoCache @@ -316,23 +312,19 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics Public Sub RequestDiagnosticRefresh() Implements IDiagnosticAnalyzerService.RequestDiagnosticRefresh End Sub - Public Function GetDiagnosticsForSpanAsync(document As TextDocument, range As TextSpan?, shouldIncludeDiagnostic As Func(Of String, Boolean), includeCompilerDiagnostics As Boolean, priority As ICodeActionRequestPriorityProvider, diagnosticKinds As DiagnosticKind, isExplicit As Boolean, cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of DiagnosticData)) Implements IDiagnosticAnalyzerService.GetDiagnosticsForSpanAsync + Public Function GetDiagnosticsForSpanAsync(document As TextDocument, range As TextSpan?, shouldIncludeDiagnostic As Func(Of String, Boolean), priority As ICodeActionRequestPriorityProvider, diagnosticKinds As DiagnosticKind, isExplicit As Boolean, cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of DiagnosticData)) Implements IDiagnosticAnalyzerService.GetDiagnosticsForSpanAsync Return SpecializedTasks.EmptyImmutableArray(Of DiagnosticData) End Function - Public Function GetCachedDiagnosticsAsync(workspace As Workspace, projectId As ProjectId, documentId As DocumentId, includeLocalDocumentDiagnostics As Boolean, includeNonLocalDocumentDiagnostics As Boolean, cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of DiagnosticData)) Implements IDiagnosticAnalyzerService.GetCachedDiagnosticsAsync - Return SpecializedTasks.EmptyImmutableArray(Of DiagnosticData)() - End Function - - Public Function GetDiagnosticsForIdsAsync(solution As Solution, projectId As ProjectId, documentId As DocumentId, diagnosticIds As ImmutableHashSet(Of String), shouldIncludeAnalyzer As Func(Of DiagnosticAnalyzer, Boolean), getDocuments As Func(Of Project, DocumentId, IReadOnlyList(Of DocumentId)), includeLocalDocumentDiagnostics As Boolean, includeNonLocalDocumentDiagnostics As Boolean, cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of DiagnosticData)) Implements IDiagnosticAnalyzerService.GetDiagnosticsForIdsAsync + Public Function GetDiagnosticsForIdsAsync(project As Project, documentId As DocumentId, diagnosticIds As ImmutableHashSet(Of String), shouldIncludeAnalyzer As Func(Of DiagnosticAnalyzer, Boolean), includeLocalDocumentDiagnostics As Boolean, includeNonLocalDocumentDiagnostics As Boolean, cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of DiagnosticData)) Implements IDiagnosticAnalyzerService.GetDiagnosticsForIdsAsync Return SpecializedTasks.EmptyImmutableArray(Of DiagnosticData)() End Function - Public Function GetProjectDiagnosticsForIdsAsync(solution As Solution, projectId As ProjectId, diagnosticIds As ImmutableHashSet(Of String), shouldIncludeAnalyzer As Func(Of DiagnosticAnalyzer, Boolean), includeNonLocalDocumentDiagnostics As Boolean, cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of DiagnosticData)) Implements IDiagnosticAnalyzerService.GetProjectDiagnosticsForIdsAsync + Public Function GetProjectDiagnosticsForIdsAsync(project As Project, diagnosticIds As ImmutableHashSet(Of String), shouldIncludeAnalyzer As Func(Of DiagnosticAnalyzer, Boolean), includeNonLocalDocumentDiagnostics As Boolean, cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of DiagnosticData)) Implements IDiagnosticAnalyzerService.GetProjectDiagnosticsForIdsAsync Return SpecializedTasks.EmptyImmutableArray(Of DiagnosticData)() End Function - Public Function ForceAnalyzeProjectAsync(project As Project, cancellationToken As CancellationToken) As Task Implements IDiagnosticAnalyzerService.ForceAnalyzeProjectAsync + Public Function ForceAnalyzeProjectAsync(project As Project, cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of DiagnosticData)) Implements IDiagnosticAnalyzerService.ForceAnalyzeProjectAsync Throw New NotImplementedException() End Function End Class diff --git a/src/VisualStudio/Core/Test/ExtractInterface/ExtractInterfaceViewModelTests.vb b/src/VisualStudio/Core/Test/ExtractInterface/ExtractInterfaceViewModelTests.vb index 02da64ac88ed5..56026455d00db 100644 --- a/src/VisualStudio/Core/Test/ExtractInterface/ExtractInterfaceViewModelTests.vb +++ b/src/VisualStudio/Core/Test/ExtractInterface/ExtractInterfaceViewModelTests.vb @@ -265,7 +265,7 @@ public class $$MyClass }"]]> Dim viewModel = Await GetViewModelAsync(markup, LanguageNames.CSharp, "IMyClass") - Assert.Equal(5, viewModel.MemberContainers.Count) + Assert.Equal(5, viewModel.MemberContainers.Length) Assert.Equal("Goo()", viewModel.MemberContainers.ElementAt(0).SymbolName) Assert.Equal("Goo(int)", viewModel.MemberContainers.ElementAt(1).SymbolName) Assert.Equal("Goo(int, int)", viewModel.MemberContainers.ElementAt(2).SymbolName) @@ -291,7 +291,7 @@ public class $$MyClass Using workspace = EditorTestWorkspace.Create(workspaceXml) Dim doc = workspace.Documents.Single() Dim workspaceDoc = workspace.CurrentSolution.GetDocument(doc.Id) - If (Not doc.CursorPosition.HasValue) Then + If Not doc.CursorPosition.HasValue Then Assert.True(False, "Missing caret location in document.") End If @@ -300,16 +300,15 @@ public class $$MyClass Dim symbol = (Await workspaceDoc.GetSemanticModelAsync()).GetDeclaredSymbol(token.Parent) Dim extractableMembers = DirectCast(symbol, INamedTypeSymbol).GetMembers().Where(Function(s) Not (TypeOf s Is IMethodSymbol) OrElse DirectCast(s, IMethodSymbol).MethodKind <> MethodKind.Constructor) - Dim memberViewModels = extractableMembers.Select(Function(member As ISymbol) - Return New MemberSymbolViewModel(member, Nothing) - End Function) + Dim memberViewModels = extractableMembers.Select( + Function(member As ISymbol) New MemberSymbolViewModel(member, Nothing)) Return New ExtractInterfaceDialogViewModel( workspaceDoc.Project.Services.GetService(Of ISyntaxFactsService)(), notificationService:=New TestNotificationService(), uiThreadOperationExecutor:=Nothing, defaultInterfaceName:=defaultInterfaceName, - conflictingTypeNames:=If(conflictingTypeNames, New List(Of String)), + conflictingTypeNames:=conflictingTypeNames.AsImmutableOrEmpty(), memberViewModels:=memberViewModels.ToImmutableArray(), defaultNamespace:=defaultNamespace, generatedNameTypeParameterSuffix:=generatedNameTypeParameterSuffix, diff --git a/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioProjectTests/AnalyzerReferenceTests.vb b/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioProjectTests/AnalyzerReferenceTests.vb index 6d9f10df1256e..c0d0b85ee28c5 100644 --- a/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioProjectTests/AnalyzerReferenceTests.vb +++ b/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioProjectTests/AnalyzerReferenceTests.vb @@ -2,13 +2,13 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.Collections.Immutable +Imports System.ComponentModel.Composition Imports System.IO Imports System.Threading Imports Microsoft.CodeAnalysis -Imports Microsoft.CodeAnalysis.Diagnostics -Imports Microsoft.CodeAnalysis.[Shared].TestHooks +Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Test.Utilities +Imports Microsoft.CodeAnalysis.Workspaces.AnalyzerRedirecting Imports Microsoft.VisualStudio.LanguageServices.Implementation.Diagnostics Imports Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics Imports Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim.Framework @@ -285,5 +285,43 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim Assert.False(project.HasSdkCodeStyleAnalyzers) End Using End Function + + + Public Async Function RedirectedAnalyzers_CSharp() As Task + Using environment = New TestEnvironment(GetType(Redirector)) + Dim project = Await environment.ProjectFactory.CreateAndAddToWorkspaceAsync( + "Project", LanguageNames.CSharp, CancellationToken.None) + + ' Add analyzers + project.AddAnalyzerReference(Path.Combine(TempRoot.Root, "Sdks", "Microsoft.NET.Sdk", "analyzers", "Microsoft.CodeAnalysis.NetAnalyzers.dll")) + project.AddAnalyzerReference(Path.Combine(TempRoot.Root, "Sdks", "Microsoft.NET.Sdk", "analyzers", "Microsoft.CodeAnalysis.CSharp.NetAnalyzers.dll")) + project.AddAnalyzerReference(Path.Combine(TempRoot.Root, "Dir", "File.dll")) + + ' Ensure the SDK ones are redirected + AssertEx.Equal( + { + Path.Combine(TempRoot.Root, "Sdks", "Microsoft.NET.Sdk", "analyzers", "Microsoft.CodeAnalysis.NetAnalyzers.redirected.dll"), + Path.Combine(TempRoot.Root, "Sdks", "Microsoft.NET.Sdk", "analyzers", "Microsoft.CodeAnalysis.CSharp.NetAnalyzers.redirected.dll"), + Path.Combine(TempRoot.Root, "Dir", "File.dll") + }, environment.Workspace.CurrentSolution.Projects.Single().AnalyzerReferences.Select(Function(r) r.FullPath)) + End Using + End Function + + + Private Class Redirector + Implements IAnalyzerAssemblyRedirector + + + Public Sub New() + End Sub + + Public Function RedirectPath(fullPath As String) As String Implements IAnalyzerAssemblyRedirector.RedirectPath + If fullPath.Contains("Microsoft.NET.Sdk") Then + Return Path.ChangeExtension(fullPath, ".redirected.dll") + End If + + Return Nothing + End Function + End Class End Class End Namespace diff --git a/src/VisualStudio/Core/Test/Venus/DocumentService_IntegrationTests.vb b/src/VisualStudio/Core/Test/Venus/DocumentService_IntegrationTests.vb index 85111a14aaf6e..38be0fb67008c 100644 --- a/src/VisualStudio/Core/Test/Venus/DocumentService_IntegrationTests.vb +++ b/src/VisualStudio/Core/Test/Venus/DocumentService_IntegrationTests.vb @@ -229,17 +229,14 @@ class { } ' confirm there are errors Assert.True(model.GetDiagnostics().Any()) - Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) + Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)() ' confirm diagnostic support is off for the document Assert.False(document.SupportsDiagnostics()) - ' register the workspace to the service - diagnosticService.CreateIncrementalAnalyzer(workspace) - ' confirm that IDE doesn't report the diagnostics Dim diagnostics = Await diagnosticService.GetDiagnosticsForIdsAsync( - workspace.CurrentSolution, projectId:=Nothing, documentId:=document.Id, diagnosticIds:=Nothing, shouldIncludeAnalyzer:=Nothing, + document.Project, documentId:=document.Id, diagnosticIds:=Nothing, shouldIncludeAnalyzer:=Nothing, includeLocalDocumentDiagnostics:=True, includeNonLocalDocumentDiagnostics:=True, CancellationToken.None) Assert.False(diagnostics.Any()) End Using diff --git a/src/VisualStudio/ExternalAccess/Copilot/.editorconfig b/src/VisualStudio/ExternalAccess/Copilot/.editorconfig new file mode 100644 index 0000000000000..8b8e284ec0a39 --- /dev/null +++ b/src/VisualStudio/ExternalAccess/Copilot/.editorconfig @@ -0,0 +1,3 @@ +[**] +dotnet_public_api_analyzer.skip_namespaces = Microsoft.CodeAnalysis.ExternalAccess.Copilot.Internal + diff --git a/src/VisualStudio/ExternalAccess/Copilot/Internal/SemanticSearch/SemanticSearchCopilotUIProviderWrapper.cs b/src/VisualStudio/ExternalAccess/Copilot/Internal/SemanticSearch/SemanticSearchCopilotUIProviderWrapper.cs new file mode 100644 index 0000000000000..12966f1629140 --- /dev/null +++ b/src/VisualStudio/ExternalAccess/Copilot/Internal/SemanticSearch/SemanticSearchCopilotUIProviderWrapper.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.Composition; +using System.Windows.Controls; +using Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.SemanticSearch; +using Microsoft.VisualStudio.OLE.Interop; +using Microsoft.VisualStudio.Text.Editor; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot.Internal.SemanticSearch; + +[Export(typeof(ISemanticSearchCopilotUIProvider)), Shared] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class SemanticSearchCopilotUIProviderWrapper( + [Import(AllowDefault = true)] Lazy? impl) : ISemanticSearchCopilotUIProvider +{ + private sealed class TextBoxWrapper(ITextBoxControlImpl impl) : ITextBoxControl + { + Control ITextBoxControl.Control => impl.Control; + string ITextBoxControl.Text { get => impl.Text; set => impl.Text = value; } + IOleCommandTarget ITextBoxControl.CommandTarget => impl.CommandTarget; + IWpfTextView ITextBoxControl.View => impl.View; + } + + bool ISemanticSearchCopilotUIProvider.IsAvailable + => impl != null; + + ITextBoxControl ISemanticSearchCopilotUIProvider.GetTextBox() + { + Contract.ThrowIfNull(impl); + return new TextBoxWrapper(impl.Value.GetTextBox()); + } +} diff --git a/src/VisualStudio/ExternalAccess/Copilot/InternalAPI.Shipped.txt b/src/VisualStudio/ExternalAccess/Copilot/InternalAPI.Shipped.txt new file mode 100644 index 0000000000000..7dc5c58110bfa --- /dev/null +++ b/src/VisualStudio/ExternalAccess/Copilot/InternalAPI.Shipped.txt @@ -0,0 +1 @@ +#nullable enable diff --git a/src/VisualStudio/ExternalAccess/Copilot/InternalAPI.Unshipped.txt b/src/VisualStudio/ExternalAccess/Copilot/InternalAPI.Unshipped.txt new file mode 100644 index 0000000000000..d14e794951821 --- /dev/null +++ b/src/VisualStudio/ExternalAccess/Copilot/InternalAPI.Unshipped.txt @@ -0,0 +1,13 @@ +#nullable enable +Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.ISemanticSearchCopilotUIProviderImpl +Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.ISemanticSearchCopilotUIProviderImpl.GetTextBox() -> Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.ITextBoxControlImpl! +Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.ITextBoxControlImpl +Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.ITextBoxControlImpl.CommandTarget.get -> Microsoft.VisualStudio.OLE.Interop.IOleCommandTarget! +Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.ITextBoxControlImpl.Control.get -> System.Windows.Controls.Control! +Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.ITextBoxControlImpl.Text.get -> string! +Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.ITextBoxControlImpl.Text.set -> void +Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.ITextBoxControlImpl.View.get -> Microsoft.VisualStudio.Text.Editor.IWpfTextView! +Microsoft.CodeAnalysis.SemanticSearch.ISemanticSearchCopilotUIProviderWrapper +Microsoft.CodeAnalysis.SemanticSearch.ISemanticSearchCopilotUIProviderWrapper.IsAvailable.get -> bool +Microsoft.CodeAnalysis.SemanticSearch.ISemanticSearchCopilotUIProviderWrapper.ISemanticSearchCopilotUIProviderWrapper(System.Lazy? impl) -> void +Microsoft.VisualStudio.LanguageServices.ExternalAccess.Copilot.Internal.ISemanticSearchCopilotUIProviderWrapper diff --git a/src/VisualStudio/ExternalAccess/Copilot/Microsoft.VisualStudio.LanguageServices.ExternalAccess.Copilot.csproj b/src/VisualStudio/ExternalAccess/Copilot/Microsoft.VisualStudio.LanguageServices.ExternalAccess.Copilot.csproj new file mode 100644 index 0000000000000..b3e5e06c4d54b --- /dev/null +++ b/src/VisualStudio/ExternalAccess/Copilot/Microsoft.VisualStudio.LanguageServices.ExternalAccess.Copilot.csproj @@ -0,0 +1,37 @@ + + + + + Library + Microsoft.CodeAnalysis.ExternalAccess.Copilot + net472 + true + + + true + Microsoft.VisualStudio.LanguageServices.ExternalAccess.Copilot + + A supporting package for Copilot features: + https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_git/VisualStudio.Conversations + + + + + + + + + + + + + + + + + + + + diff --git a/src/VisualStudio/ExternalAccess/Copilot/PublicAPI.Shipped.txt b/src/VisualStudio/ExternalAccess/Copilot/PublicAPI.Shipped.txt new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/VisualStudio/ExternalAccess/Copilot/PublicAPI.Unshipped.txt b/src/VisualStudio/ExternalAccess/Copilot/PublicAPI.Unshipped.txt new file mode 100644 index 0000000000000..8b137891791fe --- /dev/null +++ b/src/VisualStudio/ExternalAccess/Copilot/PublicAPI.Unshipped.txt @@ -0,0 +1 @@ + diff --git a/src/VisualStudio/ExternalAccess/Copilot/SemanticSearch/ISemanticSearchCopilotUIProviderImpl.cs b/src/VisualStudio/ExternalAccess/Copilot/SemanticSearch/ISemanticSearchCopilotUIProviderImpl.cs new file mode 100644 index 0000000000000..be63658590193 --- /dev/null +++ b/src/VisualStudio/ExternalAccess/Copilot/SemanticSearch/ISemanticSearchCopilotUIProviderImpl.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.Windows.Controls; +using Microsoft.VisualStudio.OLE.Interop; +using Microsoft.VisualStudio.Text.Editor; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch; + +internal interface ITextBoxControlImpl +{ + Control Control { get; } + string Text { get; set; } + IOleCommandTarget CommandTarget { get; } + IWpfTextView View { get; } +} + +internal interface ISemanticSearchCopilotUIProviderImpl +{ + ITextBoxControlImpl GetTextBox(); +} diff --git a/src/VisualStudio/ExternalAccess/FSharp/Completion/FSharpCommonCompletionProvider.cs b/src/VisualStudio/ExternalAccess/FSharp/Completion/FSharpCommonCompletionProvider.cs index a6361b67347c1..22229d4af262d 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Completion/FSharpCommonCompletionProvider.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Completion/FSharpCommonCompletionProvider.cs @@ -4,7 +4,6 @@ #nullable disable -using System; using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.ExternalAccess.FSharp.Internal.Completion; diff --git a/src/VisualStudio/ExternalAccess/FSharp/Completion/FSharpCompletionProviderBase.cs b/src/VisualStudio/ExternalAccess/FSharp/Completion/FSharpCompletionProviderBase.cs index ea1f447b7bf56..d93a2707d626e 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Completion/FSharpCompletionProviderBase.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Completion/FSharpCompletionProviderBase.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.Completion; -using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; diff --git a/src/VisualStudio/ExternalAccess/FSharp/Editor/IFSharpEditorFormattingService.cs b/src/VisualStudio/ExternalAccess/FSharp/Editor/IFSharpEditorFormattingService.cs index 582636f404e6f..8093f3e66d412 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Editor/IFSharpEditorFormattingService.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Editor/IFSharpEditorFormattingService.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; diff --git a/src/VisualStudio/ExternalAccess/FSharp/Editor/IFSharpEditorInlineRenameService.cs b/src/VisualStudio/ExternalAccess/FSharp/Editor/IFSharpEditorInlineRenameService.cs index fc2346566e0b8..e11887167346b 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Editor/IFSharpEditorInlineRenameService.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Editor/IFSharpEditorInlineRenameService.cs @@ -8,7 +8,6 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; diff --git a/src/VisualStudio/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameInfo.cs b/src/VisualStudio/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameInfo.cs index 3127f9f685dfb..fb30aaad68c73 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameInfo.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameInfo.cs @@ -4,14 +4,12 @@ #nullable disable -using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.ExternalAccess.FSharp.Internal; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Rename; using Microsoft.CodeAnalysis.Text; diff --git a/src/VisualStudio/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameLocationSet.cs b/src/VisualStudio/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameLocationSet.cs index dc6bb255efc47..4c4973457cba3 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameLocationSet.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameLocationSet.cs @@ -4,13 +4,11 @@ #nullable disable -using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Rename; namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor diff --git a/src/VisualStudio/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameReplacementInfo.cs b/src/VisualStudio/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameReplacementInfo.cs index 035d18ef86c94..18f59678164a7 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameReplacementInfo.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameReplacementInfo.cs @@ -4,7 +4,6 @@ #nullable disable -using System; using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis.Editor; diff --git a/src/VisualStudio/ExternalAccess/FSharp/FSharpEditorFeaturesResources.cs b/src/VisualStudio/ExternalAccess/FSharp/FSharpEditorFeaturesResources.cs index 876c418d31490..583af63031447 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/FSharpEditorFeaturesResources.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/FSharpEditorFeaturesResources.cs @@ -5,7 +5,6 @@ #nullable disable using System; -using Microsoft.CodeAnalysis.Editor; namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp { diff --git a/src/VisualStudio/ExternalAccess/FSharp/FSharpGlobalOptions.cs b/src/VisualStudio/ExternalAccess/FSharp/FSharpGlobalOptions.cs index 1735f0020ece9..5aa996990a7c1 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/FSharpGlobalOptions.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/FSharpGlobalOptions.cs @@ -5,11 +5,9 @@ using System; using System.Composition; using Microsoft.CodeAnalysis.Completion; -using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.SolutionCrawler; -using Microsoft.VisualStudio.LanguageServices; namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp { diff --git a/src/VisualStudio/ExternalAccess/FSharp/Internal/CommentSelection/FSharpCommentSelectionService.cs b/src/VisualStudio/ExternalAccess/FSharp/Internal/CommentSelection/FSharpCommentSelectionService.cs index a22ab48dce0d8..0aca50b9849e0 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Internal/CommentSelection/FSharpCommentSelectionService.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Internal/CommentSelection/FSharpCommentSelectionService.cs @@ -5,14 +5,9 @@ #nullable disable using System; -using System.Collections.Immutable; using System.Composition; -using System.Threading; -using System.Threading.Tasks; using Microsoft.CodeAnalysis.CommentSelection; -using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Internal.CommentSelection { diff --git a/src/VisualStudio/ExternalAccess/FSharp/Internal/Diagnostics/FSharpDocumentDiagnosticAnalyzer.cs b/src/VisualStudio/ExternalAccess/FSharp/Internal/Diagnostics/FSharpDocumentDiagnosticAnalyzer.cs index 7cf82fd0244cd..2d9cf7e135052 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Internal/Diagnostics/FSharpDocumentDiagnosticAnalyzer.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Internal/Diagnostics/FSharpDocumentDiagnosticAnalyzer.cs @@ -9,13 +9,10 @@ using System.Composition; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.ExternalAccess.FSharp.Diagnostics; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Simplification; namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Internal.Diagnostics { diff --git a/src/VisualStudio/ExternalAccess/FSharp/Internal/Diagnostics/FSharpSimplifyNameDiagnosticAnalyzer.cs b/src/VisualStudio/ExternalAccess/FSharp/Internal/Diagnostics/FSharpSimplifyNameDiagnosticAnalyzer.cs index 5de0fc5b156ca..cf30efc0f9515 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Internal/Diagnostics/FSharpSimplifyNameDiagnosticAnalyzer.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Internal/Diagnostics/FSharpSimplifyNameDiagnosticAnalyzer.cs @@ -9,13 +9,10 @@ using System.Composition; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.ExternalAccess.FSharp.Diagnostics; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Simplification; namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Internal.Diagnostics { diff --git a/src/VisualStudio/ExternalAccess/FSharp/Internal/Diagnostics/FSharpUnusedDeclarationsAnalyzer.cs b/src/VisualStudio/ExternalAccess/FSharp/Internal/Diagnostics/FSharpUnusedDeclarationsAnalyzer.cs index 37a35d397f322..334729930054a 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Internal/Diagnostics/FSharpUnusedDeclarationsAnalyzer.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Internal/Diagnostics/FSharpUnusedDeclarationsAnalyzer.cs @@ -9,13 +9,10 @@ using System.Composition; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.ExternalAccess.FSharp.Diagnostics; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Simplification; namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Internal.Diagnostics { diff --git a/src/VisualStudio/ExternalAccess/FSharp/Internal/DocumentHighlighting/FSharpDocumentHighlightsService.cs b/src/VisualStudio/ExternalAccess/FSharp/Internal/DocumentHighlighting/FSharpDocumentHighlightsService.cs index ba9ed55d038ba..a7e95ea7dc962 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Internal/DocumentHighlighting/FSharpDocumentHighlightsService.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Internal/DocumentHighlighting/FSharpDocumentHighlightsService.cs @@ -5,7 +5,6 @@ #nullable disable using System; -using System.Linq; using System.Composition; using System.Collections.Immutable; using System.Threading; @@ -13,7 +12,6 @@ using Microsoft.CodeAnalysis.DocumentHighlighting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.ExternalAccess.FSharp.DocumentHighlighting; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Internal.DocumentHighlighting { diff --git a/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/FSharpEditorInlineRenameService.cs b/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/FSharpEditorInlineRenameService.cs index 0fc2d99295a31..aed68094921ca 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/FSharpEditorInlineRenameService.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/FSharpEditorInlineRenameService.cs @@ -17,7 +17,6 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Rename; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Internal.Editor { diff --git a/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/FSharpSmartIndentProvider.cs b/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/FSharpSmartIndentProvider.cs index 7aff5846e719c..25d50eb1c19a0 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/FSharpSmartIndentProvider.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/FSharpSmartIndentProvider.cs @@ -8,19 +8,16 @@ using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Editor.Implementation.SmartIndent; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; -using Microsoft.CodeAnalysis.Editor.Shared.Options; using Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Internal.Editor { diff --git a/src/VisualStudio/ExternalAccess/FSharp/Internal/FSharpGlyphHelpers.cs b/src/VisualStudio/ExternalAccess/FSharp/Internal/FSharpGlyphHelpers.cs index 2153890b08d1d..1158717a998ed 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Internal/FSharpGlyphHelpers.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Internal/FSharpGlyphHelpers.cs @@ -4,9 +4,6 @@ #nullable disable -using System; -using Roslyn.Utilities; - namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Internal { internal static class FSharpGlyphHelpers diff --git a/src/VisualStudio/ExternalAccess/FSharp/Internal/NavigateTo/FSharpNavigateToMatchKindHelpers.cs b/src/VisualStudio/ExternalAccess/FSharp/Internal/NavigateTo/FSharpNavigateToMatchKindHelpers.cs index 176b4218ee131..66761ef5ec483 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Internal/NavigateTo/FSharpNavigateToMatchKindHelpers.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Internal/NavigateTo/FSharpNavigateToMatchKindHelpers.cs @@ -4,10 +4,8 @@ #nullable disable -using System; using Microsoft.CodeAnalysis.ExternalAccess.FSharp.NavigateTo; using Microsoft.CodeAnalysis.NavigateTo; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Internal.NavigateTo { diff --git a/src/VisualStudio/ExternalAccess/FSharp/Internal/Navigation/InternalFSharpNavigableItem.cs b/src/VisualStudio/ExternalAccess/FSharp/Internal/Navigation/InternalFSharpNavigableItem.cs index f2ae319723ab8..5d05d69b38047 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Internal/Navigation/InternalFSharpNavigableItem.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Internal/Navigation/InternalFSharpNavigableItem.cs @@ -4,7 +4,6 @@ #nullable disable -using System; using System.Collections.Immutable; using Microsoft.CodeAnalysis.ExternalAccess.FSharp.Navigation; using Microsoft.CodeAnalysis.Navigation; diff --git a/src/VisualStudio/ExternalAccess/FSharp/Internal/SignatureHelp/FSharpSignatureHelpTriggerReasonHelpers.cs b/src/VisualStudio/ExternalAccess/FSharp/Internal/SignatureHelp/FSharpSignatureHelpTriggerReasonHelpers.cs index 17c7bae8e540e..34d3528e4fe49 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Internal/SignatureHelp/FSharpSignatureHelpTriggerReasonHelpers.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Internal/SignatureHelp/FSharpSignatureHelpTriggerReasonHelpers.cs @@ -4,10 +4,8 @@ #nullable disable -using System; using Microsoft.CodeAnalysis.ExternalAccess.FSharp.SignatureHelp; using Microsoft.CodeAnalysis.SignatureHelp; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Internal.SignatureHelp { diff --git a/src/VisualStudio/ExternalAccess/FSharp/Microsoft.CodeAnalysis.ExternalAccess.FSharp.csproj b/src/VisualStudio/ExternalAccess/FSharp/Microsoft.CodeAnalysis.ExternalAccess.FSharp.csproj index d5e722268a4da..e041981e98b54 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Microsoft.CodeAnalysis.ExternalAccess.FSharp.csproj +++ b/src/VisualStudio/ExternalAccess/FSharp/Microsoft.CodeAnalysis.ExternalAccess.FSharp.csproj @@ -15,10 +15,6 @@ - - - - + + + + + + + + + + + + + - diff --git a/src/VisualStudio/Setup/Roslyn.VisualStudio.Setup.csproj b/src/VisualStudio/Setup/Roslyn.VisualStudio.Setup.csproj index f02ebb53bedc9..1e4e3c3d22fcb 100644 --- a/src/VisualStudio/Setup/Roslyn.VisualStudio.Setup.csproj +++ b/src/VisualStudio/Setup/Roslyn.VisualStudio.Setup.csproj @@ -1,7 +1,6 @@ - Library Roslyn.VisualStudio.Setup @@ -50,7 +49,7 @@ true BindingRedirect - + Microsoft.CodeAnalysis.ExternalAccess.Copilot BuiltProjectOutputGroup true @@ -80,7 +79,7 @@ true BindingRedirect - + Microsoft.CodeAnalysis.ExternalAccess.Razor BuiltProjectOutputGroup true @@ -236,6 +235,12 @@ BuiltProjectOutputGroup;SatelliteDllsProjectOutputGroup BindingRedirect + + Microsoft.VisualStudio.LanguageServices.ExternalAccess.Copilot + BuiltProjectOutputGroup + true + BindingRedirect + RemoteWorkspaces BuiltProjectOutputGroup;SatelliteDllsProjectOutputGroup diff --git a/src/VisualStudio/Setup/source.extension.vsixmanifest b/src/VisualStudio/Setup/source.extension.vsixmanifest index 438a34bfc9481..add0ea3be74b0 100644 --- a/src/VisualStudio/Setup/source.extension.vsixmanifest +++ b/src/VisualStudio/Setup/source.extension.vsixmanifest @@ -47,7 +47,6 @@ - @@ -68,10 +67,9 @@ + - - diff --git a/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicCodePageEditorFactory.vb b/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicCodePageEditorFactory.vb index 626c5d46813ab..e6db83887e5a1 100644 --- a/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicCodePageEditorFactory.vb +++ b/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicCodePageEditorFactory.vb @@ -7,7 +7,7 @@ Imports Microsoft.VisualStudio.LanguageServices.Implementation Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic - Friend Class VisualBasicCodePageEditorFactory + Friend NotInheritable Class VisualBasicCodePageEditorFactory Inherits AbstractCodePageEditorFactory Public Sub New(editorFactory As AbstractEditorFactory) diff --git a/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicDebuggerIntelliSenseContext.vb b/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicDebuggerIntelliSenseContext.vb index 63acb0c9c2533..e1948413d2047 100644 --- a/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicDebuggerIntelliSenseContext.vb +++ b/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicDebuggerIntelliSenseContext.vb @@ -22,6 +22,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic Inherits AbstractDebuggerIntelliSenseContext Private _innerMostContainingNodeIsExpression As Boolean + Private Const StatementTerminator As String = vbCrLf Public Sub New(wpfTextView As IWpfTextView, vsTextView As IVsTextView, @@ -58,9 +59,10 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic isImmediateWindow) End Sub - Protected Overrides Function GetAdjustedContextPoint(contextPoint As Integer, document As Document) As Integer + Protected Overrides Function GetAdjustedBuffer(contextPoint As Integer, document As Document, debuggerMappedSpan As ITrackingSpan) As IProjectionBuffer Dim tree = document.GetSyntaxTreeSynchronously(CancellationToken.None) Dim token = tree.FindTokenOnLeftOfPosition(contextPoint, CancellationToken.None) + Dim adjustedStart = token.FullSpan.End Dim containingNode = token.Parent.AncestorsAndSelf().Where(Function(s) TypeOf s Is ExpressionSyntax OrElse TypeOf s Is MethodBaseSyntax OrElse @@ -68,23 +70,30 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic If containingNode IsNot Nothing Then If TypeOf containingNode Is ExpressionSyntax AndAlso Not IsRightSideOfLocalDeclaration(containingNode) Then _innerMostContainingNodeIsExpression = True - Return containingNode.Span.End + adjustedStart = containingNode.Span.End Else Dim statement = containingNode.GetExecutableBlockStatements().FirstOrDefault() If statement IsNot Nothing Then - Return statement.FullSpan.End - ElseIf TypeOf containingNode Is MethodBlockBaseSyntax + adjustedStart = statement.FullSpan.End + ElseIf TypeOf containingNode Is MethodBlockBaseSyntax Then ' Something like ' Sub Goo(o as integer) ' [| End Sub |] - Return DirectCast(containingNode, MethodBlockBaseSyntax).EndBlockStatement.SpanStart + adjustedStart = DirectCast(containingNode, MethodBlockBaseSyntax).EndBlockStatement.SpanStart Else - Return containingNode.Span.End + adjustedStart = containingNode.Span.End End If End If End If - Return token.FullSpan.End + Dim beforeAdjustedStart = GetPreviousStatementBufferAndSpan(adjustedStart, document) + Dim afterAdjustedStart = ContextBuffer.CurrentSnapshot.CreateTrackingSpanFromIndexToEnd(adjustedStart, SpanTrackingMode.EdgePositive) + + Return ProjectionBufferFactoryService.CreateProjectionBuffer( + projectionEditResolver:=Nothing, + sourceSpans:={beforeAdjustedStart, debuggerMappedSpan, StatementTerminator, afterAdjustedStart}, + options:=ProjectionBufferOptions.None, + contentType:=ContentType) End Function Private Shared Function IsRightSideOfLocalDeclaration(containingNode As SyntaxNode) As Boolean @@ -105,7 +114,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic Return False End Function - Protected Overrides Function GetPreviousStatementBufferAndSpan(contextPoint As Integer, document As Document) As ITrackingSpan + Private Function GetPreviousStatementBufferAndSpan(contextPoint As Integer, document As Document) As ITrackingSpan ' This text can be validly inserted at the end of an expression context to allow ' intellisense to trigger a new expression context Dim forceExpressionContext = ".__o(" @@ -133,11 +142,5 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic Return True End Get End Property - - Protected Overrides ReadOnly Property StatementTerminator As String - Get - Return vbCrLf - End Get - End Property End Class End Namespace diff --git a/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicEditorFactory.vb b/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicEditorFactory.vb index 06e5fd09457e3..f4d974bf94c6c 100644 --- a/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicEditorFactory.vb +++ b/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicEditorFactory.vb @@ -5,7 +5,6 @@ Imports System.Runtime.InteropServices Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Editor -Imports Microsoft.CodeAnalysis.Shared.Extensions Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.VisualStudio.ComponentModelHost Imports Microsoft.VisualStudio.LanguageServices.Implementation diff --git a/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicPackage.vb b/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicPackage.vb index f03d6a481434d..3df609cae372b 100644 --- a/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicPackage.vb +++ b/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicPackage.vb @@ -7,7 +7,6 @@ Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.ErrorReporting Imports Microsoft.CodeAnalysis.Options -Imports Microsoft.VisualStudio.LanguageServices.Implementation Imports Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService Imports Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem Imports Microsoft.VisualStudio.LanguageServices.VisualBasic.ObjectBrowser @@ -83,12 +82,12 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic End Try End Function - Protected Overrides Async Function RegisterObjectBrowserLibraryManagerAsync(cancellationToken As CancellationToken) As Task + Protected Overrides Sub RegisterObjectBrowserLibraryManager() Dim workspace As VisualStudioWorkspace = ComponentModel.GetService(Of VisualStudioWorkspace)() - Await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken) + Contract.ThrowIfFalse(JoinableTaskFactory.Context.IsOnMainThread) - Dim objectManager = TryCast(Await GetServiceAsync(GetType(SVsObjectManager)).ConfigureAwait(True), IVsObjectManager2) + Dim objectManager = TryCast(GetService(GetType(SVsObjectManager)), IVsObjectManager2) If objectManager IsNot Nothing Then Me._libraryManager = New ObjectBrowserLibraryManager(Me, ComponentModel, workspace) @@ -96,13 +95,13 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic Me._libraryManagerCookie = 0 End If End If - End Function + End Sub - Protected Overrides Async Function UnregisterObjectBrowserLibraryManagerAsync(cancellationToken As CancellationToken) As Task - Await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken) + Protected Overrides Sub UnregisterObjectBrowserLibraryManager() + Contract.ThrowIfFalse(JoinableTaskFactory.Context.IsOnMainThread) If _libraryManagerCookie <> 0 Then - Dim objectManager = TryCast(Await GetServiceAsync(GetType(SVsObjectManager)).ConfigureAwait(True), IVsObjectManager2) + Dim objectManager = TryCast(GetService(GetType(SVsObjectManager)), IVsObjectManager2) If objectManager IsNot Nothing Then objectManager.UnregisterLibrary(Me._libraryManagerCookie) Me._libraryManagerCookie = 0 @@ -111,7 +110,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic Me._libraryManager.Dispose() Me._libraryManager = Nothing End If - End Function + End Sub Public Function NeedExport(pageID As String, ByRef needExportParam As Integer) As Integer Implements IVsUserSettingsQuery.NeedExport ' We need to override MPF's definition of NeedExport since it doesn't know about our automation object diff --git a/src/VisualStudio/VisualStudioDiagnosticsToolWindow/DiagnosticsWindow.cs b/src/VisualStudio/VisualStudioDiagnosticsToolWindow/DiagnosticsWindow.cs index 373e438aed590..427b2fb7060f5 100644 --- a/src/VisualStudio/VisualStudioDiagnosticsToolWindow/DiagnosticsWindow.cs +++ b/src/VisualStudio/VisualStudioDiagnosticsToolWindow/DiagnosticsWindow.cs @@ -5,10 +5,10 @@ using System; using System.Runtime.InteropServices; using System.Windows.Controls; +using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.LanguageServices; using Microsoft.VisualStudio.Shell; using Roslyn.Hosting.Diagnostics.PerfMargin; -using Roslyn.Utilities; namespace Roslyn.VisualStudio.DiagnosticsWindow { diff --git a/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/ForceLowMemoryModePage.cs b/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/ForceLowMemoryModePage.cs index 0acde61bcfe15..83668df1fbde5 100644 --- a/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/ForceLowMemoryModePage.cs +++ b/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/ForceLowMemoryModePage.cs @@ -7,7 +7,6 @@ using System; using System.Runtime.InteropServices; using System.Windows.Controls; -using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.LanguageServices; using Microsoft.VisualStudio.LanguageServices.Implementation.Options; diff --git a/src/VisualStudio/Xaml/Impl/Features/OrganizeImports/XamlRemoveUnnecessaryImportsService.cs b/src/VisualStudio/Xaml/Impl/Features/OrganizeImports/XamlRemoveUnnecessaryImportsService.cs index 97d01f20e52c6..a82020c5da29b 100644 --- a/src/VisualStudio/Xaml/Impl/Features/OrganizeImports/XamlRemoveUnnecessaryImportsService.cs +++ b/src/VisualStudio/Xaml/Impl/Features/OrganizeImports/XamlRemoveUnnecessaryImportsService.cs @@ -7,7 +7,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Xaml.Features.OrganizeImports; -using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.RemoveUnnecessaryImports; diff --git a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Commands/CreateEventCommandHandler.cs b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Commands/CreateEventCommandHandler.cs index bad837fd8f3bf..db6d1fcff6d58 100644 --- a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Commands/CreateEventCommandHandler.cs +++ b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Commands/CreateEventCommandHandler.cs @@ -7,14 +7,15 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Xaml; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServer.Handler; using Microsoft.CodeAnalysis.LanguageServer.Handler.Commands; -using Roslyn.LanguageServer.Protocol; using Microsoft.VisualStudio.LanguageServices.Xaml.Features.Commands; using Microsoft.VisualStudio.LanguageServices.Xaml.Features.Completion; using Newtonsoft.Json.Linq; +using Roslyn.LanguageServer.Protocol; using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Xaml.LanguageServer.Handler diff --git a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Completion/CompletionResolveHandler.cs b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Completion/CompletionResolveHandler.cs index 3b1b10ba43021..0c08b8ba1f0b5 100644 --- a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Completion/CompletionResolveHandler.cs +++ b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Completion/CompletionResolveHandler.cs @@ -18,7 +18,6 @@ using Newtonsoft.Json.Linq; using Roslyn.LanguageServer.Protocol; using Roslyn.Text.Adornments; -using Roslyn.Utilities; using LSP = Roslyn.LanguageServer.Protocol; namespace Microsoft.VisualStudio.LanguageServices.Xaml.LanguageServer.Handler diff --git a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Diagnostics/WorkspacePullDiagnosticHandler.cs b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Diagnostics/WorkspacePullDiagnosticHandler.cs index 3bf3f21307bda..9ddc087650f3f 100644 --- a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Diagnostics/WorkspacePullDiagnosticHandler.cs +++ b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Diagnostics/WorkspacePullDiagnosticHandler.cs @@ -14,7 +14,6 @@ using Microsoft.VisualStudio.LanguageServices.Xaml.Features.Diagnostics; using Microsoft.VisualStudio.LanguageServices.Xaml.Implementation.LanguageServer.Extensions; using Microsoft.VisualStudio.LanguageServices.Xaml.LanguageServer; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Xaml.Implementation.LanguageServer.Handler.Diagnostics { diff --git a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/OnAutoInsert/OnAutoInsertHandler.cs b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/OnAutoInsert/OnAutoInsertHandler.cs index 4fc4845f0ec71..ab12574e46705 100644 --- a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/OnAutoInsert/OnAutoInsertHandler.cs +++ b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/OnAutoInsert/OnAutoInsertHandler.cs @@ -11,7 +11,7 @@ using Microsoft.CodeAnalysis.LanguageServer.Handler; using Roslyn.LanguageServer.Protocol; using Microsoft.VisualStudio.LanguageServices.Xaml.Features.AutoInsert; -using Roslyn.Utilities; +using Microsoft.CodeAnalysis; namespace Microsoft.VisualStudio.LanguageServices.Xaml.LanguageServer.Handler { diff --git a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/OnTypeRename/OnTypeRenameHandler.cs b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/OnTypeRename/OnTypeRenameHandler.cs index f5b603d1d93d1..2265786ce5de2 100644 --- a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/OnTypeRename/OnTypeRenameHandler.cs +++ b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/OnTypeRename/OnTypeRenameHandler.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.LanguageServer.Handler; using Roslyn.LanguageServer.Protocol; using Microsoft.VisualStudio.LanguageServices.Xaml.Features.TypeRename; -using Roslyn.Utilities; +using Microsoft.CodeAnalysis; namespace Microsoft.VisualStudio.LanguageServices.Xaml.LanguageServer.Handler { diff --git a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/XamlRequestExecutionQueue.cs b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/XamlRequestExecutionQueue.cs index d973ca8e34384..4b45c16dd99a9 100644 --- a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/XamlRequestExecutionQueue.cs +++ b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/XamlRequestExecutionQueue.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 Microsoft.CodeAnalysis.LanguageServer; using Microsoft.CodeAnalysis.LanguageServer.Handler; using Microsoft.CommonLanguageServerProtocol.Framework; diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs index cf2aa2ed0d0e9..aa610663a1295 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs @@ -277,7 +277,7 @@ private protected override SyntaxNode OperatorDeclaration(string operatorName, b var modifierList = AsModifierList(accessibility, modifiers, SyntaxKind.OperatorDeclaration); var attributes = default(SyntaxList); - if (operatorName is WellKnownMemberNames.ImplicitConversionName or WellKnownMemberNames.ExplicitConversionName) + if (operatorName is WellKnownMemberNames.ImplicitConversionName or WellKnownMemberNames.ExplicitConversionName or WellKnownMemberNames.CheckedExplicitConversionName) { var isImplicit = operatorName is WellKnownMemberNames.ImplicitConversionName; return SyntaxFactory.ConversionOperatorDeclaration( @@ -285,7 +285,7 @@ private protected override SyntaxNode OperatorDeclaration(string operatorName, b isImplicit ? ImplicitKeyword : ExplicitKeyword, explicitInterfaceSpecifier: null, OperatorKeyword, - checkedKeyword: default, + checkedKeyword: CSharp.SyntaxFacts.IsCheckedOperator(operatorName) ? CheckedKeyword : default, returnTypeNode, parameterList, body, expressionBody: null, semicolon); } else @@ -440,13 +440,15 @@ private static SyntaxNode AccessorDeclaration( public override SyntaxNode WithAccessorDeclarations(SyntaxNode declaration, IEnumerable accessorDeclarations) => declaration switch { - PropertyDeclarationSyntax property => property.WithAccessorList(CreateAccessorList(property.AccessorList, accessorDeclarations)) - .WithExpressionBody(null) - .WithSemicolonToken(default), + PropertyDeclarationSyntax property => + property.WithAccessorList(CreateAccessorList(property.AccessorList, accessorDeclarations)) + .WithExpressionBody(null) + .WithSemicolonToken(property.Initializer is null ? default : property.SemicolonToken), - IndexerDeclarationSyntax indexer => indexer.WithAccessorList(CreateAccessorList(indexer.AccessorList, accessorDeclarations)) - .WithExpressionBody(null) - .WithSemicolonToken(default), + IndexerDeclarationSyntax indexer => + indexer.WithAccessorList(CreateAccessorList(indexer.AccessorList, accessorDeclarations)) + .WithExpressionBody(null) + .WithSemicolonToken(default), _ => declaration, }; @@ -1611,8 +1613,8 @@ public override DeclarationModifiers GetModifiers(SyntaxNode declaration) private static SyntaxTokenList GetModifierTokens(SyntaxNode declaration) => CSharpAccessibilityFacts.GetModifierTokens(declaration); - public override SyntaxNode WithModifiers(SyntaxNode declaration, DeclarationModifiers modifiers) - => this.Isolate(declaration, d => this.WithModifiersInternal(d, modifiers)); + internal override TSyntaxNode WithModifiers(TSyntaxNode declaration, DeclarationModifiers modifiers) + => (TSyntaxNode)this.Isolate(declaration, d => this.WithModifiersInternal(d, modifiers)); private SyntaxNode WithModifiersInternal(SyntaxNode declaration, DeclarationModifiers modifiers) { diff --git a/src/Workspaces/CSharp/Portable/FindSymbols/CSharpDeclaredSymbolInfoFactoryService.cs b/src/Workspaces/CSharp/Portable/FindSymbols/CSharpDeclaredSymbolInfoFactoryService.cs index 104f5e5fd9889..b24c3bc2cb5d3 100644 --- a/src/Workspaces/CSharp/Portable/FindSymbols/CSharpDeclaredSymbolInfoFactoryService.cs +++ b/src/Workspaces/CSharp/Portable/FindSymbols/CSharpDeclaredSymbolInfoFactoryService.cs @@ -218,6 +218,12 @@ protected override void AddLocalFunctionInfos( return null; } + // Extensions don't declare a type of their own. As they have no name, it's not something someone could search + // for with navigate-to. Instead, they just act as a loose block around a set of actual extension members. So + // just return null here to avoid creating anything in this case. + if (typeDeclaration.Kind() == SyntaxKind.ExtensionDeclaration) + return null; + return DeclaredSymbolInfo.Create( stringTable, typeDeclaration.Identifier.ValueText, diff --git a/src/Workspaces/CSharp/Portable/Formatting/CSharpSyntaxFormattingService.cs b/src/Workspaces/CSharp/Portable/Formatting/CSharpSyntaxFormattingService.cs index 8e0238e4d88b8..1af732a124a4b 100644 --- a/src/Workspaces/CSharp/Portable/Formatting/CSharpSyntaxFormattingService.cs +++ b/src/Workspaces/CSharp/Portable/Formatting/CSharpSyntaxFormattingService.cs @@ -19,7 +19,6 @@ using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Formatting; diff --git a/src/Workspaces/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.Workspaces.csproj b/src/Workspaces/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.Workspaces.csproj index 92415ddba7007..02fadfdfe88b3 100644 --- a/src/Workspaces/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.Workspaces.csproj +++ b/src/Workspaces/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.Workspaces.csproj @@ -45,6 +45,7 @@ + diff --git a/src/Workspaces/CSharp/Portable/OrganizeImports/CSharpOrganizeImportsService.Rewriter.cs b/src/Workspaces/CSharp/Portable/OrganizeImports/CSharpOrganizeImportsService.Rewriter.cs index 39aaa3c9a5283..a901004ab6d2c 100644 --- a/src/Workspaces/CSharp/Portable/OrganizeImports/CSharpOrganizeImportsService.Rewriter.cs +++ b/src/Workspaces/CSharp/Portable/OrganizeImports/CSharpOrganizeImportsService.Rewriter.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.CSharp.Utilities; using Microsoft.CodeAnalysis.OrganizeImports; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.OrganizeImports; diff --git a/src/Workspaces/CSharp/Portable/OrganizeImports/CSharpOrganizeImportsService.cs b/src/Workspaces/CSharp/Portable/OrganizeImports/CSharpOrganizeImportsService.cs index 8cbd26e4b51db..8a67c11256287 100644 --- a/src/Workspaces/CSharp/Portable/OrganizeImports/CSharpOrganizeImportsService.cs +++ b/src/Workspaces/CSharp/Portable/OrganizeImports/CSharpOrganizeImportsService.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.OrganizeImports; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.OrganizeImports; diff --git a/src/Workspaces/CSharp/Portable/ReassignedVariable/CSharpReassignedVariableService.cs b/src/Workspaces/CSharp/Portable/ReassignedVariable/CSharpReassignedVariableService.cs index 5be7ce3817c6a..1f1add0365ed4 100644 --- a/src/Workspaces/CSharp/Portable/ReassignedVariable/CSharpReassignedVariableService.cs +++ b/src/Workspaces/CSharp/Portable/ReassignedVariable/CSharpReassignedVariableService.cs @@ -8,7 +8,6 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.ReassignedVariable; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.ReassignedVariable; diff --git a/src/Workspaces/CSharp/Portable/Rename/CSharpRenameRewriterLanguageService.cs b/src/Workspaces/CSharp/Portable/Rename/CSharpRenameRewriterLanguageService.cs index 313e9b4435a0f..32a61d36fbf79 100644 --- a/src/Workspaces/CSharp/Portable/Rename/CSharpRenameRewriterLanguageService.cs +++ b/src/Workspaces/CSharp/Portable/Rename/CSharpRenameRewriterLanguageService.cs @@ -399,17 +399,16 @@ private SyntaxToken RenameAndAnnotate(SyntaxToken token, SyntaxToken newToken, b var isMemberGroupReference = _semanticFactsService.IsInsideNameOfExpression(_semanticModel, token.Parent, _cancellationToken); - var renameAnnotation = - new RenameActionAnnotation( - token.Span, - isRenameLocation, - prefix, - suffix, - renameDeclarationLocations: renameDeclarationLocations, - isOriginalTextLocation: isOldText, - isNamespaceDeclarationReference: isNamespaceDeclarationReference, - isInvocationExpression: false, - isMemberGroupReference: isMemberGroupReference); + var renameAnnotation = new RenameActionAnnotation( + token.Span, + isRenameLocation, + prefix, + suffix, + renameDeclarationLocations: renameDeclarationLocations, + isOriginalTextLocation: isOldText, + isNamespaceDeclarationReference: isNamespaceDeclarationReference, + isInvocationExpression: false, + isMemberGroupReference: isMemberGroupReference); newToken = _renameAnnotations.WithAdditionalAnnotations(newToken, renameAnnotation, new RenameTokenSimplificationAnnotation() { OriginalTextSpan = token.Span }); diff --git a/src/Workspaces/CSharp/Portable/SemanticModelReuse/CSharpSemanticModelReuseLanguageService.cs b/src/Workspaces/CSharp/Portable/SemanticModelReuse/CSharpSemanticModelReuseLanguageService.cs index 0b31f73ff3c75..ff38d9d3807a1 100644 --- a/src/Workspaces/CSharp/Portable/SemanticModelReuse/CSharpSemanticModelReuseLanguageService.cs +++ b/src/Workspaces/CSharp/Portable/SemanticModelReuse/CSharpSemanticModelReuseLanguageService.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.SemanticModelReuse; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.SemanticModelReuse; diff --git a/src/Workspaces/CSharp/Portable/Simplification/CSharpSimplificationService.cs b/src/Workspaces/CSharp/Portable/Simplification/CSharpSimplificationService.cs index f2ed9d5989834..5a58134e3f235 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/CSharpSimplificationService.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/CSharpSimplificationService.cs @@ -16,7 +16,6 @@ using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Simplification; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Simplification; diff --git a/src/Workspaces/CSharpTest/CodeGeneration/SyntaxGeneratorTests.cs b/src/Workspaces/CSharpTest/CodeGeneration/SyntaxGeneratorTests.cs index 717c86bb6493b..9883526bd0041 100644 --- a/src/Workspaces/CSharpTest/CodeGeneration/SyntaxGeneratorTests.cs +++ b/src/Workspaces/CSharpTest/CodeGeneration/SyntaxGeneratorTests.cs @@ -1001,6 +1001,24 @@ public void TestConversionOperatorDeclaration() "public static implicit operator global::System.Decimal(global::System.Byte value)\r\n{\r\n}"); } + [Fact, WorkItem(77101, "https://github.com/dotnet/roslyn/issues/77101")] + public void TestExplicitCheckedOperatorFromSymbol() + { + var compilation = CSharpCompilation.Create("Test", [SyntaxFactory.ParseSyntaxTree(""" + public class C + { + public static explicit operator checked int(C c) => 0; + } + """)]); + + var c = compilation.GetTypeByMetadataName("C"); + var op = c.GetMembers().OfType().Where(m => m.MethodKind == MethodKind.Conversion).Single(); + + VerifySyntax( + Generator.OperatorDeclaration(op), + "public static explicit operator checked global::System.Int32(global::C c)\r\n{\r\n}"); + } + [Fact] public void TestConstructorDeclaration() { diff --git a/src/Workspaces/CSharpTest/EmbeddedLanguages/VirtualChars/CSharpVirtualCharServiceTests.cs b/src/Workspaces/CSharpTest/EmbeddedLanguages/VirtualChars/CSharpVirtualCharServiceTests.cs index 711fac1b21591..982dedb95ba1a 100644 --- a/src/Workspaces/CSharpTest/EmbeddedLanguages/VirtualChars/CSharpVirtualCharServiceTests.cs +++ b/src/Workspaces/CSharpTest/EmbeddedLanguages/VirtualChars/CSharpVirtualCharServiceTests.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Test.Utilities; -using Roslyn.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.EmbeddedLanguages.VirtualChars diff --git a/src/Workspaces/CSharpTest/Formatting/CSharpFormattingTestBase.cs b/src/Workspaces/CSharpTest/Formatting/CSharpFormattingTestBase.cs index 91bd5f6c19791..481000073bcce 100644 --- a/src/Workspaces/CSharpTest/Formatting/CSharpFormattingTestBase.cs +++ b/src/Workspaces/CSharpTest/Formatting/CSharpFormattingTestBase.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Threading.Tasks; +using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.UnitTests.Formatting; @@ -21,7 +22,7 @@ protected override SyntaxNode ParseCompilation(string text, ParseOptions? parseO => SyntaxFactory.ParseCompilationUnit(text, options: (CSharpParseOptions?)parseOptions); private protected Task AssertNoFormattingChangesAsync( - string code, + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string code, OptionsCollection? changedOptionSet = null, bool testWithTransformation = true, ParseOptions? parseOptions = null) @@ -30,8 +31,8 @@ private protected Task AssertNoFormattingChangesAsync( } private protected Task AssertFormatAsync( - string expected, - string code, + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string expected, + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string code, OptionsCollection? changedOptionSet = null, bool testWithTransformation = true, ParseOptions? parseOptions = null) @@ -40,8 +41,8 @@ private protected Task AssertFormatAsync( } private protected Task AssertFormatAsync( - string expected, - string code, + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string expected, + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string code, IEnumerable spans, OptionsCollection? changedOptionSet = null, bool testWithTransformation = true, diff --git a/src/Workspaces/CSharpTest/Formatting/FormattingTests.cs b/src/Workspaces/CSharpTest/Formatting/FormattingTests.cs index ae5911669009c..7de45b76ce74d 100644 --- a/src/Workspaces/CSharpTest/Formatting/FormattingTests.cs +++ b/src/Workspaces/CSharpTest/Formatting/FormattingTests.cs @@ -2,12 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp.Formatting; +using Microsoft.CodeAnalysis.CSharp.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Test.Utilities; @@ -15,10968 +14,12522 @@ using Xunit; using static Microsoft.CodeAnalysis.CSharp.Formatting.CSharpFormattingOptions2; -namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Formatting -{ - using static CSharpSyntaxTokens; - - [Trait(Traits.Feature, Traits.Features.Formatting)] - public class FormattingTests : CSharpFormattingTestBase - { - [Fact] - public async Task Format1() - => await AssertFormatAsync("namespace A { }", "namespace A{}"); +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Formatting; - [Fact] - public async Task Format2() - { - var content = @"class A { - }"; +using static CSharpSyntaxTokens; - var expected = @"class A +[Trait(Traits.Feature, Traits.Features.Formatting)] +public sealed class FormattingTests : CSharpFormattingTestBase { -}"; - await AssertFormatAsync(expected, content); - } + [Fact] + public async Task Format1() + => await AssertFormatAsync("namespace A { }", "namespace A{}"); - [Fact] - public async Task Format3() - { - var content = @"class A - { -int i = 20 ; }"; + [Fact] + public async Task Format2() + { + var content = """ + class A { + } + """; - var expected = @"class A -{ - int i = 20; -}"; + var expected = """ + class A + { + } + """; + await AssertFormatAsync(expected, content); + } - await AssertFormatAsync(expected, content); - } + [Fact] + public async Task Format3() + { + var content = """ + class A + { + int i = 20 ; } + """; - [Fact] - public async Task Format4() - { - var content = @"class A - { -int i = 20 ; int j = 1 + 2 ; - T . S = Test ( 10 ) ; - }"; + var expected = """ + class A + { + int i = 20; + } + """; - var expected = @"class A -{ - int i = 20; int j = 1 + 2; - T.S = Test( 10 ); -}"; + await AssertFormatAsync(expected, content); + } - await AssertFormatAsync(expected, content); - } + [Fact] + public async Task Format4() + { + var content = """ + class A + { + int i = 20 ; int j = 1 + 2 ; + T . S = Test ( 10 ) ; + } + """; - [Fact] - public async Task Format5() - { - var content = @"class A - { - List < int > Method < TArg , TArg2 > ( TArg a, TArg2 b ) - { -int i = 20 ; int j = 1 + 2 ; - T . S = Test ( 10 ) ; - } }"; + var expected = """ + class A + { + int i = 20; int j = 1 + 2; + T.S = Test( 10 ); + } + """; - var expected = @"class A -{ - List Method(TArg a, TArg2 b) - { - int i = 20; int j = 1 + 2; - T.S = Test(10); + await AssertFormatAsync(expected, content); } -}"; - await AssertFormatAsync(expected, content); - } - - [Fact] - public async Task Format6() - { - var content = @"class A - { -A a = new A { - Property1 = 1, Property2 = 3, - Property3 = { 1 , 2 , 3 } }; - }"; - - var expected = @"class A -{ - A a = new A + [Fact] + public async Task Format5() { - Property1 = 1, - Property2 = 3, - Property3 = { 1, 2, 3 } - }; -}"; - - await AssertFormatAsync(expected, content); - } + var content = """ + class A + { + List < int > Method < TArg , TArg2 > ( TArg a, TArg2 b ) + { + int i = 20 ; int j = 1 + 2 ; + T . S = Test ( 10 ) ; + } } + """; - [Fact] - public async Task Format7() - { - var content = @"class A - { - var a = from i in new [ ] { 1 , 2 , 3 } where i > 10 select i ; -}"; + var expected = """ + class A + { + List Method(TArg a, TArg2 b) + { + int i = 20; int j = 1 + 2; + T.S = Test(10); + } + } + """; - var expected = @"class A -{ - var a = from i in new[] { 1, 2, 3 } where i > 10 select i; -}"; + await AssertFormatAsync(expected, content); + } - await AssertFormatAsync(expected, content); - } + [Fact] + public async Task Format6() + { + var content = """ + class A + { + A a = new A { + Property1 = 1, Property2 = 3, + Property3 = { 1 , 2 , 3 } }; + } + """; - [Fact] - public async Task Format8() - { - var content = @"class A - { -void Method() -{ - if (true) - { - } - else if (false) - { - } -} -}"; + var expected = """ + class A + { + A a = new A + { + Property1 = 1, + Property2 = 3, + Property3 = { 1, 2, 3 } + }; + } + """; - var expected = @"class A -{ - void Method() - { - if (true) - { - } - else if (false) - { - } + await AssertFormatAsync(expected, content); } -}"; - await AssertFormatAsync(expected, content); - } + [Fact] + public async Task Format7() + { + var content = """ + class A + { + var a = from i in new [ ] { 1 , 2 , 3 } where i > 10 select i ; + } + """; - [Fact] - public async Task Format9() - { - var content = @"class A - { -void Method() -{ - if (true) { } else if (false) { } -} -}"; + var expected = """ + class A + { + var a = from i in new[] { 1, 2, 3 } where i > 10 select i; + } + """; - var expected = @"class A -{ - void Method() - { - if (true) { } else if (false) { } + await AssertFormatAsync(expected, content); } -}"; - await AssertFormatAsync(expected, content); - } - - [Fact] - public async Task Format10() - { - var content = @"class A - { - var a = from i in new [ ] { 1 , 2 , 3 } -where i > 10 select i ; -}"; + [Fact] + public async Task Format8() + { + var content = """ + class A + { + void Method() + { + if (true) + { + } + else if (false) + { + } + } + } + """; - var expected = @"class A -{ - var a = from i in new[] { 1, 2, 3 } - where i > 10 - select i; -}"; + var expected = """ + class A + { + void Method() + { + if (true) + { + } + else if (false) + { + } + } + } + """; - await AssertFormatAsync(expected, content); - } + await AssertFormatAsync(expected, content); + } - [Fact] - public async Task ObjectInitializer() - { - await AssertFormatAsync(@"public class C -{ - public C() + [Fact] + public async Task Format9() { - C c = new C() - { - c = new C() + var content = """ + class A + { + void Method() { - goo = 1, - bar = 2 + if (true) { } else if (false) { } } - }; - } -}", @"public class C -{ - public C() - { - C c = new C() - { - c = new C() - { - goo = 1, - bar = 2 - } - }; - } -}"); - } + } + """; - [Fact] - public async Task AnonymousType() - { - await AssertFormatAsync(@"class C -{ - C() - { - var anonType = new - { - p3 = new + var expected = """ + class A { - p1 = 3, - p2 = null - }, - p4 = true - }; + void Method() + { + if (true) { } else if (false) { } + } + } + """; + + await AssertFormatAsync(expected, content); } -}", @"class C -{ - C() - { - var anonType = new + + [Fact] + public async Task Format10() { - p3= new - { - p1 = 3, - p2 = null - }, - p4 = true - }; + var content = """ + class A + { + var a = from i in new [ ] { 1 , 2 , 3 } + where i > 10 select i ; + } + """; + + var expected = """ + class A + { + var a = from i in new[] { 1, 2, 3 } + where i > 10 + select i; + } + """; + + await AssertFormatAsync(expected, content); } -}"); - } - [Fact] - public async Task MultilineLambda() - { - await AssertFormatAsync(@"class C -{ - C() + [Fact] + public async Task ObjectInitializer() { - System.Func ret = x => + await AssertFormatAsync(""" + public class C + { + public C() + { + C c = new C() { - System.Func ret2 = y => - { - y++; - return y; - }; - return x + 1; + c = new C() + { + goo = 1, + bar = 2 + } }; + } + } + """, """ + public class C + { + public C() + { + C c = new C() + { + c = new C() + { + goo = 1, + bar = 2 + } + }; + } + } + """); } -}", @"class C -{ - C() + + [Fact] + public async Task AnonymousType() { - System.Func ret = x => + await AssertFormatAsync(""" + class C + { + C() + { + var anonType = new { -System.Func ret2 = y => + p3 = new + { + p1 = 3, + p2 = null + }, + p4 = true + }; + } + } + """, """ + class C + { + C() + { + var anonType = new + { + p3= new { - y++; - return y; - }; - return x + 1; - }; + p1 = 3, + p2 = null + }, + p4 = true + }; + } + } + """); } -}"); - } - [Fact] - public async Task AnonymousMethod() - { - await AssertFormatAsync(@"class C -{ - C() + [Fact] + public async Task MultilineLambda() { - timer.Tick += delegate (object sender, EventArgs e) - { - MessageBox.Show(this, ""Timer ticked""); - }; + await AssertFormatAsync(""" + class C + { + C() + { + System.Func ret = x => + { + System.Func ret2 = y => + { + y++; + return y; + }; + return x + 1; + }; + } + } + """, """ + class C + { + C() + { + System.Func ret = x => + { + System.Func ret2 = y => + { + y++; + return y; + }; + return x + 1; + }; + } + } + """); } -}", @"class C -{ - C() + + [Fact] + public async Task AnonymousMethod() { - timer.Tick += delegate(object sender, EventArgs e) - { - MessageBox.Show(this, ""Timer ticked""); - }; + await AssertFormatAsync(""" + class C + { + C() + { + timer.Tick += delegate (object sender, EventArgs e) + { + MessageBox.Show(this, "Timer ticked"); + }; + } + } + """, """ + class C + { + C() + { + timer.Tick += delegate(object sender, EventArgs e) + { + MessageBox.Show(this, "Timer ticked"); + }; + } + } + """); } -}"); - } - [Fact] - public async Task Scen1() - { - await AssertFormatAsync(@"namespace Namespace1 -{ - class Program + [Fact] + public async Task Scen1() { - static int i = 1 + 2; - - static void Main(string[] args) - { - Program p = new Program(); - - if (i < 5) - i = 0; - - for (i = 0; i < 3; i++) - Console.WriteLine(i); - - while (i < 4) - i++; - - do + await AssertFormatAsync(""" + namespace Namespace1 { - } while (i < 4); + class Program + { + static int i = 1 + 2; - Method(i, ""hello"", true); + static void Main(string[] args) + { + Program p = new Program(); - } + if (i < 5) + i = 0; - static void Method(int i, string s, bool b) - { - } - } -}", @"namespace Namespace1 -{ -class Program -{ -static int i=1+2; + for (i = 0; i < 3; i++) + Console.WriteLine(i); -static void Main(string[] args) -{ -Program p=new Program(); + while (i < 4) + i++; -if (i<5) - i=0; - -for (i=0;i<3;i++) - Console.WriteLine(i); + do + { + } while (i < 4); -while (i<4) - i++; + Method(i, "hello", true); -do{ - }while(i<4); + } -Method(i,""hello"",true); + static void Method(int i, string s, bool b) + { + } + } + } + """, """ + namespace Namespace1 + { + class Program + { + static int i=1+2; -} + static void Main(string[] args) + { + Program p=new Program(); -static void Method(int i, string s, bool b) -{ -} -} -}"); - } + if (i<5) + i=0; + + for (i=0;i<3;i++) + Console.WriteLine(i); - [Fact] - public async Task Scen2() - { - await AssertFormatAsync(@"namespace MyNamespace -{ - class Class1 - { - } - enum E - { - } - namespace NestedNamespace - { - } -} + while (i<4) + i++; -namespace Namespace1 -{ - class Class1 - { - int i; - class NestedClass - { - } - T t; - T Method(RR r) where RR : Class1 - { - return default(T); - } - } + do{ + }while(i<4); - struct S - { - string field1; - bool field2; - public void Method() - { - } - } + Method(i,"hello",true); - enum E - { - Enum1 = 10, - Enum2, - Enum3 + } + + static void Method(int i, string s, bool b) + { + } + } + } + """); } - class Program + [Fact] + public async Task Scen2() { - static int i = 10; - - class NestedClass - { - int field; - class NestedClass2 + await AssertFormatAsync(""" + namespace MyNamespace { - int field; - class NestedClass3 + class Class1 { - enum E + } + enum E + { + } + namespace NestedNamespace + { + } + } + + namespace Namespace1 + { + class Class1 + { + int i; + class NestedClass + { + } + T t; + T Method(RR r) where RR : Class1 + { + return default(T); + } + } + + struct S + { + string field1; + bool field2; + public void Method() { } } - int Prop + + enum E { - get { return field; } - set { field = value; } + Enum1 = 10, + Enum2, + Enum3 } - public void Method() + + class Program { + static int i = 10; + + class NestedClass + { + int field; + class NestedClass2 + { + int field; + class NestedClass3 + { + enum E + { + } + } + int Prop + { + get { return field; } + set { field = value; } + } + public void Method() + { + } + } + } + + struct S + { + string field1; + bool field2; + public void Method() + { + } + } + + enum E + { + Enum1 = 10, + Enum2, + Enum3 + } + + public int Prop + { + get { return i; } + set { i = value; } + } + + static void Main() + { + { + Program p = new Program(); + NestedClass n = new NestedClass(); + } + + if (i < 10) + { + Console.WriteLine(i); + } + + switch (i) + { + case 1: + break; + case 2: + break; + default: + break; + } + + for (i = 0; i < 10; i++) + { + i++; + } + + while (i < 10) + { + i++; + } + + try + { + Console.WriteLine(); + } + catch + { + Console.WriteLine(); + } + finally + { + Console.WriteLine(); + } + + } + public void Method(T t) + { + Console.WriteLine(t.ToString()); + } + } } - } + """, """ + namespace MyNamespace + { + class Class1 + { + } + enum E + { + } + namespace NestedNamespace + { + } + } - struct S - { + namespace Namespace1 + { + class Class1 + { + int i; + class NestedClass + { + } + T t; + T Method(RR r) where RR : Class1 + { + return default(T); + } + } + + struct S + { string field1; - bool field2; + bool field2; public void Method() { } - } + } - enum E - { - Enum1 = 10, + enum E + { + Enum1=10, Enum2, Enum3 - } + } - public int Prop - { - get { return i; } - set { i = value; } - } + class Program + { + static int i = 10; - static void Main() - { + class NestedClass + { + int field; + class NestedClass2 { - Program p = new Program(); - NestedClass n = new NestedClass(); + int field; + class NestedClass3 + { + enum E + { + } } - - if (i < 10) + int Prop { - Console.WriteLine(i); + get {return field;} + set {field=value;} } - - switch (i) + public void Method() { - case 1: - break; - case 2: - break; - default: - break; } + } + } - for (i = 0; i < 10; i++) + struct S + { + string field1; + bool field2; + public void Method() { - i++; } + } - while (i < 10) + enum E { - i++; - } + Enum1 = 10, + Enum2, + Enum3 + } - try + public int Prop { - Console.WriteLine(); - } - catch + get {return i;} + set {i=value;} + } + + static void Main() + { + { + Program p=new Program(); + NestedClass n=new NestedClass(); + } + + if (i<10) { - Console.WriteLine(); + Console.WriteLine(i); } - finally + + switch (i) { - Console.WriteLine(); + case 1: + break; + case 2: + break; + default: + break; + } + + for (i=0;i<10;i++) + { + i++; } - } - public void Method(T t) - { - Console.WriteLine(t.ToString()); - } + while (i<10) + { + i++; + } - } -}", @"namespace MyNamespace -{ - class Class1 - { + try + { + Console.WriteLine(); } -enum E -{ -} - namespace NestedNamespace - { + catch + { + Console.WriteLine(); + } + finally + { + Console.WriteLine(); } -} - -namespace Namespace1 -{ -class Class1 -{ -int i; -class NestedClass -{ -} -T t; - T Method(RR r) where RR : Class1 - { - return default(T); - } - } - -struct S -{ -string field1; - bool field2; -public void Method() -{ -} -} -enum E -{ - Enum1=10, -Enum2, -Enum3 - } + } + public void Method(T t) + { + Console.WriteLine(t.ToString()); + } -class Program -{ -static int i = 10; + } + } + """); + } -class NestedClass -{ - int field; -class NestedClass2 -{ -int field; - class NestedClass3 -{ - enum E + [Fact] + public async Task Scen3() + { + await AssertFormatAsync(""" + namespace Namespace1 + { + class Program { + static void Main() + { + Program p = new Program(); + } } -} -int Prop -{ - get {return field;} - set {field=value;} -} -public void Method() -{ -} -} + } + """, """ + namespace Namespace1 + { + class Program + { + static void Main() + { + Program p=new Program(); + } + } + } + """); } -struct S -{ - string field1; - bool field2; -public void Method() -{ -} - } - -enum E -{ - Enum1 = 10, - Enum2, -Enum3 - } - -public int Prop -{ -get {return i;} -set {i=value;} - } - -static void Main() -{ -{ - Program p=new Program(); -NestedClass n=new NestedClass(); + [Fact] + public async Task Scen4() + { + await AssertFormatAsync(""" + class Class1 + { + // public void goo() + // { + // // TODO: Add the implementation for Class1.goo() here. + // + // } } + """, """ + class Class1 + { + // public void goo() + // { + // // TODO: Add the implementation for Class1.goo() here. + // + // } + } + """); + } -if (i<10) -{ - Console.WriteLine(i); -} - -switch (i) -{ - case 1: - break; - case 2: - break; -default: -break; + [Fact] + public async Task Scen5() + { + await AssertFormatAsync(""" + class Class1 + { + public void Method() + { + { + int i = 0; + System.Console.WriteLine(); + } + } + } + """, """ + class Class1 + { + public void Method() + { + { + int i = 0; + System.Console.WriteLine(); + } + } + } + """); } -for (i=0;i<10;i++) -{ - i++; -} - -while (i<10) -{ - i++; - } - -try -{ - Console.WriteLine(); - } -catch -{ - Console.WriteLine(); - } -finally -{ - Console.WriteLine(); + [Fact] + public async Task Scen6() + { + await AssertFormatAsync(""" + namespace Namespace1 + { + class OuterClass + { + class InnerClass + { + } + } } - -} -public void Method(T t) -{ - Console.WriteLine(t.ToString()); + """, """ + namespace Namespace1 + { + class OuterClass + { + class InnerClass + { } - -} -}"); - } - - [Fact] - public async Task Scen3() - { - await AssertFormatAsync(@"namespace Namespace1 -{ - class Program - { - static void Main() - { - Program p = new Program(); - } + } + } + """); } -}", @"namespace Namespace1 -{ -class Program -{ -static void Main() -{ -Program p=new Program(); -} -} -}"); - } - - [Fact] - public async Task Scen4() - { - await AssertFormatAsync(@"class Class1 -{ - // public void goo() - // { - // // TODO: Add the implementation for Class1.goo() here. - // - // } -}", @"class Class1 -{ - // public void goo() -// { -// // TODO: Add the implementation for Class1.goo() here. -// -// } -}"); - } - [Fact] - public async Task Scen5() - { - await AssertFormatAsync(@"class Class1 -{ - public void Method() + [Fact] + public async Task Scen7() { - { + await AssertFormatAsync(""" + class Class1 + { + public void Method() + { + int i = 0; + switch (i) + { + case 0: + break; + } + if (i > 0) goto z; + i = -i; + z: + i = 2 * i; + } + } + """, """ + class Class1 + { + public void Method() + { int i = 0; - System.Console.WriteLine(); - } - } -}", @"class Class1 -{ -public void Method() -{ -{ -int i = 0; - System.Console.WriteLine(); -} -} -}"); - } - - [Fact] - public async Task Scen6() - { - await AssertFormatAsync(@"namespace Namespace1 -{ - class OuterClass - { - class InnerClass - { - } - } -}", @"namespace Namespace1 -{ -class OuterClass -{ -class InnerClass -{ -} -} -}"); - } - - [Fact] - public async Task Scen7() - { - await AssertFormatAsync(@"class Class1 -{ - public void Method() - { - int i = 0; - switch (i) - { + switch (i) + { case 0: - break; - } - if (i > 0) goto z; - i = -i; - z: - i = 2 * i; + break; + } + if (i > 0) goto z; + i = -i; + z: + i = 2 * i; + } + } + """); } -}", @"class Class1 -{ -public void Method() -{ -int i = 0; -switch (i) -{ -case 0: -break; -} -if (i > 0) goto z; -i = -i; -z: -i = 2 * i; -} -}"); - } - [Fact] - public async Task Scen8() - { - await AssertFormatAsync(@"class Class1 -{ - public void Method() + [Fact] + public async Task Scen8() { - int i = 10; - } -}", @"class Class1 - { + await AssertFormatAsync(""" + class Class1 + { public void Method() - { + { int i = 10; - } -}"); - } + } + } + """, """ + class Class1 + { + public void Method() + { + int i = 10; + } + } + """); + } - [Fact] - public async Task IndentStatementsInMethod() - { - await AssertFormatAsync(@"class C -{ - void Goo() + [Fact] + public async Task IndentStatementsInMethod() { - int x = 0; - int y = 0; - int z = 0; + await AssertFormatAsync(""" + class C + { + void Goo() + { + int x = 0; + int y = 0; + int z = 0; + } + } + """, """ + class C + { + void Goo() + { + int x = 0; + int y = 0; + int z = 0; + } + } + """); } -}", @"class C -{ - void Goo() + + [Fact] + public async Task IndentFieldsInClass() { - int x = 0; - int y = 0; - int z = 0; + await AssertFormatAsync(""" + class C + { + int a = 10; + int b; + int c; + } + """, """ + class C + { + int a = 10; + int b; + int c; + } + """); } -}"); - } - - [Fact] - public async Task IndentFieldsInClass() - { - await AssertFormatAsync(@"class C -{ - int a = 10; - int b; - int c; -}", @"class C -{ - int a = 10; - int b; - int c; -}"); - } - [Fact] - public async Task IndentUserDefaultSettingTest() - { - await AssertFormatAsync(@"class Class2 -{ - public void nothing() + [Fact] + public async Task IndentUserDefaultSettingTest() { - nothing_again(() => + await AssertFormatAsync(""" + class Class2 { - Console.WriteLine(""Nothing""); - }); - label1: - int f = 5; - label2: - switch (f) - { - case 1: + public void nothing() { - break; + nothing_again(() => + { + Console.WriteLine("Nothing"); + }); + label1: + int f = 5; + label2: + switch (f) + { + case 1: + { + break; + } + case 2: + int d = f + f; + label3: + d = d - f; + break; + default: + { + int g = f * f; + g = g - f; + break; + } + } + return; + } + + public void nothing_again(Action a) + { + l: + goto l; } - case 2: + } + """, """ + class Class2 + { + public void nothing() + { + nothing_again(() => + { + Console.WriteLine("Nothing"); + }); + label1: + int f = 5; + label2: + switch (f) + { + case 1: + { + break; + } + case 2: int d = f + f; label3: d = d - f; break; - default: - { - int g = f * f; - g = g - f; - break; + default: + { + int g = f * f; + g = g - f; + break; + } + } + return; + } + + public void nothing_again(Action a) + { + l: + goto l; + } } - } - return; + """); } - public void nothing_again(Action a) - { - l: - goto l; - } -}", @"class Class2 + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/766133")] + public async Task RelativeIndentationToFirstTokenInBaseTokenWithObjectInitializers() { - public void nothing() - { - nothing_again(() => - { - Console.WriteLine(""Nothing""); - }); -label1: - int f = 5; -label2: - switch (f) - { - case 1: + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - break; - } - case 2: - int d = f + f; -label3: - d = d - f; - break; - default: - { - int g = f * f; - g = g - f; - break; - } - } - return; - } + { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers, false) }, + }; + await AssertFormatAsync(""" + class Program + { + static void Main(string[] args) + { + var summa = new D { + A = 0, + B = 4 + }; + } + } - public void nothing_again(Action a) - { - l: - goto l; - } - }"); - } + class D + { + public int A { get; set; } + public int B { get; set; } + } + """, """ + class Program + { + static void Main(string[] args) + { + var summa = new D + { + A = 0, + B = 4 + }; + } + } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/766133")] - public async Task RelativeIndentationToFirstTokenInBaseTokenWithObjectInitializers() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) + class D { - { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers, false) }, - }; - await AssertFormatAsync(@"class Program -{ - static void Main(string[] args) - { - var summa = new D { - A = 0, - B = 4 - }; + public int A { get; set; } + public int B { get; set; } + } + """, changingOptions); } -} -class D -{ - public int A { get; set; } - public int B { get; set; } -}", @"class Program -{ - static void Main(string[] args) + [Fact] + public async Task RemoveSpacingAroundBinaryOperatorsShouldMakeAtLeastOneSpaceForIsAndAsKeywords() { - var summa = new D + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - A = 0, - B = 4 + { CSharpFormattingOptions2.SpacingAroundBinaryOperator, BinaryOperatorSpacingOptions.Remove } }; - } -} - -class D -{ - public int A { get; set; } - public int B { get; set; } -}", changingOptions); - } - - [Fact] - public async Task RemoveSpacingAroundBinaryOperatorsShouldMakeAtLeastOneSpaceForIsAndAsKeywords() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) + await AssertFormatAsync(""" + class Class2 { - { CSharpFormattingOptions2.SpacingAroundBinaryOperator, BinaryOperatorSpacingOptions.Remove } - }; - await AssertFormatAsync(@"class Class2 -{ - public void nothing() - { - var a = 1*2+3-4/5; - a+=1; - object o = null; - string s = o as string; - bool b = o is string; + public void nothing() + { + var a = 1*2+3-4/5; + a+=1; + object o = null; + string s = o as string; + bool b = o is string; + } + } + """, """ + class Class2 + { + public void nothing() + { + var a = 1 * 2 + 3 - 4 / 5; + a += 1; + object o = null; + string s = o as string; + bool b = o is string; + } + } + """, changingOptions); } -}", @"class Class2 - { - public void nothing() - { - var a = 1 * 2 + 3 - 4 / 5; - a += 1; - object o = null; - string s = o as string; - bool b = o is string; - } - }", changingOptions); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/772298")] - public async Task IndentUserSettingNonDefaultTest_OpenBracesOfLambdaWithNoNewLine() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) - { - { IndentBraces, true }, - { IndentBlock, false }, - { IndentSwitchSection, false }, - { IndentSwitchCaseSection, false }, - { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.LambdaExpressionBody, false) }, - { LabelPositioning, LabelPositionOptions.LeftMost } - }; - - await AssertFormatAsync(@"class Class2 + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/772298")] + public async Task IndentUserSettingNonDefaultTest_OpenBracesOfLambdaWithNoNewLine() { - public void nothing() + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - nothing_again(() => { - Console.WriteLine(""Nothing""); - }); - } - }", @"class Class2 -{ - public void nothing() - { - nothing_again(() => + { IndentBraces, true }, + { IndentBlock, false }, + { IndentSwitchSection, false }, + { IndentSwitchCaseSection, false }, + { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.LambdaExpressionBody, false) }, + { LabelPositioning, LabelPositionOptions.LeftMost } + }; + + await AssertFormatAsync(""" + class Class2 + { + public void nothing() + { + nothing_again(() => { + Console.WriteLine("Nothing"); + }); + } + } + """, """ + class Class2 { - Console.WriteLine(""Nothing""); - }); + public void nothing() + { + nothing_again(() => + { + Console.WriteLine("Nothing"); + }); + } + } + """, changedOptionSet: changingOptions); } -}", changedOptionSet: changingOptions); - } - [Fact] - public async Task IndentUserSettingNonDefaultTest() + [Fact] + public async Task IndentUserSettingNonDefaultTest() + { + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) - { - { IndentBraces, true }, - { IndentBlock, false }, - { IndentSwitchSection, false }, - { IndentSwitchCaseSection, false }, - { IndentSwitchCaseSectionWhenBlock, false }, - { LabelPositioning, LabelPositionOptions.LeftMost } - }; - - await AssertFormatAsync(@"class Class2 - { - public void nothing() - { - nothing_again(() => - { - Console.WriteLine(""Nothing""); - }); -label1: - int f = 5; -label2: - switch (f) - { - case 1: - { - break; - } - case 2: - int d = f + f; -label3: - d = d - f; - break; - default: - { - int g = f * f; - g = g - f; - break; - } - } - return; - } + { IndentBraces, true }, + { IndentBlock, false }, + { IndentSwitchSection, false }, + { IndentSwitchCaseSection, false }, + { IndentSwitchCaseSectionWhenBlock, false }, + { LabelPositioning, LabelPositionOptions.LeftMost } + }; - public void nothing_again(Action a) - { -l: - goto l; - } - }", @"class Class2 -{ - public void nothing() - { - nothing_again(() => - { - Console.WriteLine(""Nothing""); - }); - label1: - int f = 5; - label2: - switch (f) - { - case 1: + await AssertFormatAsync(""" + class Class2 { - break; - } - case 2: + public void nothing() + { + nothing_again(() => + { + Console.WriteLine("Nothing"); + }); + label1: + int f = 5; + label2: + switch (f) + { + case 1: + { + break; + } + case 2: int d = f + f; label3: d = d - f; break; - default: + default: + { + int g = f * f; + g = g - f; + break; + } + } + return; + } + + public void nothing_again(Action a) + { + l: + goto l; + } + } + """, """ + class Class2 + { + public void nothing() { - int g = f * f; - g = g - f; - break; + nothing_again(() => + { + Console.WriteLine("Nothing"); + }); + label1: + int f = 5; + label2: + switch (f) + { + case 1: + { + break; + } + case 2: + int d = f + f; + label3: + d = d - f; + break; + default: + { + int g = f * f; + g = g - f; + break; + } + } + return; } - } - return; - } - public void nothing_again(Action a) - { - l: - goto l; + public void nothing_again(Action a) + { + l: + goto l; + } + } + """, changedOptionSet: changingOptions); } -}", changedOptionSet: changingOptions); - } - - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/20009")] - public async Task IndentSwitch_IndentCase_IndentWhenBlock() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) - { - { IndentSwitchSection, true }, - { IndentSwitchCaseSection, true }, - { IndentSwitchCaseSectionWhenBlock, true }, - }; - await AssertFormatAsync( -@"class Class2 -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/20009")] + public async Task IndentSwitch_IndentCase_IndentWhenBlock() { - switch (i) + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - case 0: + { IndentSwitchSection, true }, + { IndentSwitchCaseSection, true }, + { IndentSwitchCaseSectionWhenBlock, true }, + }; + + await AssertFormatAsync( + """ + class Class2 + { + void M() + { + switch (i) + { + case 0: + { + } + case 1: + break; + } + } + } + """, + """ + class Class2 + { + void M() { + switch (i) { + case 0: { } - case 1: + case 1: break; - } - } -}", -@"class Class2 -{ - void M() - { - switch (i) { - case 0: { - } - case 1: - break; + } + } } + """, changedOptionSet: changingOptions); } -}", changedOptionSet: changingOptions); - } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/20009")] - public async Task IndentSwitch_IndentCase_NoIndentWhenBlock() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) - { - { IndentSwitchSection, true }, - { IndentSwitchCaseSection, true }, - { IndentSwitchCaseSectionWhenBlock, false }, - }; - - await AssertFormatAsync( -@"class Class2 -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/20009")] + public async Task IndentSwitch_IndentCase_NoIndentWhenBlock() { - switch (i) + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - case 0: + { IndentSwitchSection, true }, + { IndentSwitchCaseSection, true }, + { IndentSwitchCaseSectionWhenBlock, false }, + }; + + await AssertFormatAsync( + """ + class Class2 { + void M() + { + switch (i) + { + case 0: + { + } + case 1: + break; + } + } } - case 1: + """, + """ + class Class2 + { + void M() + { + switch (i) { + case 0: { + } + case 1: break; - } - } -}", -@"class Class2 -{ - void M() - { - switch (i) { - case 0: { - } - case 1: - break; + } + } } + """, changedOptionSet: changingOptions); } -}", changedOptionSet: changingOptions); - } - - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/20009")] - public async Task IndentSwitch_NoIndentCase_IndentWhenBlock() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) - { - { IndentSwitchSection, true }, - { IndentSwitchCaseSection, false }, - { IndentSwitchCaseSectionWhenBlock, true }, - }; - await AssertFormatAsync( -@"class Class2 -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/20009")] + public async Task IndentSwitch_NoIndentCase_IndentWhenBlock() { - switch (i) + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - case 0: + { IndentSwitchSection, true }, + { IndentSwitchCaseSection, false }, + { IndentSwitchCaseSectionWhenBlock, true }, + }; + + await AssertFormatAsync( + """ + class Class2 + { + void M() { + switch (i) + { + case 0: + { + } + case 1: + break; + } } - case 1: - break; - } - } -}", -@"class Class2 -{ - void M() - { - switch (i) { - case 0: { - } - case 1: - break; } - } -}", changedOptionSet: changingOptions); - } - - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/20009")] - public async Task IndentSwitch_NoIndentCase_NoIndentWhenBlock() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) + """, + """ + class Class2 { - { IndentSwitchSection, true }, - { IndentSwitchCaseSection, false }, - { IndentSwitchCaseSectionWhenBlock, false }, - }; + void M() + { + switch (i) { + case 0: { + } + case 1: + break; + } + } + } + """, changedOptionSet: changingOptions); + } - await AssertFormatAsync( -@"class Class2 -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/20009")] + public async Task IndentSwitch_NoIndentCase_NoIndentWhenBlock() { - switch (i) + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - case 0: + { IndentSwitchSection, true }, + { IndentSwitchCaseSection, false }, + { IndentSwitchCaseSectionWhenBlock, false }, + }; + + await AssertFormatAsync( + """ + class Class2 { + void M() + { + switch (i) + { + case 0: + { + } + case 1: + break; + } + } } - case 1: - break; - } - } -}", -@"class Class2 -{ - void M() - { - switch (i) { - case 0: { - } - case 1: - break; + """, + """ + class Class2 + { + void M() + { + switch (i) { + case 0: { + } + case 1: + break; + } + } } + """, changedOptionSet: changingOptions); } -}", changedOptionSet: changingOptions); - } - - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/20009")] - public async Task NoIndentSwitch_IndentCase_IndentWhenBlock() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) - { - { IndentSwitchSection, false }, - { IndentSwitchCaseSection, true }, - { IndentSwitchCaseSectionWhenBlock, true }, - }; - await AssertFormatAsync( -@"class Class2 -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/20009")] + public async Task NoIndentSwitch_IndentCase_IndentWhenBlock() { - switch (i) + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - case 0: + { IndentSwitchSection, false }, + { IndentSwitchCaseSection, true }, + { IndentSwitchCaseSectionWhenBlock, true }, + }; + + await AssertFormatAsync( + """ + class Class2 { + void M() + { + switch (i) + { + case 0: + { + } + case 1: + break; + } + } } - case 1: - break; - } - } -}", -@"class Class2 -{ - void M() - { - switch (i) { - case 0: { - } - case 1: - break; + """, + """ + class Class2 + { + void M() + { + switch (i) { + case 0: { + } + case 1: + break; + } + } } + """, changedOptionSet: changingOptions); } -}", changedOptionSet: changingOptions); - } - - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/20009")] - public async Task NoIndentSwitch_IndentCase_NoIndentWhenBlock() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) - { - { IndentSwitchSection, false }, - { IndentSwitchCaseSection, true }, - { IndentSwitchCaseSectionWhenBlock, false }, - }; - await AssertFormatAsync( -@"class Class2 -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/20009")] + public async Task NoIndentSwitch_IndentCase_NoIndentWhenBlock() { - switch (i) - { - case 0: + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - } - case 1: - break; - } - } -}", -@"class Class2 -{ - void M() - { - switch (i) { - case 0: { - } - case 1: - break; - } - } -}", changedOptionSet: changingOptions); - } + { IndentSwitchSection, false }, + { IndentSwitchCaseSection, true }, + { IndentSwitchCaseSectionWhenBlock, false }, + }; - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/20009")] - public async Task NoIndentSwitch_NoIndentCase_IndentWhenBlock() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) + await AssertFormatAsync( + """ + class Class2 { - { IndentSwitchSection, false }, - { IndentSwitchCaseSection, false }, - { IndentSwitchCaseSectionWhenBlock, true }, - }; + void M() + { + switch (i) + { + case 0: + { + } + case 1: + break; + } + } + } + """, + """ + class Class2 + { + void M() + { + switch (i) { + case 0: { + } + case 1: + break; + } + } + } + """, changedOptionSet: changingOptions); + } - await AssertFormatAsync( -@"class Class2 -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/20009")] + public async Task NoIndentSwitch_NoIndentCase_IndentWhenBlock() { - switch (i) + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - case 0: + { IndentSwitchSection, false }, + { IndentSwitchCaseSection, false }, + { IndentSwitchCaseSectionWhenBlock, true }, + }; + + await AssertFormatAsync( + """ + class Class2 { + void M() + { + switch (i) + { + case 0: + { + } + case 1: + break; + } + } } - case 1: - break; - } - } -}", -@"class Class2 -{ - void M() - { - switch (i) { - case 0: { - } - case 1: - break; + """, + """ + class Class2 + { + void M() + { + switch (i) { + case 0: { + } + case 1: + break; + } + } } + """, changedOptionSet: changingOptions); } -}", changedOptionSet: changingOptions); - } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/20009")] - public async Task NoIndentSwitch_NoIndentCase_NoIndentWhenBlock() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/20009")] + public async Task NoIndentSwitch_NoIndentCase_NoIndentWhenBlock() + { + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) + { IndentSwitchSection, false }, + { IndentSwitchCaseSection, false }, + { IndentSwitchCaseSectionWhenBlock, false }, + }; + + await AssertFormatAsync( + """ + class Class2 { - { IndentSwitchSection, false }, - { IndentSwitchCaseSection, false }, - { IndentSwitchCaseSectionWhenBlock, false }, - }; + void M() + { + switch (i) + { + case 0: + { + } + case 1: + break; + } + } + } + """, + """ + class Class2 + { + void M() + { + switch (i) { + case 0: { + } + case 1: + break; + } + } + } + """, changedOptionSet: changingOptions); + } - await AssertFormatAsync( -@"class Class2 -{ - void M() + [Fact] + public async Task TestWrappingDefault() + { + await AssertFormatAsync(""" + class Class5 + { + delegate void Del(int x); + public int Age { get { int age = 0; return age; } } + public int Age2 + { + get { int age2 = 0; return age2; } + set { int age2 = value; } + } + void bar() + { + int x = 0; + if (x == 1) x = 2; else x = 3; + do { x = 4; } while (x != 4); + switch (x) { case 1: break; case 2: break; default: break; } + Del d = delegate (int k) { Console.WriteLine(); Console.WriteLine(); }; + } + } + """, """ + class Class5 + { + delegate void Del(int x); + public int Age { get { int age = 0; return age; } } + public int Age2 + { + get { int age2 = 0; return age2; } + set { int age2 = value; } + } + void bar() + { + int x = 0; + if(x == 1) x = 2; else x =3; + do { x = 4; } while (x != 4); + switch (x) { case 1: break; case 2: break; default: break; } + Del d = delegate(int k) { Console.WriteLine(); Console.WriteLine(); }; + } + } + """); + } + + [Fact] + public async Task TestWrappingNonDefault_FormatBlock() { - switch (i) + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - case 0: + { CSharpFormattingOptions2.WrappingPreserveSingleLine, false } + }; + await AssertFormatAsync(""" + class Class5 + { + delegate void Del(int x); + public int Age + { + get + { + int age = 0; return age; + } + } + public int Age2 + { + get + { + int age2 = 0; return age2; + } + set + { + int age2 = value; + } + } + void bar() + { + int x = 0; + if (x == 1) x = 2; else x = 3; + do { x = 4; } while (x != 4); + switch (x) + { + case 1: break; + case 2: break; + default: break; + } + Del d = delegate (int k) { Console.WriteLine(); Console.WriteLine(); }; + } + void goo() + { + int xx = 0; int zz = 0; + } + } + class goo + { + int x = 0; + } + """, """ + class Class5 + { + delegate void Del(int x); + public int Age { get { int age = 0; return age; } } + public int Age2 + { + get { int age2 = 0; return age2; } + set { int age2 = value; } + } + void bar() + { + int x = 0; + if(x == 1) x = 2; else x =3; + do { x = 4; } while (x != 4); + switch (x) { case 1: break; case 2: break; default: break; } + Del d = delegate(int k) { Console.WriteLine(); Console.WriteLine(); }; + } + void goo() { int xx = 0; int zz = 0;} + } + class goo{int x = 0;} + """, changingOptions); + } + + [Fact] + public async Task TestWrappingNonDefault_FormatStatmtMethDecl() + { + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - } - case 1: - break; - } + { CSharpFormattingOptions2.WrappingKeepStatementsOnSingleLine, false } + }; + await AssertFormatAsync(""" + class Class5 + { + delegate void Del(int x); + public int Age { get { int age = 0; return age; } } + public int Age2 + { + get { int age2 = 0; return age2; } + set { int age2 = value; } + } + void bar() + { + int x = 0; + if (x == 1) + x = 2; + else + x = 3; + do + { x = 4; } while (x != 4); + switch (x) + { + case 1: + break; + case 2: + break; + default: + break; + } + Del d = delegate (int k) + { Console.WriteLine(); Console.WriteLine(); }; + } + void goo() { int y = 0; int z = 0; } + } + class goo + { + int x = 0; + } + """, """ + class Class5 + { + delegate void Del(int x); + public int Age { get { int age = 0; return age; } } + public int Age2 + { + get { int age2 = 0; return age2; } + set { int age2 = value; } + } + void bar() + { + int x = 0; + if(x == 1) x = 2; else x =3; + do { x = 4; } while (x != 4); + switch (x) { case 1: break; case 2: break; default: break; } + Del d = delegate(int k) { Console.WriteLine(); Console.WriteLine(); }; + } + void goo(){int y=0; int z =0 ;} + } + class goo + { + int x = 0; + } + """, changingOptions); } -}", -@"class Class2 -{ - void M() + + [Fact] + public async Task TestWrappingNonDefault() + { + var changingOptions = new OptionsCollection(LanguageNames.CSharp) + { + { CSharpFormattingOptions2.WrappingPreserveSingleLine, false }, + { CSharpFormattingOptions2.WrappingKeepStatementsOnSingleLine, false } + }; + await AssertFormatAsync(""" + class Class5 + { + delegate void Del(int x); + public int Age + { + get + { + int age = 0; + return age; + } + } + public int Age2 + { + get + { + int age2 = 0; + return age2; + } + set + { + int age2 = value; + } + } + void bar() + { + int x = 0; + if (x == 1) + x = 2; + else + x = 3; + do + { + x = 4; + } while (x != 4); + switch (x) + { + case 1: + break; + case 2: + break; + default: + break; + } + Del d = delegate (int k) + { + Console.WriteLine(); + Console.WriteLine(); + }; + } + } + class goo + { + int x = 0; + } + """, """ + class Class5 + { + delegate void Del(int x); + public int Age { get { int age = 0; return age; } } + public int Age2 + { + get { int age2 = 0; return age2; } + set { int age2 = value; } + } + void bar() + { + int x = 0; + if(x == 1) x = 2; else x =3; + do { x = 4; } while (x != 4); + switch (x) { case 1: break; case 2: break; default: break; } + Del d = delegate(int k) { Console.WriteLine(); Console.WriteLine(); }; + } + } + class goo{int x = 0;} + """, changingOptions); + } + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/991480")] + public async Task TestLeaveStatementMethodDeclarationSameLineNotAffectingForStatement() + { + var changingOptions = new OptionsCollection(LanguageNames.CSharp) + { + { CSharpFormattingOptions2.WrappingKeepStatementsOnSingleLine, false } + }; + await AssertFormatAsync(""" + class Program + { + static void Main(string[] args) + { + for (int d = 0; d < 10; ++d) + { } + } + } + """, """ + class Program + { + static void Main(string[] args) + { + for (int d = 0; d < 10; ++d) { } + } + } + """, changingOptions); + } + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/751789")] + public async Task NewLineForOpenBracesDefault() { - switch (i) { - case 0: { + await AssertFormatAsync(""" + class f00 + { + void br() + { + Func ret = x => + { + return x + 1; + }; + var obj = new + { + // ... + }; + if (true) + { + System.Console.WriteLine(""); + } + else + { + } + timer.Tick += delegate (object sender, EventArgs e) + + + { + MessageBox.Show(this, "Timer ticked"); + }; + + var obj1 = new goo + { + }; + + async void LocalFunction() + { + } + + try + { + } + catch (Exception e) + { + } + finally + { } + + using (someVar) + { + } + + switch (switchVar) + { + default: + break; + } + } + } + + namespace NS1 + { + public class goo : System.Object + + + + { + public int f { get; set; } + } + } + """, """ + class f00 + { + void br() { + Func ret = x => + { + return x + 1; + }; + var obj = new + { + // ... + }; + if(true) + { + System.Console.WriteLine(""); + } + else + { + } + timer.Tick += delegate (object sender, EventArgs e) + + + { + MessageBox.Show(this, "Timer ticked"); + }; + + var obj1 = new goo + { + }; + + async void LocalFunction() { + } + + try + { + } + catch (Exception e) + { + } + finally + {} + + using (someVar) + { + } + + switch (switchVar) + { + default: + break; + } + } + } + + namespace NS1 { + public class goo : System.Object + + + + { + public int f { get; set; } + } + } + """); } - case 1: - break; + + [Fact, WorkItem("https://developercommunity.visualstudio.com/content/problem/8808/c-structure-guide-lines-for-unsafe-fixed.html")] + [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/751789")] + public async Task NewLineForOpenBracesNonDefault() + { + var changingOptions = new OptionsCollection(LanguageNames.CSharp) + { + { NewLineBeforeOpenBrace, NewLineBeforeOpenBracePlacement.None } + }; + await AssertFormatAsync(""" + class f00 { + void br() { + Func ret = x => { + return x + 1; + }; + var obj = new { + // ... + }; + if (true) { + System.Console.WriteLine(""); + } + else { + } + timer.Tick += delegate (object sender, EventArgs e) { + MessageBox.Show(this, "Timer ticked"); + }; + + var obj1 = new goo { + }; + + async void LocalFunction() { + } + + try { + } + catch (Exception e) { + } + finally { } + + using (someVar) { + } + + switch (switchVar) { + default: + break; + } + + unsafe { + } + + fixed (int* p = &i) { + } + } + } + + namespace NS1 { + public class goo : System.Object { + } + } + """, """ + class f00 + { + void br() { + Func ret = x => + { + return x + 1; + }; + var obj = new + { + // ... + }; + if(true) + { + System.Console.WriteLine(""); + } + else + { } + timer.Tick += delegate (object sender, EventArgs e) + + + { + MessageBox.Show(this, "Timer ticked"); + }; + + var obj1 = new goo + { + }; + + async void LocalFunction() + { + } + + try + { + } + catch (Exception e) + { + } + finally + {} + + using (someVar) + { + } + + switch (switchVar) + { + default: + break; + } + + unsafe + { + } + + fixed (int* p = &i) + { + } + } + } + + namespace NS1 { + public class goo : System.Object + + + + { + } + } + """, changingOptions); + } + + [Fact] + public async Task NewLineForKeywordDefault() + { + await AssertFormatAsync(""" + class c + { + void f00() + { + + try + { + // ... + } + catch (Exception e) + { + // ... + } + finally + { + // ... + } + + if (a > b) + { + return 3; + } + else + { + return 0; + } + } + } + """, + """ + class c + { + void f00(){ + + try + { + // ... + } catch (Exception e) + { + // ... + } finally + { + // ... + } + + if (a > b) + { + return 3; + } else + { + return 0; + } + } + } + """); + } + + [Fact] + public async Task NewLineForKeywordNonDefault() + { + var changingOptions = new OptionsCollection(LanguageNames.CSharp) + { + { CSharpFormattingOptions2.NewLineForElse, false }, + { CSharpFormattingOptions2.NewLineForCatch, false }, + { CSharpFormattingOptions2.NewLineForFinally, false } + }; + await AssertFormatAsync(""" + class c + { + void f00() + { + + try + { + // ... + } catch (Exception e) + { + // ... + } finally + { + // ... + } + if (a > b) + { + return 3; + } else + { + return 0; + } + } + } + """, """ + class c + { + void f00(){ + + try + { + // ... + } + + + catch (Exception e) + { + // ... + } + + + finally + { + // ... + } + if (a > b) + { + return 3; + } + + else + { + return 0; + } + } + } + """, changingOptions); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/33458")] + public async Task NoNewLineForElseChecksBraceOwner() + { + var changingOptions = new OptionsCollection(LanguageNames.CSharp) + { + { NewLineForElse, false }, + { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ControlBlocks, false) } + }; + + await AssertFormatAsync(""" + class Class + { + void Method() + { + if (true) + for (int i = 0; i < 10; i++) { + Method(); + } + else + return; + } + } + """, """ + class Class + { + void Method() + { + if (true) + for (int i = 0; i < 10; i++) { + Method(); + } else + return; + } + } + """, changedOptionSet: changingOptions); + } + + [Fact] + public async Task NewLineForExpressionDefault() + { + await AssertFormatAsync(""" + class f00 + { + void br() + { + var queryLowNums = from num in numbers + where num < 5 + select num; + + var queryLowNums = + + from num in numbers + where num < 5 + select num; + + var q = from c in cust + from o in c.Orders + orderby o.Total descending + select new { c.Name, c.OrderID }; + var obj = new + { + X1 = 0, + Y1 = 1, + X2 = 2, + Y2 = 3 + }; + var obj1 = new { X1 = 0, Y1 = 1, X2 = 2, Y2 = 3 }; + MyObject obj = new MyObject + { + X1 = 0, + Y1 = 1, + X2 = 2, + Y2 = 3 + }; + MyObject obj = new MyObject { X1 = 0, Y1 = 1, X2 = 2, Y2 = 3 }; + } + } + """, """ + class f00 + { + void br() + { + var queryLowNums = from num in numbers where num < 5 + select num; + + var queryLowNums = + + from num in numbers where num < 5 + select num; + + var q = from c in cust + from o in c.Orders orderby o.Total descending + select new { c.Name, c.OrderID }; + var obj = new { X1 = 0, Y1 = 1, + X2 = 2, + Y2 = 3 + }; + var obj1 = new { X1 = 0, Y1 = 1, X2 = 2, Y2 = 3 }; + MyObject obj = new MyObject { X1 = 0, Y1 = 1, + X2 = 2, + Y2 = 3 + }; + MyObject obj = new MyObject { X1 = 0, Y1 = 1, X2 = 2, Y2 = 3 }; + } + } + """); + } + + [Fact] + public async Task NewLineForExpressionNonDefault() + { + var changingOptions = new OptionsCollection(LanguageNames.CSharp) + { + { CSharpFormattingOptions2.NewLineForMembersInObjectInit, false }, + { CSharpFormattingOptions2.NewLineForMembersInAnonymousTypes, false }, + { CSharpFormattingOptions2.NewLineForClausesInQuery, false } + }; + await AssertFormatAsync(""" + class f00 + { + void br() + { + + var queryLowNums = from num in numbers where num < 5 + select num; + + var queryLowNums = + + from num in numbers where num < 5 + select num; + + var q = from c in cust + from o in c.Orders orderby o.Total descending + select new { c.Name, c.OrderID }; + var obj = new + { + X1 = 0, Y1 = 1, + X2 = 2, + Y2 = 3 + }; + MyObject obj = new MyObject + { + X1 = 0, Y1 = 1, + X2 = 2, + Y2 = 3 + }; + } + } + """, """ + class f00 + { + void br() + { + + var queryLowNums = from num in numbers where num < 5 + select num; + + var queryLowNums = + + from num in numbers where num < 5 + select num; + + var q = from c in cust + from o in c.Orders orderby o.Total descending + select new { c.Name, c.OrderID }; + var obj = new { X1 = 0, Y1 = 1, + X2 = 2, + Y2 = 3 + }; + MyObject obj = new MyObject { X1 = 0, Y1 = 1, + X2 = 2, + Y2 = 3 + }; + } + } + """, changingOptions); + } + + [Fact] + public async Task Enums_Bug2586() + { + await AssertFormatAsync(""" + enum E + { + a = 10, + b, + c + } + """, """ + enum E + { + a = 10, + b, + c + } + """); + } + + [Fact] + public async Task DoNotInsertLineBreaksInSingleLineEnum() + => await AssertFormatAsync(@"enum E { a = 10, b, c }", @"enum E { a = 10, b, c }"); + + [Fact] + public async Task AlreadyFormattedSwitchIsNotFormatted_Bug2588() + { + await AssertFormatAsync(""" + class C + { + void M() + { + switch (3) + { + case 0: + break; + } + } + } + """, """ + class C + { + void M() + { + switch (3) + { + case 0: + break; + } + } + } + """); + } + + [Fact] + public async Task BreaksAreAlignedInSwitchCasesFormatted_Bug2587() + { + await AssertFormatAsync(""" + class C + { + void M() + { + switch (3) + { + case 0: + break; + } + } + } + """, """ + class C + { + void M() + { + switch (3) + { + case 0: + break; + } + } + } + """); + } + + [Fact] + public async Task BreaksAndBracesAreAlignedInSwitchCasesWithBracesFormatted_Bug2587() + { + await AssertFormatAsync(""" + class C + { + void M() + { + switch (3) + { + case 0: + { + break; + } + } + } + } + """, """ + class C + { + void M() + { + switch (3) + { + case 0: + { + break; + } + } + } + } + """); + } + + [Fact] + public async Task LineBreaksAreNotInsertedForSwitchCasesOnASingleLine1() + { + await AssertFormatAsync(""" + class C + { + void M() + { + switch (3) + { + case 0: break; + default: break; + } + } + } + """, """ + class C + { + void M() + { + switch (3) + { + case 0: break; + default: break; + } + } + } + """); + } + + [Fact] + public async Task LineBreaksAreNotInsertedForSwitchCasesOnASingleLine2() + { + await AssertFormatAsync(""" + class C + { + void M() + { + switch (3) + { + case 0: { break; } + default: { break; } + } + } + } + """, """ + class C + { + void M() + { + switch (3) + { + case 0: { break; } + default: { break; } + } + } + } + """); + } + + [Fact] + public async Task FormatLabelAndGoto1_Bug2588() + { + await AssertFormatAsync(""" + class C + { + void M() + { + Goo: + goto Goo; + } + } + """, """ + class C + { + void M() + { + Goo: + goto Goo; + } + } + """); + } + + [Fact] + public async Task FormatLabelAndGoto2_Bug2588() + { + await AssertFormatAsync(""" + class C + { + void M() + { + int x = 0; + Goo: + goto Goo; + } + } + """, """ + class C + { + void M() + { + int x = 0; + Goo: + goto Goo; + } + } + """); + } + + [Fact] + public async Task FormatNestedLabelAndGoto1_Bug2588() + { + await AssertFormatAsync(""" + class C + { + void M() + { + if (true) + { + Goo: + goto Goo; + } + } + } + """, """ + class C + { + void M() + { + if (true) + { + Goo: + goto Goo; + } + } + } + """); + } + + [Fact] + public async Task FormatNestedLabelAndGoto2_Bug2588() + { + await AssertFormatAsync(""" + class C + { + void M() + { + if (true) + { + int x = 0; + Goo: + goto Goo; + } + } + } + """, """ + class C + { + void M() + { + if (true) + { + int x = 0; + Goo: + goto Goo; + } + } + } + """); + } + + [Fact] + public async Task AlreadyFormattedGotoLabelIsNotFormatted1_Bug2588() + { + await AssertFormatAsync(""" + class C + { + void M() + { + Goo: + goto Goo; + } + } + """, """ + class C + { + void M() + { + Goo: + goto Goo; + } + } + """); + } + + [Fact] + public async Task AlreadyFormattedGotoLabelIsNotFormatted2_Bug2588() + { + await AssertFormatAsync(""" + class C + { + void M() + { + Goo: goto Goo; + } + } + """, """ + class C + { + void M() + { + Goo: goto Goo; + } + } + """); + } + + [Fact] + public async Task AlreadyFormattedGotoLabelIsNotFormatted3_Bug2588() + { + await AssertFormatAsync(""" + class C + { + void M() + { + int x = 0; + Goo: + goto Goo; + } + } + """, """ + class C + { + void M() + { + int x = 0; + Goo: + goto Goo; + } + } + """); + } + + [Fact] + public async Task DoNotAddLineBreakBeforeWhere1_Bug2582() + { + await AssertFormatAsync(""" + class C + { + void M() where T : I + { + } + } + """, """ + class C + { + void M() where T : I + { + } + } + """); + } + + [Fact] + public async Task DoNotAddLineBreakBeforeWhere2_Bug2582() + { + await AssertFormatAsync(""" + class C where T : I + { + } + """, """ + class C where T : I + { + } + """); + } + + [Fact] + public async Task DoNotAddSpaceAfterUnaryMinus() + { + await AssertFormatAsync(""" + class C + { + void M() + { + int x = -1; + } + } + """, """ + class C + { + void M() + { + int x = -1; + } + } + """); + } + + [Fact] + public async Task DoNotAddSpaceAfterUnaryPlus() + { + await AssertFormatAsync(""" + class C + { + void M() + { + int x = +1; + } + } + """, """ + class C + { + void M() + { + int x = +1; + } + } + """); + } + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545909")] + public async Task DoNotAddSpaceAfterIncrement() + { + var code = """ + class C + { + void M(int[] i) + { + ++i[0]; + } + } + """; + await AssertFormatAsync(code, code); + } + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545909")] + public async Task DoNotAddSpaceBeforeIncrement() + { + var code = """ + class C + { + void M(int[] i) + { + i[0]++; + } + } + """; + await AssertFormatAsync(code, code); + } + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545909")] + public async Task DoNotAddSpaceAfterDecrement() + { + var code = """ + class C + { + void M(int[] i) + { + --i[0]; + } + } + """; + await AssertFormatAsync(code, code); + } + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545909")] + public async Task DoNotAddSpaceBeforeDecrement() + { + var code = """ + class C + { + void M(int[] i) + { + i[0]--; + } + } + """; + await AssertFormatAsync(code, code); + } + + [Fact] + public async Task Anchoring() + { + await AssertFormatAsync(""" + class C + { + void M() + { + Console.WriteLine("Goo", + 0, 1, + 2); + } + } + """, """ + class C + { + void M() + { + Console.WriteLine("Goo", + 0, 1, + 2); + } + } + """); + } + + [Fact] + public async Task Exclamation() + { + await AssertFormatAsync(""" + class C + { + void M() + { + if (!true) ; + } + } + """, """ + class C + { + void M() + { + if ( ! true ) ; + } + } + """); + } + + [Fact] + public async Task StartAndEndTrivia() + { + await AssertFormatAsync(""" + + + + class C { } + + + + + + """, """ + + + + class C { } + + + + + + """); + } + + [Fact] + public async Task FirstTriviaAndAnchoring1() + { + await AssertFormatAsync(""" + + namespace N + { + class C + { + void Method() + { + int i = + 1 + + + 3; + } + } + } + + + + + """, """ + + namespace N { + class C { + void Method() { + int i = + 1 + + + 3; + } + } + } + + + + + """); + } + + [Fact] + public async Task FirstTriviaAndAnchoring2() + { + await AssertFormatAsync(""" + + namespace N + { + class C + { + int i = + 1 + + + 3; + } + } + + + + + """, """ + + namespace N { + class C { + int i = + 1 + + + 3; + } + } + + + + + """); + } + + [Fact] + public async Task FirstTriviaAndAnchoring3() + { + await AssertFormatAsync(""" + + + class C + { + int i = + 1 + + + 3; + } + + + + + """, """ + + + class C { + int i = + 1 + + + 3; + } + + + + + """); + } + + [Fact] + public async Task Base1() + { + await AssertFormatAsync(""" + class C + { + C() : base() + { + } + } + """, """ + class C + { + C ( ) : base ( ) + { + } + } + """); + } + + [Fact] + public async Task This1() + { + await AssertFormatAsync(""" + class C + { + C(int i) : this() + { + } + + C() { } + } + """, """ + class C + { + C ( int i ) : this ( ) + { + } + + C ( ) { } + } + """); + } + + [Fact] + public async Task QueryExpression1() + { + await AssertFormatAsync(""" + class C + { + int Method() + { + var q = + from c in from b in cs select b select c; + } + } + """, """ + class C + { + int Method() + { + var q = + from c in from b in cs select b select c; + } + } + """); + } + + [Fact] + public async Task QueryExpression2() + { + await AssertFormatAsync(""" + class C + { + int Method() + { + var q = from c in + from b in cs + select b + select c; + } + } + """, """ + class C + { + int Method() + { + var q = from c in + from b in cs + select b + select c; + } + } + """); + } + + [Fact] + public async Task QueryExpression3() + { + await AssertFormatAsync(""" + class C + { + int Method() + { + var q = from c in Get(1 + + 2 + + 3) + from b in Get(1 + + 2 + + 3) + select new { b, c }; + } + } + """, """ + class C + { + int Method() + { + var q = from c in Get(1 + + 2 + + 3) + from b in Get(1 + + 2 + + 3) + select new { b, c }; + } + } + """); + } + + [Fact] + public async Task QueryExpression4() + { + await AssertFormatAsync(""" + class C + { + int Method() + { + var q = + from c in + from b in cs + select b + select c; + } + } + """, """ + class C + { + int Method() + { + var q = + from c in + from b in cs + select b + select c; + } + } + """); + } + + [Fact] + public async Task Label1() + { + await AssertFormatAsync(""" + class C + { + int Method() + { + L: int i = 10; + } + } + """, """ + class C + { + int Method() + { + L : int i = 10 ; + } + } + """); + } + + [Fact] + public async Task Label2() + { + await AssertFormatAsync(""" + class C + { + int Method() + { + int x = 1; + L: int i = 10; + } + } + """, """ + class C + { + int Method() + { + int x = 1 ; + L : int i = 10 ; + } + } + """); } -}", changedOptionSet: changingOptions); - } - [Fact] - public async Task TestWrappingDefault() - { - await AssertFormatAsync(@"class Class5 -{ - delegate void Del(int x); - public int Age { get { int age = 0; return age; } } - public int Age2 - { - get { int age2 = 0; return age2; } - set { int age2 = value; } - } - void bar() + [Fact] + public async Task Label3() { - int x = 0; - if (x == 1) x = 2; else x = 3; - do { x = 4; } while (x != 4); - switch (x) { case 1: break; case 2: break; default: break; } - Del d = delegate (int k) { Console.WriteLine(); Console.WriteLine(); }; + await AssertFormatAsync(""" + class C + { + int Method() + { + int x = 1; + L: + int i = 10; + } + } + """, """ + class C + { + int Method() + { + int x = 1 ; + L : + int i = 10 ; + } + } + """); } -}", @"class Class5 - { - delegate void Del(int x); - public int Age { get { int age = 0; return age; } } - public int Age2 - { - get { int age2 = 0; return age2; } - set { int age2 = value; } - } - void bar() - { - int x = 0; - if(x == 1) x = 2; else x =3; - do { x = 4; } while (x != 4); - switch (x) { case 1: break; case 2: break; default: break; } - Del d = delegate(int k) { Console.WriteLine(); Console.WriteLine(); }; - } - }"); - } - [Fact] - public async Task TestWrappingNonDefault_FormatBlock() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) - { - { CSharpFormattingOptions2.WrappingPreserveSingleLine, false } - }; - await AssertFormatAsync(@"class Class5 -{ - delegate void Del(int x); - public int Age + [Fact] + public async Task Label4() { - get - { - int age = 0; return age; - } + await AssertFormatAsync(""" + class C + { + int Method() + { + int x = 1; + L: int i = 10; + int next = 30; + } + } + """, """ + class C + { + int Method() + { + int x = 1 ; + L : int i = 10 ; + int next = 30; + } + } + """); } - public int Age2 + + [Fact] + public async Task Label5() { - get - { - int age2 = 0; return age2; - } - set - { - int age2 = value; - } + await AssertFormatAsync(""" + class C + { + int Method() + { + L: int i = 10; + int next = 30; + } + } + """, """ + class C + { + int Method() + { + L : int i = 10 ; + int next = 30; + } + } + """); } - void bar() + + [Fact] + public async Task Label6() { - int x = 0; - if (x == 1) x = 2; else x = 3; - do { x = 4; } while (x != 4); - switch (x) - { - case 1: break; - case 2: break; - default: break; - } - Del d = delegate (int k) { Console.WriteLine(); Console.WriteLine(); }; + await AssertFormatAsync(""" + class C + { + int Method() + { + L: + int i = 10; + int next = 30; + } + } + """, """ + class C + { + int Method() + { + L : + int i = 10 ; + int next = 30; + } + } + """); } - void goo() + + [Fact] + public async Task Label7() { - int xx = 0; int zz = 0; + await AssertFormatAsync(""" + class C + { + int Method() + { + int i2 = 1; + L: + int i = 10; + int next = 30; + } + } + """, """ + class C + { + int Method() + { + int i2 = 1 ; + L : + int i = 10 ; + int next = 30; + } + } + """); } -} -class goo -{ - int x = 0; -}", @"class Class5 -{ - delegate void Del(int x); - public int Age { get { int age = 0; return age; } } - public int Age2 - { - get { int age2 = 0; return age2; } - set { int age2 = value; } - } - void bar() - { - int x = 0; - if(x == 1) x = 2; else x =3; - do { x = 4; } while (x != 4); - switch (x) { case 1: break; case 2: break; default: break; } - Del d = delegate(int k) { Console.WriteLine(); Console.WriteLine(); }; - } - void goo() { int xx = 0; int zz = 0;} -} -class goo{int x = 0;}", changingOptions); - } - [Fact] - public async Task TestWrappingNonDefault_FormatStatmtMethDecl() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) + [Fact] + public async Task Label8() + { + await AssertFormatAsync(""" + class C { - { CSharpFormattingOptions2.WrappingKeepStatementsOnSingleLine, false } - }; - await AssertFormatAsync(@"class Class5 -{ - delegate void Del(int x); - public int Age { get { int age = 0; return age; } } - public int Age2 - { - get { int age2 = 0; return age2; } - set { int age2 = value; } - } - void bar() - { - int x = 0; - if (x == 1) - x = 2; - else - x = 3; - do - { x = 4; } while (x != 4); - switch (x) - { - case 1: - break; - case 2: - break; - default: - break; - } - Del d = delegate (int k) - { Console.WriteLine(); Console.WriteLine(); }; + int Method() + { + L: + int i = + 10; + } + } + """, """ + class C + { + int Method() + { + L: + int i = + 10; + } + } + """); } - void goo() { int y = 0; int z = 0; } -} -class goo -{ - int x = 0; -}", @"class Class5 -{ - delegate void Del(int x); - public int Age { get { int age = 0; return age; } } - public int Age2 - { - get { int age2 = 0; return age2; } - set { int age2 = value; } - } - void bar() - { - int x = 0; - if(x == 1) x = 2; else x =3; - do { x = 4; } while (x != 4); - switch (x) { case 1: break; case 2: break; default: break; } - Del d = delegate(int k) { Console.WriteLine(); Console.WriteLine(); }; - } - void goo(){int y=0; int z =0 ;} -} -class goo -{ - int x = 0; -}", changingOptions); - } - [Fact] - public async Task TestWrappingNonDefault() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) - { - { CSharpFormattingOptions2.WrappingPreserveSingleLine, false }, - { CSharpFormattingOptions2.WrappingKeepStatementsOnSingleLine, false } - }; - await AssertFormatAsync(@"class Class5 -{ - delegate void Del(int x); - public int Age + [Fact] + public async Task AutoProperty() { - get - { - int age = 0; - return age; - } + await AssertFormatAsync(""" + class Class + { + private int Age { get; set; } + public string Names { get; set; } + } + """, """ + class Class + { + private int Age{get; set; } + public string Names { get; set;} + } + """); } - public int Age2 + + [Fact] + public async Task NormalPropertyGet() { - get - { - int age2 = 0; - return age2; - } - set - { - int age2 = value; - } + await AssertFormatAsync(""" + class Class + { + private string name; + public string Names + { + get + { + return name; + } + } + } + """, """ + class Class + { + private string name; + public string Names + { + get + { + return name; + } + } + } + """); } - void bar() + + [Fact] + public async Task NormalPropertyBoth() { - int x = 0; - if (x == 1) - x = 2; - else - x = 3; - do - { - x = 4; - } while (x != 4); - switch (x) - { - case 1: - break; - case 2: - break; - default: - break; - } - Del d = delegate (int k) - { - Console.WriteLine(); - Console.WriteLine(); - }; + await AssertFormatAsync(""" + class Class + { + private string name; + public string Names + { + get + { + return name; + } + set + { + name = value; + } + } + } + """, """ + class Class + { + private string name; + public string Names + { + get + { + return name; + } + set + { + name = value; + } + } + } + """); } -} -class goo -{ - int x = 0; -}", @"class Class5 -{ - delegate void Del(int x); - public int Age { get { int age = 0; return age; } } - public int Age2 - { - get { int age2 = 0; return age2; } - set { int age2 = value; } - } - void bar() - { - int x = 0; - if(x == 1) x = 2; else x =3; - do { x = 4; } while (x != 4); - switch (x) { case 1: break; case 2: break; default: break; } - Del d = delegate(int k) { Console.WriteLine(); Console.WriteLine(); }; - } -} -class goo{int x = 0;}", changingOptions); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/991480")] - public async Task TestLeaveStatementMethodDeclarationSameLineNotAffectingForStatement() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) - { - { CSharpFormattingOptions2.WrappingKeepStatementsOnSingleLine, false } - }; - await AssertFormatAsync(@"class Program -{ - static void Main(string[] args) + [Fact] + public async Task ErrorHandling1() { - for (int d = 0; d < 10; ++d) - { } + await AssertFormatAsync(""" + class C + { + int Method() + { + int a b c; + } + } + """, """ + class C + { + int Method() + { + int a b c ; + } + } + """); } -}", @"class Program -{ - static void Main(string[] args) + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537763")] + public async Task NullableType() { - for (int d = 0; d < 10; ++d) { } + await AssertFormatAsync(""" + class Program + { + static void Main(string[] args) + { + int? i = 10; + } + } + """, """ + class Program + { + static void Main(string[] args) + { + int ? i = 10; + } + } + """); } -}", changingOptions); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/751789")] - public async Task NewLineForOpenBracesDefault() - { - await AssertFormatAsync(@"class f00 -{ - void br() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537766")] + public async Task SuppressWrappingOnBraces() { - Func ret = x => - { - return x + 1; - }; - var obj = new - { - // ... - }; - if (true) - { - System.Console.WriteLine(""""); - } - else - { - } - timer.Tick += delegate (object sender, EventArgs e) - - -{ - MessageBox.Show(this, ""Timer ticked""); -}; - - var obj1 = new goo - { - }; - - async void LocalFunction() - { - } + await AssertFormatAsync(""" + class Class1 + { } - try - { - } - catch (Exception e) - { - } - finally - { } + """, """ + class Class1 + {} - using (someVar) - { - } - - switch (switchVar) - { - default: - break; - } + """); } -} - -namespace NS1 -{ - public class goo : System.Object - - + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537824")] + public async Task DoWhile() { - public int f { get; set; } - } -}", @"class f00 -{ - void br() { -Func ret = x => - { - return x + 1; - }; -var obj = new - { - // ... - }; -if(true) -{ - System.Console.WriteLine(""""); - } -else -{ -} - timer.Tick += delegate (object sender, EventArgs e) - - -{ - MessageBox.Show(this, ""Timer ticked""); - }; - -var obj1 = new goo + await AssertFormatAsync(""" + public class Class1 { - }; - - async void LocalFunction() { - } - - try - { - } - catch (Exception e) - { - } - finally - {} - - using (someVar) - { - } - - switch (switchVar) - { - default: - break; - } -} -} - -namespace NS1 { -public class goo : System.Object + void Goo() + { + do + { + } while (true); + } + } + """, """ + public class Class1 + { + void Goo() + { + do + { + }while (true); + } + } + """); + } -{ - public int f { get; set; } -} -}"); - } + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537774")] + public async Task SuppressWrappingBug() + { + await AssertFormatAsync(""" + class Class1 + { + int Goo() + { + return 0; + } + } - [Fact, WorkItem("https://developercommunity.visualstudio.com/content/problem/8808/c-structure-guide-lines-for-unsafe-fixed.html")] - [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/751789")] - public async Task NewLineForOpenBracesNonDefault() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) + """, """ + class Class1 { - { NewLineBeforeOpenBrace, NewLineBeforeOpenBracePlacement.None } - }; - await AssertFormatAsync(@"class f00 { - void br() { - Func ret = x => { - return x + 1; - }; - var obj = new { - // ... - }; - if (true) { - System.Console.WriteLine(""""); - } - else { - } - timer.Tick += delegate (object sender, EventArgs e) { - MessageBox.Show(this, ""Timer ticked""); - }; + int Goo() + {return 0; + } + } - var obj1 = new goo { - }; + """); + } - async void LocalFunction() { - } + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537768")] + public async Task PreserveLineForAttribute() + { + await AssertFormatAsync(""" + class Class1 + { + [STAThread] + static void Main(string[] args) + { + } + } - try { - } - catch (Exception e) { - } - finally { } + """, """ + class Class1 + { + [STAThread] + static void Main(string[] args) + { + } + } - using (someVar) { - } + """); + } - switch (switchVar) { - default: - break; - } + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537878")] + public async Task NoFormattingOnMissingTokens() + { + await AssertFormatAsync(""" + namespace ClassLibrary1 + { + class Class1 + { + void Goo() + { + if (true) + } + } + } - unsafe { - } + """, """ + namespace ClassLibrary1 + { + class Class1 + { + void Goo() + { + if (true) + } + } + } - fixed (int* p = &i) { - } + """); } -} -namespace NS1 { - public class goo : System.Object { - } -}", @"class f00 -{ - void br() { -Func ret = x => -{ - return x + 1; - }; -var obj = new - { - // ... - }; -if(true) -{ - System.Console.WriteLine(""""); - } -else -{ -} - timer.Tick += delegate (object sender, EventArgs e) + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537783")] + public async Task UnaryExpression() + { + await AssertFormatAsync(""" + class Program + { + static void Main(string[] args) + { + int a = 6; + a = a++ + 5; + } + } + """, """ + class Program + { + static void Main(string[] args) + { + int a = 6; + a = a++ + 5; + } + } -{ - MessageBox.Show(this, ""Timer ticked""); - }; + """); + } -var obj1 = new goo + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537885")] + public async Task Pointer() + { + await AssertFormatAsync(""" + class Program { - }; + static void Main(string[] args) + { + int* p; + } + } - async void LocalFunction() + """, """ + class Program { - } + static void Main(string[] args) + { + int* p; + } + } - try - { - } - catch (Exception e) - { - } - finally - {} + """); + } - using (someVar) - { - } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/50723")] + public async Task TuplePointer() + { + var properlyFormattedCode = """ + public unsafe static class Program + { + public static void Main(string[] args) + { + int* intPointer = null; + (int, int)* intIntPointer = null; + } + } - switch (switchVar) - { - default: - break; - } + """; + await AssertFormatAsync(properlyFormattedCode, properlyFormattedCode); + } - unsafe -{ - } + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537886")] + public async Task Tild() + { + await AssertFormatAsync(""" + class Program + { + static void Main(string[] args) + { + int j = 103; + j = ~7; + } + } - fixed (int* p = &i) -{ - } -} -} + """, """ + class Program + { + static void Main(string[] args) + { + int j = 103; + j = ~7; + } + } -namespace NS1 { -public class goo : System.Object + """); + } + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537884")] + public async Task ArrayInitializer1() + { + await AssertFormatAsync(""" + class Program + { + static void Main(string[] args) + { + int[] arr = {1,2, + 3,4 + }; + } + } + """, """ + class Program + { + static void Main(string[] args) + { + int[] arr = {1,2, + 3,4 + }; + } + } -{ -} -}", changingOptions); - } + """); + } - [Fact] - public async Task NewLineForKeywordDefault() - { - await AssertFormatAsync(@"class c -{ - void f00() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537884")] + public async Task ArrayInitializer2() { + await AssertFormatAsync(""" + class Program + { + static void Main(string[] args) + { + int[] arr = new int[] {1,2, + 3,4 + }; + } + } - try - { - // ... - } - catch (Exception e) - { - // ... - } - finally - { - // ... - } + """, """ + class Program + { + static void Main(string[] args) + { + int[] arr = new int [] {1,2, + 3,4 + }; + } + } - if (a > b) - { - return 3; - } - else - { - return 0; - } + """); } -}", - @"class c -{ -void f00(){ - -try -{ - // ... -} catch (Exception e) -{ - // ... -} finally -{ - // ... -} -if (a > b) -{ - return 3; -} else -{ - return 0; -} -} -}"); - } + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537884")] + public async Task ImplicitArrayInitializer() + { + await AssertFormatAsync(""" + class Program + { + static void Main(string[] args) + { + var arr = new[] {1,2, + 3,4 + }; + } + } - [Fact] - public async Task NewLineForKeywordNonDefault() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) + """, """ + class Program { - { CSharpFormattingOptions2.NewLineForElse, false }, - { CSharpFormattingOptions2.NewLineForCatch, false }, - { CSharpFormattingOptions2.NewLineForFinally, false } - }; - await AssertFormatAsync(@"class c -{ - void f00() - { + static void Main(string[] args) + { + var arr = new [] {1,2, + 3,4 + } ; + } + } - try - { - // ... - } catch (Exception e) - { - // ... - } finally - { - // ... - } - if (a > b) - { - return 3; - } else - { - return 0; - } + """); } -}", @"class c -{ -void f00(){ -try -{ - // ... -} + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/65498")] + public async Task StackAllocArrayInitializer0() + { + await AssertFormatAsync(""" + F(stackalloc int[] + { + 1, + 2, + }); + """, """ + F(stackalloc int[] + { + 1, + 2, + } ); + """); + } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/65498")] + public async Task StackAllocArrayInitializer0_Implicit() + { + await AssertFormatAsync(""" + F(stackalloc[] + { + 1, + 2, + } + ); + """, """ + F( stackalloc [] + { + 1, + 2, + } + ); + """); + } -catch (Exception e) -{ - // ... -} + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/65498")] + public async Task StackAllocArrayInitializer1() + { + await AssertFormatAsync(""" + F( + stackalloc int[] + { + 1,2, + 3,4 + } + ); + """, """ + F( + stackalloc int[] + { + 1,2, + 3,4 + } + ); + """); + } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/65498")] + public async Task StackAllocArrayInitializer1_Implicit() + { + await AssertFormatAsync(""" + F( + stackalloc[] + { + 1,2, + 3,4 + } + ); + """, """ + F( + stackalloc [] + { + 1,2, + 3,4 + } + ); + """); + } - finally -{ - // ... -} -if (a > b) -{ - return 3; -} + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/65498")] + public async Task StackAllocArrayInitializer2() + { + await AssertFormatAsync(""" + var x = (stackalloc int[] {1,2, + 3 + }); + """, """ + var x = (stackalloc int[] {1,2, + 3 + }); + """); + } -else -{ - return 0; -} -} -}", changingOptions); - } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/65498")] + public async Task StackAllocArrayInitializer2_Implicit() + { + await AssertFormatAsync(""" + var x = (stackalloc[] + {1, + 2, 3 + }); + """, """ + var x = (stackalloc [] + {1, + 2, 3 + }); + """); + } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/33458")] - public async Task NoNewLineForElseChecksBraceOwner() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537884")] + public async Task CollectionInitializer() + { + await AssertFormatAsync(""" + class Program { - { NewLineForElse, false }, - { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ControlBlocks, false) } - }; + static void Main(string[] args) + { + var arr = new List {1,2, + 3,4 + }; + } + } - await AssertFormatAsync(@"class Class -{ - void Method() - { - if (true) - for (int i = 0; i < 10; i++) { - Method(); + """, """ + class Program + { + static void Main(string[] args) + { + var arr = new List {1,2, + 3,4 + }; + } } - else - return; - } -}", @"class Class -{ - void Method() - { - if (true) - for (int i = 0; i < 10; i++) { - Method(); - } else - return; + + """); } -}", changedOptionSet: changingOptions); - } - [Fact] - public async Task NewLineForExpressionDefault() - { - await AssertFormatAsync(@"class f00 -{ - void br() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537916")] + public async Task AddressOfOperator() { - var queryLowNums = from num in numbers - where num < 5 - select num; - - var queryLowNums = + await AssertFormatAsync(""" + unsafe class Class1 + { + void Method() + { + int a = 12; + int* p = &a; + } + } - from num in numbers - where num < 5 - select num; + """, """ + unsafe class Class1 + { + void Method() + { + int a = 12; + int* p = &a; + } + } - var q = from c in cust - from o in c.Orders - orderby o.Total descending - select new { c.Name, c.OrderID }; - var obj = new - { - X1 = 0, - Y1 = 1, - X2 = 2, - Y2 = 3 - }; - var obj1 = new { X1 = 0, Y1 = 1, X2 = 2, Y2 = 3 }; - MyObject obj = new MyObject - { - X1 = 0, - Y1 = 1, - X2 = 2, - Y2 = 3 - }; - MyObject obj = new MyObject { X1 = 0, Y1 = 1, X2 = 2, Y2 = 3 }; + """); } -}", @"class f00 -{ - void br() - { -var queryLowNums = from num in numbers where num < 5 - select num; - -var queryLowNums = - - from num in numbers where num < 5 - select num; - - var q = from c in cust -from o in c.Orders orderby o.Total descending - select new { c.Name, c.OrderID }; -var obj = new { X1 = 0, Y1 = 1, - X2 = 2, - Y2 = 3 - }; -var obj1 = new { X1 = 0, Y1 = 1, X2 = 2, Y2 = 3 }; - MyObject obj = new MyObject { X1 = 0, Y1 = 1, - X2 = 2, - Y2 = 3 - }; -MyObject obj = new MyObject { X1 = 0, Y1 = 1, X2 = 2, Y2 = 3 }; - } -}"); - } - [Fact] - public async Task NewLineForExpressionNonDefault() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) - { - { CSharpFormattingOptions2.NewLineForMembersInObjectInit, false }, - { CSharpFormattingOptions2.NewLineForMembersInAnonymousTypes, false }, - { CSharpFormattingOptions2.NewLineForClausesInQuery, false } - }; - await AssertFormatAsync(@"class f00 -{ - void br() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537885")] + public async Task DereferenceOperator() { + await AssertFormatAsync(""" + unsafe class Class1 + { + void Method() + { + int a = 12; + int* p = &a; + Console.WriteLine(*p); + } + } - var queryLowNums = from num in numbers where num < 5 - select num; + """, """ + unsafe class Class1 + { + void Method() + { + int a = 12; + int* p = & a; + Console.WriteLine(* p); + } + } - var queryLowNums = + """); + } - from num in numbers where num < 5 - select num; + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537905")] + public async Task Namespaces() + { + await AssertFormatAsync(""" + using System; + using System.Data; + """, @"using System; using System.Data;"); + } - var q = from c in cust - from o in c.Orders orderby o.Total descending - select new { c.Name, c.OrderID }; - var obj = new - { - X1 = 0, Y1 = 1, - X2 = 2, - Y2 = 3 - }; - MyObject obj = new MyObject - { - X1 = 0, Y1 = 1, - X2 = 2, - Y2 = 3 - }; + [Fact] + public async Task NamespaceDeclaration() + { + await AssertFormatAsync(""" + namespace N + { + } + """, """ + namespace N + { + } + """); } -}", @"class f00 -{ - void br() + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537902")] + public async Task DoWhile1() { + await AssertFormatAsync(""" + class Program + { + static void Main(string[] args) + { + do { } + while (i < 4); + } + } + """, """ + class Program + { + static void Main(string[] args) + { + do { } + while (i < 4); + } + } + """); + } -var queryLowNums = from num in numbers where num < 5 - select num; + [Fact] + public async Task NewConstraint() + { + await AssertFormatAsync(""" + class Program + { + void Test(T t) where T : new() + { + } + } + """, """ + class Program + { + void Test(T t) where T : new ( ) + { + } + } + """); + } -var queryLowNums = + [Fact] + public async Task UnaryExpressionWithInitializer() + { + await AssertFormatAsync(""" + using System; + using System.Collections.Generic; + using System.Linq; - from num in numbers where num < 5 - select num; + class Program + { + static void Main(string[] args) + { + if ((new int[] { 1, 2, 3 }).Any()) + { + return; + } + } + } + """, """ + using System; + using System.Collections.Generic; + using System.Linq; - var q = from c in cust -from o in c.Orders orderby o.Total descending - select new { c.Name, c.OrderID }; -var obj = new { X1 = 0, Y1 = 1, - X2 = 2, - Y2 = 3 - }; - MyObject obj = new MyObject { X1 = 0, Y1 = 1, - X2 = 2, - Y2 = 3 - }; + class Program + { + static void Main(string[] args) + { + if ((new int[] { 1, 2, 3 } ).Any()) + { + return; + } + } + } + """); } -}", changingOptions); - } - - [Fact] - public async Task Enums_Bug2586() - { - await AssertFormatAsync(@"enum E -{ - a = 10, - b, - c -}", @"enum E -{ - a = 10, - b, - c -}"); - } - [Fact] - public async Task DoNotInsertLineBreaksInSingleLineEnum() - => await AssertFormatAsync(@"enum E { a = 10, b, c }", @"enum E { a = 10, b, c }"); - - [Fact] - public async Task AlreadyFormattedSwitchIsNotFormatted_Bug2588() - { - await AssertFormatAsync(@"class C -{ - void M() + [Fact] + public async Task Attributes1() { - switch (3) - { - case 0: - break; - } + await AssertFormatAsync(""" + class Program + { + [Flags] public void Method() { } + } + """, """ + class Program + { + [ Flags ] public void Method ( ) { } + } + """); } -}", @"class C -{ - void M() + + [Fact] + public async Task Attributes2() { - switch (3) - { - case 0: - break; - } + await AssertFormatAsync(""" + class Program + { + [Flags] + public void Method() { } + } + """, """ + class Program + { + [ Flags ] + public void Method ( ) { } + } + """); } -}"); - } - [Fact] - public async Task BreaksAreAlignedInSwitchCasesFormatted_Bug2587() - { - await AssertFormatAsync(@"class C -{ - void M() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538288")] + public async Task ColonColon1() { - switch (3) - { - case 0: - break; - } + await AssertFormatAsync(""" + class Program + { + public void Method() + { + throw new global::System.NotImplementedException(); + } + } + """, """ + class Program + { + public void Method ( ) { + throw new global :: System.NotImplementedException(); + } + } + """); } -}", @"class C -{ - void M() + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538354")] + public async Task BugFix3939() { - switch (3) - { - case 0: - break; - } + await AssertFormatAsync(""" + using + System. + Collections. + Generic; + """, """ + using + System. + Collections. + Generic; + """); } -}"); - } - [Fact] - public async Task BreaksAndBracesAreAlignedInSwitchCasesWithBracesFormatted_Bug2587() - { - await AssertFormatAsync(@"class C -{ - void M() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538354")] + public async Task Tab1() + => await AssertFormatAsync(@"using System;", @" using System;"); + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538329")] + public async Task SuppressLinkBreakInIfElseStatement() { - switch (3) - { - case 0: + await AssertFormatAsync(""" + class Program + { + static void Main(string[] args) { - break; + int a; + if (true) a = 10; + else a = 11; } - } - } -}", @"class C -{ - void M() - { - switch (3) - { - case 0: + } + """, """ + class Program { - break; + static void Main(string[] args) + { + int a; + if (true) a = 10; + else a = 11; } - } + } + """); } -}"); - } - [Fact] - public async Task LineBreaksAreNotInsertedForSwitchCasesOnASingleLine1() - { - await AssertFormatAsync(@"class C -{ - void M() - { - switch (3) - { - case 0: break; - default: break; - } - } -}", @"class C -{ - void M() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538464")] + public async Task BugFix4087() { - switch (3) - { - case 0: break; - default: break; - } + await AssertFormatAsync(""" + class Program + { + static void Main(string[] args) + { + Func fun = x => { return x + 1; } + } + } + """, """ + class Program + { + static void Main(string[] args) + { + Func fun = x => { return x + 1; } + } + } + """); } -}"); - } - [Fact] - public async Task LineBreaksAreNotInsertedForSwitchCasesOnASingleLine2() - { - await AssertFormatAsync(@"class C -{ - void M() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538511")] + public async Task AttributeTargetSpecifier() { - switch (3) - { - case 0: { break; } - default: { break; } - } + var code = """ + public class Class1 + { + [method : + void Test() + { + } + } + """; + + var expected = """ + public class Class1 + { + [method: + void Test() + { + } + } + """; + + await AssertFormatAsync(expected, code); } -}", @"class C -{ - void M() + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538635")] + public async Task Finalizer() { - switch (3) - { - case 0: { break; } - default: { break; } - } + var code = """ + public class Class1 + { + ~ Class1() { } + } + """; + + var expected = """ + public class Class1 + { + ~Class1() { } + } + """; + + await AssertFormatAsync(expected, code); } -}"); - } - [Fact] - public async Task FormatLabelAndGoto1_Bug2588() - { - await AssertFormatAsync(@"class C -{ - void M() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538743")] + public async Task BugFix4442() { - Goo: - goto Goo; + var code = """ + class Program + { + static void Main(string[] args) + { + string str = "ab,die|wo"; + string[] a = str.Split(new char[] { ',', '|' }) + ; + } + } + """; + + await AssertFormatAsync(code, code); } -}", @"class C -{ - void M() + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538658")] + public async Task BugFix4328() { -Goo: -goto Goo; + var code = """ + class Program + { + static void Main(string[] args) + { + double d = new double (); + } + } + """; + var expected = """ + class Program + { + static void Main(string[] args) + { + double d = new double(); + } + } + """; + await AssertFormatAsync(expected, code); } -}"); - } - [Fact] - public async Task FormatLabelAndGoto2_Bug2588() - { - await AssertFormatAsync(@"class C -{ - void M() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538658")] + public async Task BugFix4515() { - int x = 0; - Goo: - goto Goo; + var code = """ + class Program + { + static void Main(string[] args) + { + var t = typeof ( System.Object ) ; + var t1 = default ( System.Object ) ; + var t2 = sizeof ( System.Object ) ; + } + } + """; + var expected = """ + class Program + { + static void Main(string[] args) + { + var t = typeof(System.Object); + var t1 = default(System.Object); + var t2 = sizeof(System.Object); + } + } + """; + await AssertFormatAsync(expected, code); } -}", @"class C -{ - void M() + + [Fact] + public async Task CastExpressionTest() { -int x = 0; -Goo: -goto Goo; + var code = """ + class Program + { + static void Main(string[] args) + { + var a = (int) 1; + } + } + """; + var expected = """ + class Program + { + static void Main(string[] args) + { + var a = (int)1; + } + } + """; + await AssertFormatAsync(expected, code); } -}"); - } - [Fact] - public async Task FormatNestedLabelAndGoto1_Bug2588() - { - await AssertFormatAsync(@"class C -{ - void M() + [Fact] + public async Task NamedParameter() { - if (true) - { - Goo: - goto Goo; - } + var code = """ + class Program + { + static void Main(string[] args) + { + Main ( args : null ) ; + } + } + """; + var expected = """ + class Program + { + static void Main(string[] args) + { + Main(args: null); + } + } + """; + await AssertFormatAsync(expected, code); } -}", @"class C -{ - void M() + + [Fact] + public async Task RefReadonlyParameters() { -if (true) -{ -Goo: -goto Goo; -} + var code = """ + class C + { + int this [ ref readonly int x , ref readonly int y ] { get ; set ; } + void M ( ref readonly int x , ref readonly int y ) { } + } + """; + var expected = """ + class C + { + int this[ref readonly int x, ref readonly int y] { get; set; } + void M(ref readonly int x, ref readonly int y) { } + } + """; + await AssertFormatAsync(expected, code); } -}"); - } - [Fact] - public async Task FormatNestedLabelAndGoto2_Bug2588() - { - await AssertFormatAsync(@"class C -{ - void M() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539259")] + public async Task BugFix5143() { - if (true) - { - int x = 0; - Goo: - goto Goo; - } + var code = """ + class Program + { + static void Main(string[] args) + { + int x = Goo ( + delegate ( int x ) { return x ; } ) ; + } + } + """; + var expected = """ + class Program + { + static void Main(string[] args) + { + int x = Goo( + delegate (int x) { return x; }); + } + } + """; + await AssertFormatAsync(expected, code); } -}", @"class C -{ - void M() + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539338")] + public async Task BugFix5251() { -if (true) -{ -int x = 0; -Goo: -goto Goo; -} + var code = """ + class Program + { + public static string Goo { get; private set; } + } + """; + var expected = """ + class Program + { + public static string Goo { get; private set; } + } + """; + await AssertFormatAsync(expected, code); } -}"); - } - [Fact] - public async Task AlreadyFormattedGotoLabelIsNotFormatted1_Bug2588() - { - await AssertFormatAsync(@"class C -{ - void M() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539358")] + public async Task BugFix5277() { - Goo: - goto Goo; + var code = """ + + #if true + #endif + + """; + var expected = """ + + #if true + #endif + + """; + await AssertFormatAsync(expected, code); } -}", @"class C -{ - void M() + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539542")] + public async Task BugFix5544() { - Goo: - goto Goo; + var code = """ + + class Program + { + unsafe static void Main(string[] args) + { + Program* p; + p -> Goo = 5; + } + } + + """; + var expected = """ + + class Program + { + unsafe static void Main(string[] args) + { + Program* p; + p->Goo = 5; + } + } + + """; + await AssertFormatAsync(expected, code); } -}"); - } - [Fact] - public async Task AlreadyFormattedGotoLabelIsNotFormatted2_Bug2588() - { - await AssertFormatAsync(@"class C -{ - void M() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539587")] + public async Task BugFix5602() { - Goo: goto Goo; + var code = """ + class Bug + { + public static void func() + { + long b = // + } + } + """; + var expected = """ + class Bug + { + public static void func() + { + long b = // + } + } + """; + await AssertFormatAsync(expected, code); } -}", @"class C -{ - void M() + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539616")] + public async Task BugFix5637() { - Goo: goto Goo; + var code = """ + class Bug + { + // test + public static void func() + { + } + } + """; + var expected = """ + class Bug + { + // test + public static void func() + { + } + } + """; + await AssertFormatAsync(expected, code); } -}"); - } - [Fact] - public async Task AlreadyFormattedGotoLabelIsNotFormatted3_Bug2588() - { - await AssertFormatAsync(@"class C -{ - void M() + [Fact] + public async Task GenericType() { - int x = 0; - Goo: - goto Goo; + var code = """ + class Bug + { + class N : Bug< T [ ] > + { + } + } + """; + var expected = """ + class Bug + { + class N : Bug + { + } + } + """; + await AssertFormatAsync(expected, code); } -}", @"class C -{ - void M() + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539878")] + public async Task BugFix5978() { - int x = 0; - Goo: - goto Goo; + var code = """ + class Program + { + static void Main(string[] args) + { + int i = 3; + label4: + if (i < 5) + { + label5: + if (i == 4) + { + } + else + { + System.Console.WriteLine("a"); + } + } + } + } + """; + var expected = """ + class Program + { + static void Main(string[] args) + { + int i = 3; + label4: + if (i < 5) + { + label5: + if (i == 4) + { + } + else + { + System.Console.WriteLine("a"); + } + } + } + } + """; + await AssertFormatAsync(expected, code); } -}"); - } - [Fact] - public async Task DoNotAddLineBreakBeforeWhere1_Bug2582() - { - await AssertFormatAsync(@"class C -{ - void M() where T : I + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539878")] + public async Task BugFix5979() { + var code = """ + delegate int del(int i); + class Program + { + static void Main(string[] args) + { + del q = x => + { + label2: goto label1; + label1: return x; + }; + } + } + """; + var expected = """ + delegate int del(int i); + class Program + { + static void Main(string[] args) + { + del q = x => + { + label2: goto label1; + label1: return x; + }; + } + } + """; + await AssertFormatAsync(expected, code); } -}", @"class C -{ - void M() where T : I + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539891")] + public async Task BugFix5993() { + var code = """ + public class MyClass + { + public static void Main() + { + lab1: + { + lab1:// CS0158 + goto lab1; + } + } + } + """; + var expected = """ + public class MyClass + { + public static void Main() + { + lab1: + { + lab1:// CS0158 + goto lab1; + } + } + } + """; + await AssertFormatAsync(expected, code); } -}"); - } - - [Fact] - public async Task DoNotAddLineBreakBeforeWhere2_Bug2582() - { - await AssertFormatAsync(@"class C where T : I -{ -}", @"class C where T : I -{ -}"); - } - [Fact] - public async Task DoNotAddSpaceAfterUnaryMinus() - { - await AssertFormatAsync(@"class C -{ - void M() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540315")] + public async Task BugFix6536() { - int x = -1; + var code = """ + public class MyClass + { + public static void Main() + { + int i = - - 1 + + + 1 + - + 1 + - + 1 ; + } + } + """; + var expected = """ + public class MyClass + { + public static void Main() + { + int i = - -1 + + +1 + -+1 + -+1; + } + } + """; + await AssertFormatAsync(expected, code); } -}", @"class C -{ - void M() + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540801")] + public async Task BugFix7211() { - int x = -1; + var code = """ + class Program + { + static void Main(string[] args) + { + while (0 > new int[] { 1 }.Length) + { + System.Console.WriteLine("Hello"); + } + } + } + """; + + var expected = """ + class Program + { + static void Main(string[] args) + { + while (0 > new int[] { 1 }.Length) + { + System.Console.WriteLine("Hello"); + } + } + } + """; + await AssertFormatAsync(expected, code); } -}"); - } - [Fact] - public async Task DoNotAddSpaceAfterUnaryPlus() - { - await AssertFormatAsync(@"class C -{ - void M() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541035")] + public async Task BugFix7564_1() { - int x = +1; + var code = """ + class Program + { + static void Main(string[] args) + { + while (null != new int[] { 1 }) + { + System.Console.WriteLine("Hello"); + } + } + } + """; + + var expected = """ + class Program + { + static void Main(string[] args) + { + while (null != new int[] { 1 }) + { + System.Console.WriteLine("Hello"); + } + } + } + """; + await AssertFormatAsync(expected, code); } -}", @"class C -{ - void M() + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541035")] + public async Task BugFix7564_2() { - int x = +1; + var code = """ + class Program + { + static void Main(string[] args) + { + foreach (var f in new int[] { 5 }) + { + Console.WriteLine(f); + } + } + } + """; + + var expected = """ + class Program + { + static void Main(string[] args) + { + foreach (var f in new int[] { 5 }) + { + Console.WriteLine(f); + } + } + } + """; + await AssertFormatAsync(expected, code); } -}"); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545909")] - public async Task DoNotAddSpaceAfterIncrement() - { - var code = @"class C -{ - void M(int[] i) + [Fact, WorkItem(8385, "DevDiv_Projects/Roslyn")] + public async Task NullCoalescingOperator() { - ++i[0]; + var code = """ + class C + { + void M() + { + object o2 = null??null; + } + } + """; + + var expected = """ + class C + { + void M() + { + object o2 = null ?? null; + } + } + """; + await AssertFormatAsync(expected, code); } -}"; - await AssertFormatAsync(code, code); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545909")] - public async Task DoNotAddSpaceBeforeIncrement() - { - var code = @"class C -{ - void M(int[] i) + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541925")] + public async Task QueryContinuation() { - i[0]++; + var code = """ + using System.Linq; + class C + { + static void Main(string[] args) + { + var temp = from x in "abc" + let z = x.ToString() + select z into w + select w; + } + } + """; + + var expected = """ + using System.Linq; + class C + { + static void Main(string[] args) + { + var temp = from x in "abc" + let z = x.ToString() + select z into w + select w; + } + } + """; + await AssertFormatAsync(expected, code); } -}"; - await AssertFormatAsync(code, code); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545909")] - public async Task DoNotAddSpaceAfterDecrement() - { - var code = @"class C -{ - void M(int[] i) + [Fact] + public async Task QueryContinuation2() { - --i[0]; + var code = """ + using System.Linq; + class C + { + static void Main(string[] args) + { + var temp = from x in "abc" select x into + } + } + """; + + var expected = """ + using System.Linq; + class C + { + static void Main(string[] args) + { + var temp = from x in "abc" + select x into + } + } + """; + await AssertFormatAsync(expected, code); } -}"; - await AssertFormatAsync(code, code); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545909")] - public async Task DoNotAddSpaceBeforeDecrement() - { - var code = @"class C -{ - void M(int[] i) + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542305")] + public async Task AttributeFormatting1() { - i[0]--; + var code = """ + class Program + { + void AddClass(string name,[OptionalAttribute] object position,[OptionalAttribute] object bases) + { + } + } + """; + + var expected = """ + class Program + { + void AddClass(string name, [OptionalAttribute] object position, [OptionalAttribute] object bases) + { + } + } + """; + await AssertFormatAsync(expected, code); } -}"; - await AssertFormatAsync(code, code); - } - [Fact] - public async Task Anchoring() - { - await AssertFormatAsync(@"class C -{ - void M() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542304")] + public async Task CloseBracesInArgumentList() { - Console.WriteLine(""Goo"", - 0, 1, - 2); + var code = """ + class Program + { + static void Main(string[] args) + { + var relativeIndentationGetter = new Lazy(() => + { + var indentationDelta = operation.IndentationDeltaOrPosition * this.OptionSet.IndentationSize; + var baseIndentation = this.tokenStream.GetCurrentColumn(operation.BaseToken); + + return baseIndentation + indentationDelta; + } , isThreadSafe: true); + } + } + """; + + var expected = """ + class Program + { + static void Main(string[] args) + { + var relativeIndentationGetter = new Lazy(() => + { + var indentationDelta = operation.IndentationDeltaOrPosition * this.OptionSet.IndentationSize; + var baseIndentation = this.tokenStream.GetCurrentColumn(operation.BaseToken); + + return baseIndentation + indentationDelta; + }, isThreadSafe: true); + } + } + """; + await AssertFormatAsync(expected, code); } -}", @"class C -{ - void M() + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542538")] + public async Task MissingTokens() { - Console.WriteLine(""Goo"", - 0, 1, - 2); + var code = """ + using System; + delegate void myDelegate(int name = 1); + class innerClass + { + public innerClass() + { + myDelegate x = (int y=1) => { return; }; + } + } + """; + + var expected = """ + using System; + delegate void myDelegate(int name = 1); + class innerClass + { + public innerClass() + { + myDelegate x = (int y = 1) => { return; }; + } + } + """; + + await AssertFormatAsync(expected, code); } -}"); - } - [Fact] - public async Task Exclamation() - { - await AssertFormatAsync(@"class C -{ - void M() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542199")] + public async Task ColumnOfVeryFirstToken() { - if (!true) ; + var code = @" W )b"; + + var expected = @"W )b"; + + await AssertFormatAsync(expected, code); } -}", @"class C -{ - void M() + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542718")] + public async Task EmptySuppressionSpan() { - if ( ! true ) ; + var code = """ + enum E + { + a,, + } + """; + + var expected = """ + enum E + { + a,, + } + """; + + await AssertFormatAsync(expected, code); } -}"); - } - [Fact] - public async Task StartAndEndTrivia() - { - await AssertFormatAsync(@" + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542790")] + public async Task LabelInSwitch() + { + var code = """ + class test + { + public static void Main() + { + string target = "t1"; + switch (target) + { + case "t1": + label1: + goto label1; + case "t2": + label2: + goto label2; + } + } + } + """; + var expected = """ + class test + { + public static void Main() + { + string target = "t1"; + switch (target) + { + case "t1": + label1: + goto label1; + case "t2": + label2: + goto label2; + } + } + } + """; -class C { } + await AssertFormatAsync(expected, code); + } + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543112")] + public void FormatArbitaryNode() + { + var expected = """ + public int Prop + { + get + { + return c; + } + set + { + c = value; + } + } + """; + + var property = SyntaxFactory.PropertyDeclaration( + attributeLists: [], + [PublicKeyword], + SyntaxFactory.ParseTypeName("int"), + null, + SyntaxFactory.Identifier("Prop"), + SyntaxFactory.AccessorList([ + SyntaxFactory.AccessorDeclaration( + SyntaxKind.GetAccessorDeclaration, + SyntaxFactory.Block(SyntaxFactory.ParseStatement("return c;"))), + SyntaxFactory.AccessorDeclaration( + SyntaxKind.SetAccessorDeclaration, + SyntaxFactory.Block(SyntaxFactory.ParseStatement("c = value;")))])); + + Assert.NotNull(property); + using var workspace = new AdhocWorkspace(); + var newProperty = Formatter.Format(property, workspace.Services.SolutionServices, CSharpSyntaxFormattingOptions.Default, CancellationToken.None); + + Assert.Equal(expected, newProperty.ToFullString()); + } + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543140")] + public async Task OmittedTypeArgument() + { + var code = """ + using System; + using System.Collections.Generic; + using System.Linq; + + class Program + { + static void Main(string[] args) + { + Console.WriteLine(typeof(Dictionary<, >).IsGenericTypeDefinition); + } + } + """; + var expected = """ + using System; + using System.Collections.Generic; + using System.Linq; -", @" - - -class C { } - - - - -"); - } + class Program + { + static void Main(string[] args) + { + Console.WriteLine(typeof(Dictionary<,>).IsGenericTypeDefinition); + } + } + """; - [Fact] - public async Task FirstTriviaAndAnchoring1() - { - await AssertFormatAsync(@" -namespace N -{ - class C - { - void Method() - { - int i = - 1 - + - 3; - } + await AssertFormatAsync(expected, code); } -} - + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543131")] + public async Task TryAfterLabel() + { + var code = """ + using System; + class Program + { + static object lockObj = new object(); + static int Main() + { + int sum = 0; + lock (lockObj) + try + { sum = 0; } + catch (Exception ex) + { Console.WriteLine(ex); } + return sum; + } + } + """; -", @" -namespace N { - class C { - void Method() { - int i = - 1 - + - 3; - } -} -} + var expected = """ + using System; + class Program + { + static object lockObj = new object(); + static int Main() + { + int sum = 0; + lock (lockObj) + try + { sum = 0; } + catch (Exception ex) + { Console.WriteLine(ex); } + return sum; + } + } + """; + await AssertFormatAsync(expected, code); + } + [Fact] + public async Task QueryContinuation1() + { + var code = """ + using System.Linq; -"); - } + class Program + { + static void Main(string[] args) + { + var q = from arg in args + group arg by arg.Length into final + where final + .Select(c => c) + .Distinct() + .Count() > 0 + select final; + } + } + """; - [Fact] - public async Task FirstTriviaAndAnchoring2() - { - await AssertFormatAsync(@" -namespace N -{ - class C - { - int i = - 1 - + - 3; - } -} + var expected = """ + using System.Linq; + class Program + { + static void Main(string[] args) + { + var q = from arg in args + group arg by arg.Length into final + where final + .Select(c => c) + .Distinct() + .Count() > 0 + select final; + } + } + """; + await AssertFormatAsync(expected, code); + } -", @" -namespace N { - class C { - int i = - 1 - + - 3; -} -} + [Fact] + public async Task TestCSharpFormattingSpacingOptions() + { + var text = + """ - + interface f1 + { } -"); - } + interface f2 : f1 { } - [Fact] - public async Task FirstTriviaAndAnchoring3() - { - await AssertFormatAsync(@" + struct d2 : f1 { } -class C -{ - int i = - 1 - + - 3; -} + class goo : System . Object + { + public int bar = 1* 2; + public void goobar ( ) + { + goobar ( ); + } + public int toofoobar( int i , int j ) + { + int s = ( int ) ( 34 ); + if ( i < 0 ) + { + } + return toofoobar( i,j ); + } + public string parfoobar(string [ ] str) + { + for(int i = 0 ; i < 28 ; i++) { } + return str[ 5 ]; + } + } + """; + var expectedFormattedText = + """ + interface f1 + { } + interface f2 : f1 { } -", @" - - class C { - int i = - 1 - + - 3; -} - + struct d2 : f1 { } + class goo : System.Object + { + public int bar = 1 * 2; + public void goobar() + { + goobar(); + } + public int toofoobar(int i, int j) + { + int s = (int)(34); + if (i < 0) + { + } + return toofoobar(i, j); + } + public string parfoobar(string[] str) + { + for (int i = 0; i < 28; i++) { } + return str[5]; + } + } + """; -"); - } + await AssertFormatAsync(expectedFormattedText, text); + } - [Fact] - public async Task Base1() - { - await AssertFormatAsync(@"class C -{ - C() : base() + [Fact] + public async Task SpacingFixInTokenBasedForIfAndSwitchCase() { - } -}", @" class C + var code = """ + class Class5{ + void bar() { - C ( ) : base ( ) + if(x == 1) + x = 2; else x = 3; + switch (x) { + case 1: break; case 2: break; default: break;} + } + } + """; + var expectedCode = """ + class Class5 { + void bar() + { + if (x == 1) + x = 2; + else x = 3; + switch (x) + { + case 1: break; + case 2: break; + default: break; + } + } } - } "); - } + """; + await AssertFormatAsync(expectedCode, code); + } - [Fact] - public async Task This1() - { - await AssertFormatAsync(@"class C -{ - C(int i) : this() + [Fact] + public async Task SpacingInDeconstruction() { + var code = """ + class Class5{ + void bar() + { + var(x,y)=(1,2); + } + } + """; + var expectedCode = """ + class Class5 + { + void bar() + { + var (x, y) = (1, 2); + } + } + """; + + await AssertFormatAsync(expectedCode, code); } - C() { } -}", @" class C + [Fact] + public async Task SpacingInNullableTuple() + { + var code = """ + class Class5 { - C ( int i ) : this ( ) + void bar() + { + (int, string) ? x = (1, "hello"); + } + } + """; + var expectedCode = """ + class Class5 { + void bar() + { + (int, string)? x = (1, "hello"); + } } + """; - C ( ) { } - } "); - } + await AssertFormatAsync(expectedCode, code); + } - [Fact] - public async Task QueryExpression1() - { - await AssertFormatAsync(@"class C -{ - int Method() + [Fact] + public async Task SpacingInTupleArrayCreation() { - var q = - from c in from b in cs select b select c; + var code = """ + class C + { + void bar() + { + (string a, string b)[] ab = new(string a, string b) [1]; + } + } + """; + var expectedCode = """ + class C + { + void bar() + { + (string a, string b)[] ab = new (string a, string b)[1]; + } + } + """; + + await AssertFormatAsync(expectedCode, code); } -}", @" class C + + [Fact] + public async Task SpacingInTupleArrayCreation2() + { + var code = """ + class C { - int Method() - { - var q = - from c in from b in cs select b select c; - } - } "); - } + void bar() + { + (string a, string b)[] ab = new( + } + } + """; + var expectedCode = """ + class C + { + void bar() + { + (string a, string b)[] ab = new( + } + } + """; - [Fact] - public async Task QueryExpression2() - { - await AssertFormatAsync(@"class C -{ - int Method() + await AssertFormatAsync(expectedCode, code); + } + + [Fact] + public async Task SpacingInImplicitObjectCreation() { - var q = from c in - from b in cs - select b - select c; + var code = """ + class C + { + void bar() + { + C a = new (); + } + } + """; + var expectedCode = """ + class C + { + void bar() + { + C a = new(); + } + } + """; + + await AssertFormatAsync(expectedCode, code); } -}", @" class C + + [Fact] + public async Task FormatRecursivePattern_Positional() + { + var code = """ + class C { - int Method() - { - var q = from c in - from b in cs - select b - select c; - } - } "); - } + void M() { _ = this is ( 1 , 2 ) ; } + } + """; + var expectedCode = """ + class C + { + void M() { _ = this is (1, 2); } + } + """; - [Fact] - public async Task QueryExpression3() - { - await AssertFormatAsync(@"class C -{ - int Method() + await AssertFormatAsync(expectedCode, code); + } + + [Fact] + public async Task FormatRecursivePattern_Positional_Singleline() { - var q = from c in Get(1 + - 2 + - 3) - from b in Get(1 + - 2 + - 3) - select new { b, c }; + var code = """ + class C + { + void M() { + _ = this is ( 1 , 2 ) ; } + } + """; + var expectedCode = """ + class C + { + void M() + { + _ = this is (1, 2); + } + } + """; + + await AssertFormatAsync(expectedCode, code); } -}", @"class C -{ - int Method() + + [Fact] + public async Task FormatRecursivePattern_Positional_Multiline() { - var q = from c in Get(1 + - 2 + - 3) - from b in Get(1 + - 2 + - 3) - select new { b, c }; + var code = """ + class C + { + void M() { + _ = this is ( 1 , + 2 , + 3 ) ; } + } + """; + var expectedCode = """ + class C + { + void M() + { + _ = this is (1, + 2, + 3); + } + } + """; + await AssertFormatAsync(expectedCode, code); } -}"); - } - [Fact] - public async Task QueryExpression4() - { - await AssertFormatAsync(@"class C -{ - int Method() + [Fact] + public async Task FormatRecursivePattern_Positional_Multiline2() { - var q = - from c in - from b in cs - select b - select c; + var code = """ + class C + { + void M() { + _ = this is ( 1 , + 2 , + 3 ) ; } + } + """; + var expectedCode = """ + class C + { + void M() + { + _ = this is (1, + 2, + 3); + } + } + """; + await AssertFormatAsync(expectedCode, code); } -}", @" class C + + [Fact] + public async Task FormatRecursivePattern_Positional_Multiline3() + { + var code = """ + class C { - int Method() - { - var q = - from c in - from b in cs - select b - select c; - } - } "); - } + void M() { + _ = this is + ( 1 , + 2 , + 3 ) ; } + } + """; + var expectedCode = """ + class C + { + void M() + { + _ = this is + (1, + 2, + 3); + } + } + """; + await AssertFormatAsync(expectedCode, code); + } - [Fact] - public async Task Label1() - { - await AssertFormatAsync(@"class C -{ - int Method() + [Fact] + public async Task FormatRecursivePattern_Positional_Multiline4() { - L: int i = 10; + var code = """ + class C + { + void M() { + _ = this is + ( 1 , + 2 , 3 ) ; } + } + """; + var expectedCode = """ + class C + { + void M() + { + _ = this is + (1, + 2, 3); + } + } + """; + await AssertFormatAsync(expectedCode, code); } -}", @" class C + + [Fact] + public async Task FormatRecursivePattern_Properties_Singleline() + { + var code = """ + class C { - int Method() - { - L : int i = 10 ; - } - } "); - } + void M() { _ = this is C{ P1 : 1 } ; } + } + """; + var expectedCode = """ + class C + { + void M() { _ = this is C { P1: 1 }; } + } + """; + + await AssertFormatAsync(expectedCode, code); + } - [Fact] - public async Task Label2() - { - await AssertFormatAsync(@"class C -{ - int Method() + [Fact] + public async Task FormatRecursivePattern_Properties_Multiline() { - int x = 1; - L: int i = 10; - } -}", @" class C + var code = """ + class C { - int Method() - { -int x = 1 ; - L : int i = 10 ; - } - } "); - } + void M() { + _ = this is + { + P1 : 1 , + P2 : 2 + } ; + } + } + """; + var expectedCode = """ + class C + { + void M() + { + _ = this is + { + P1: 1, + P2: 2 + }; + } + } + """; - [Fact] - public async Task Label3() - { - await AssertFormatAsync(@"class C -{ - int Method() - { - int x = 1; - L: - int i = 10; + await AssertFormatAsync(expectedCode, code); } -}", @" class C - { - int Method() - { -int x = 1 ; - L : -int i = 10 ; - } - } "); - } - [Fact] - public async Task Label4() - { - await AssertFormatAsync(@"class C -{ - int Method() + [Fact] + public async Task FormatRecursivePattern_Properties_Multiline2() { - int x = 1; - L: int i = 10; - int next = 30; - } -}", @" class C + var code = """ + class C { - int Method() - { -int x = 1 ; - L : int i = 10 ; - int next = 30; - } - } "); - } + void M() { + _ = this is { + P1 : 1 , + P2 : 2 + } ; + } + } + """; + var expectedCode = """ + class C + { + void M() + { + _ = this is + { + P1: 1, + P2: 2 + }; + } + } + """; - [Fact] - public async Task Label5() - { - await AssertFormatAsync(@"class C -{ - int Method() - { - L: int i = 10; - int next = 30; + await AssertFormatAsync(expectedCode, code); } -}", @" class C - { - int Method() - { - L : int i = 10 ; - int next = 30; - } - } "); - } - [Fact] - public async Task Label6() - { - await AssertFormatAsync(@"class C -{ - int Method() + [Fact] + public async Task FormatRecursivePattern_Properties_Multiline3() { - L: - int i = 10; - int next = 30; - } -}", @" class C + var code = """ + class C { - int Method() - { - L : -int i = 10 ; - int next = 30; - } - } "); - } + void M() { + _ = this is { + P1 : 1 , + P2 : 2, P3: 3 + } ; + } + } + """; + var expectedCode = """ + class C + { + void M() + { + _ = this is + { + P1: 1, + P2: 2, P3: 3 + }; + } + } + """; - [Fact] - public async Task Label7() - { - await AssertFormatAsync(@"class C -{ - int Method() - { - int i2 = 1; - L: - int i = 10; - int next = 30; + await AssertFormatAsync(expectedCode, code); } -}", @" class C - { - int Method() - { - int i2 = 1 ; - L : -int i = 10 ; - int next = 30; - } - } "); - } - [Fact] - public async Task Label8() - { - await AssertFormatAsync(@"class C -{ - int Method() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/27268")] + public async Task FormatRecursivePattern_NoSpaceBetweenTypeAndPositionalSubpattern() { - L: - int i = - 10; - } -}", @" class C + var code = """ + class C { - int Method() - { - L: - int i = - 10; - } - } "); - } - - [Fact] - public async Task AutoProperty() - { - await AssertFormatAsync(@"class Class -{ - private int Age { get; set; } - public string Names { get; set; } -}", @" class Class -{ - private int Age{get; set; } - public string Names { get; set;} -}"); - } + void M() { + _ = this is C( 1 , 2 ){} ; } + } + """; + var expectedCode = """ + class C + { + void M() + { + _ = this is C(1, 2) { }; + } + } + """; + // no space separates the type and the positional pattern + await AssertFormatAsync(expectedCode, code); + } - [Fact] - public async Task NormalPropertyGet() - { - await AssertFormatAsync(@"class Class -{ - private string name; - public string Names + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/27268")] + public async Task FormatRecursivePattern_PreferSpaceBetweenTypeAndPositionalSubpattern() { - get + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - return name; - } + { CSharpFormattingOptions2.SpaceAfterMethodCallName, true } + }; + var code = """ + class C + { + void M() { + _ = this is C( 1 , 2 ){} ; } + } + """; + var expectedCode = """ + class C + { + void M() + { + _ = this is C (1, 2) { }; + } + } + """; + await AssertFormatAsync(expectedCode, code, changedOptionSet: changingOptions); } -}", @"class Class -{ - private string name; - public string Names + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/27268")] + public async Task FormatRecursivePattern_PreferSpaceInsidePositionalSubpatternParentheses() { - get - { - return name; - } + var changingOptions = new OptionsCollection(LanguageNames.CSharp) + { + { CSharpFormattingOptions2.SpaceWithinMethodCallParentheses, true } + }; + var code = """ + class C + { + void M() { + _ = this is C( 1 , 2 ){} ; + _ = this is C( ){} ; } + } + """; + var expectedCode = """ + class C + { + void M() + { + _ = this is C( 1, 2 ) { }; + _ = this is C() { }; + } + } + """; + await AssertFormatAsync(expectedCode, code, changedOptionSet: changingOptions); } -}"); - } - [Fact] - public async Task NormalPropertyBoth() - { - await AssertFormatAsync(@"class Class -{ - private string name; - public string Names + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/27268")] + public async Task FormatRecursivePattern_PreferSpaceInsideEmptyPositionalSubpatternParentheses() { - get + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - return name; - } - set - { - name = value; - } + { CSharpFormattingOptions2.SpaceBetweenEmptyMethodCallParentheses, true } + }; + var code = """ + class C + { + void M() { + _ = this is C( 1 , 2 ){} ; + _ = this is C( ){} ; } + } + """; + var expectedCode = """ + class C + { + void M() + { + _ = this is C(1, 2) { }; + _ = this is C( ) { }; + } + } + """; + await AssertFormatAsync(expectedCode, code, changedOptionSet: changingOptions); } -}", @"class Class -{ - private string name; - public string Names + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/34683")] + public async Task FormatRecursivePattern_InBinaryOperation() { - get + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - return name; - } - set - { - name = value; - } + { CSharpFormattingOptions2.SpaceWithinMethodCallParentheses, true } + }; + var code = """ + class C + { + void M() + { + return + typeWithAnnotations is { } && true; + } + } + """; + var expectedCode = code; + await AssertFormatAsync(expectedCode, code, changedOptionSet: changingOptions); } -}"); - } - [Fact] - public async Task ErrorHandling1() - { - await AssertFormatAsync(@"class C -{ - int Method() + [Fact] + public async Task FormatPropertyPattern_MultilineAndEmpty() { - int a b c; - } -}", @" class C + var code = """ + class C { - int Method() - { - int a b c ; - } - } "); - } + void M() { + _ = this is + { + }; + } + } + """; + var expectedCode = """ + class C + { + void M() + { + _ = this is + { + }; + } + } + """; + await AssertFormatAsync(expectedCode, code); + } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537763")] - public async Task NullableType() - { - await AssertFormatAsync(@"class Program -{ - static void Main(string[] args) + [Fact] + public async Task FormatSwitchExpression_IndentArms() { - int? i = 10; + var code = """ + class C + { + void M() { + _ = this switch + { + { P1: 1} => true, + (0, 1) => true, + _ => false + }; + + } + } + """; + var expectedCode = """ + class C + { + void M() + { + _ = this switch + { + { P1: 1 } => true, + (0, 1) => true, + _ => false + }; + + } + } + """; + await AssertFormatAsync(expectedCode, code); } -}", @"class Program -{ - static void Main(string[] args) + + [Fact] + public async Task FormatPropertyPattern_FollowedByInvocation() { - int ? i = 10; + var code = """ + class C + { + void M() { + _ = this is { } + M(); + } + } + """; + var expectedCode = """ + class C + { + void M() + { + _ = this is { } + M(); + } + } + """; + // although 'M' will be parsed into the pattern on line above, we should not wrap the pattern + await AssertFormatAsync(expectedCode, code); } -}"); - } - - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537766")] - public async Task SuppressWrappingOnBraces() - { - await AssertFormatAsync(@"class Class1 -{ } -", @"class Class1 -{} -"); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537824")] - public async Task DoWhile() - { - await AssertFormatAsync(@"public class Class1 -{ - void Goo() + [Fact] + public async Task FormatPositionalPattern_FollowedByInvocation() { - do - { - } while (true); + var code = """ + class C + { + void M() { + _ = this is (1, 2) { } + M(); + } + } + """; + var expectedCode = """ + class C + { + void M() + { + _ = this is (1, 2) { } + M(); + } + } + """; + // although 'M' will be parsed into the pattern on line above, we should not wrap the pattern + await AssertFormatAsync(expectedCode, code); } -} -", @"public class Class1 -{ - void Goo() + + [Fact] + public async Task FormatPositionalPattern_FollowedByScope() { - do - { - }while (true); + var code = """ + class C + { + void M() { + _ = this is (1, 2) + { + M(); + } + } + } + """; + var expectedCode = """ + class C + { + void M() + { + _ = this is (1, 2) + { + M(); + } + } + } + """; + // You should not invoke Format on incomplete code and expect nice results + await AssertFormatAsync(expectedCode, code); } -} -"); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537774")] - public async Task SuppressWrappingBug() - { - await AssertFormatAsync(@"class Class1 -{ - int Goo() + [Fact] + public async Task FormatSwitchExpression_MultilineAndNoArms() { - return 0; - } -} -", @"class Class1 -{ - int Goo() - {return 0; + var code = """ + class C + { + void M() { + _ = this switch + { + }; + } + } + """; + var expectedCode = """ + class C + { + void M() + { + _ = this switch + { + }; + } + } + """; + await AssertFormatAsync(expectedCode, code); } -} -"); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537768")] - public async Task PreserveLineForAttribute() - { - await AssertFormatAsync(@"class Class1 -{ - [STAThread] - static void Main(string[] args) + [Fact] + public async Task FormatSwitchExpression_ExpressionAnchoredToArm() { + var code = """ + class C + { + void M() { + _ = this switch + { + { P1: 1} + => true, + (0, 1) + => true, + _ + => false + }; + + } + } + """; + var expectedCode = """ + class C + { + void M() + { + _ = this switch + { + { P1: 1 } + => true, + (0, 1) + => true, + _ + => false + }; + + } + } + """; + await AssertFormatAsync(expectedCode, code); } -} -", @"class Class1 -{ - [STAThread] -static void Main(string[] args) + + [Fact] + public async Task FormatSwitchExpression_NoSpaceBeforeColonInArm() { - } -} -"); - } + var code = """ + class C + { + void M() { + _ = this switch + { + { P1: 1} + => true, + (0, 1) + => true, + _ + => false + }; + + } + } + """; + var expectedCode = """ + class C + { + void M() + { + _ = this switch + { + { P1: 1 } + => true, + (0, 1) + => true, + _ + => false + }; - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537878")] - public async Task NoFormattingOnMissingTokens() - { - await AssertFormatAsync(@"namespace ClassLibrary1 -{ - class Class1 - { - void Goo() - { - if (true) - } + } + } + """; + await AssertFormatAsync(expectedCode, code); } -} -", @"namespace ClassLibrary1 -{ - class Class1 + + [Fact] + public async Task FormatSwitchExpression_ArmCommaWantsNewline() { - void Goo() - { - if (true) - } + var code = """ + class C + { + void M() { + _ = this switch + { + { P1: 1} => true, + (0, 1) => true, _ => false + }; + + } + } + """; + var expectedCode = """ + class C + { + void M() + { + _ = this switch + { + { P1: 1 } => true, + (0, 1) => true, + _ => false + }; + + } + } + """; + await AssertFormatAsync(expectedCode, code); } -} -"); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537783")] - public async Task UnaryExpression() - { - await AssertFormatAsync(@"class Program -{ - static void Main(string[] args) + [Fact] + public async Task FormatSwitchExpression_ArmCommaPreservesLines() { - int a = 6; - a = a++ + 5; + var code = """ + class C + { + void M() { + _ = this switch + { + { P1: 1} => true, + + (0, 1) => true, _ => false + }; + + } + } + """; + var expectedCode = """ + class C + { + void M() + { + _ = this switch + { + { P1: 1 } => true, + + (0, 1) => true, + _ => false + }; + + } + } + """; + await AssertFormatAsync(expectedCode, code); } -} -", @"class Program -{ - static void Main(string[] args) + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/33839")] + public async Task FormatSwitchExpression_ExpressionBody() { - int a = 6; - a = a++ + 5; + var code = """ + + public class Test + { + public object Method(int i) + => i switch + { + 1 => 'a', + 2 => 'b', + _ => null, + }; + } + """; + var expectedCode = """ + + public class Test + { + public object Method(int i) + => i switch + { + 1 => 'a', + 2 => 'b', + _ => null, + }; + } + """; + + await AssertFormatAsync(expectedCode, code); } -} -"); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537885")] - public async Task Pointer() - { - await AssertFormatAsync(@"class Program -{ - static void Main(string[] args) + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/72196")] + [InlineData("[]")] + [InlineData("[a]")] + [InlineData("[a, b]")] + [InlineData("[..]")] + [InlineData("[var a, .., var b]")] + [InlineData("[{ } a, null]")] + [InlineData("[a, []]")] + public async Task FormatSwitchExpression_ListPatternAligned(string listPattern) { - int* p; + var code = $$""" + class C + { + void M() + { + _ = Array.Empty() switch + { + {{listPattern}} => 0, + _ => 1, + }; + } + } + """; + var expectedCode = $$""" + class C + { + void M() + { + _ = Array.Empty() switch + { + {{listPattern}} => 0, + _ => 1, + }; + } + } + """; + await AssertFormatAsync(expectedCode, code); } -} -", @"class Program -{ - static void Main(string[] args) + + [Fact] + public async Task FormatSwitchWithPropertyPattern() { - int* p; + var code = """ + class C + { + void M() + { + switch (this) + { + case { P1: 1, P2: { P3: 3, P4: 4 } }: + break; + } + } + } + """; + var expectedCode = """ + class C + { + void M() + { + switch (this) + { + case { P1: 1, P2: { P3: 3, P4: 4 } }: + break; + } + } + } + """; + await AssertFormatAsync(expectedCode, code); } -} -"); - } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/50723")] - public async Task TuplePointer() - { - var properlyFormattedCode = @"public unsafe static class Program -{ - public static void Main(string[] args) + [Fact] + public async Task FormatSwitchWithPropertyPattern_Singleline() { - int* intPointer = null; - (int, int)* intIntPointer = null; + var code = """ + class C + { + void M() + { + switch (this) + { + case { P1: 1, P2: { P3: 3, P4: 4 } }: break; + } + } + } + """; + var expectedCode = """ + class C + { + void M() + { + switch (this) + { + case { P1: 1, P2: { P3: 3, P4: 4 } }: break; + } + } + } + """; + + await AssertFormatAsync(expectedCode, code); } -} -"; - await AssertFormatAsync(properlyFormattedCode, properlyFormattedCode); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537886")] - public async Task Tild() - { - await AssertFormatAsync(@"class Program -{ - static void Main(string[] args) + [Fact] + public async Task FormatSwitchWithPropertyPattern_Singleline2() { - int j = 103; - j = ~7; + var code = """ + class C + { + void M() + { + switch (this) + { + case { P1: 1, P2: { P3: 3, P4: 4 } }: System.Console.Write(1); + break; + } + } + } + """; + var expectedCode = """ + class C + { + void M() + { + switch (this) + { + case { P1: 1, P2: { P3: 3, P4: 4 } }: + System.Console.Write(1); + break; + } + } + } + """; + await AssertFormatAsync(expectedCode, code); } -} -", @"class Program -{ - static void Main(string[] args) + + [Fact] + public async Task SpacingInTupleExtension() { - int j = 103; - j = ~7; + var code = """ + static class Class5 + { + static void Extension(this(int, string) self) { } + } + """; + var expectedCode = """ + static class Class5 + { + static void Extension(this (int, string) self) { } + } + """; + + await AssertFormatAsync(expectedCode, code); } -} -"); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537884")] - public async Task ArrayInitializer1() - { - await AssertFormatAsync(@"class Program -{ - static void Main(string[] args) + [Fact] + public async Task SpacingInNestedDeconstruction() { - int[] arr = {1,2, - 3,4 - }; + var code = """ + class Class5{ + void bar() + { + ( int x1 , var( x2,x3 ) )=(1,(2,3)); + } + } + """; + var expectedCode = """ + class Class5 + { + void bar() + { + (int x1, var (x2, x3)) = (1, (2, 3)); + } + } + """; + + await AssertFormatAsync(expectedCode, code); } -} -", @"class Program -{ - static void Main(string[] args) + + [Fact] + public async Task SpacingInSuppressNullableWarningExpression() { - int[] arr = {1,2, - 3,4 - }; + var code = + """ + class C + { + static object F() + { + object? o[] = null; + object? x = null; + object? y = null; + return x ! ?? (y) ! ?? o[0] !; + } + } + """; + var expectedCode = + """ + class C + { + static object F() + { + object? o[] = null; + object? x = null; + object? y = null; + return x! ?? (y)! ?? o[0]!; + } + } + """; + + await AssertFormatAsync(expectedCode, code); } -} -"); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537884")] - public async Task ArrayInitializer2() - { - await AssertFormatAsync(@"class Program -{ - static void Main(string[] args) + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545335")] + public async Task PreprocessorOnSameLine() { - int[] arr = new int[] {1,2, - 3,4 - }; + var code = """ + class C + { + }#line default + + #line hidden + """; + + var expected = """ + class C + { + }#line default + + #line hidden + """; + + await AssertFormatAsync(expected, code); } -} -", @"class Program -{ - static void Main(string[] args) + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545626")] + public async Task ArraysInAttributes() { - int[] arr = new int [] {1,2, - 3,4 - }; + var code = """ + [A(X = new int[] { 1 })] + public class A : Attribute + { + public int[] X; + } + """; + + var expected = """ + [A(X = new int[] { 1 })] + public class A : Attribute + { + public int[] X; + } + """; + + await AssertFormatAsync(expected, code); } -} -"); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537884")] - public async Task ImplicitArrayInitializer() - { - await AssertFormatAsync(@"class Program -{ - static void Main(string[] args) + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530580")] + public async Task NoNewLineAfterBraceInExpression() { - var arr = new[] {1,2, - 3,4 - }; + var code = """ + public class A + { + void Method() + { + var po = cancellationToken.CanBeCanceled ? + new ParallelOptions() { CancellationToken = cancellationToken } : + defaultParallelOptions; + } + } + """; + + var expected = """ + public class A + { + void Method() + { + var po = cancellationToken.CanBeCanceled ? + new ParallelOptions() { CancellationToken = cancellationToken } : + defaultParallelOptions; + } + } + """; + + await AssertFormatAsync(expected, code); } -} -", @"class Program -{ - static void Main(string[] args) + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530580")] + public async Task NoIndentForNestedUsingWithoutBraces() { - var arr = new [] {1,2, - 3,4 - } ; - } -} -"); - } + var code = """ + class C + { + void M() + { + using (null) + using (null) + { + } + } + } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/65498")] - public async Task StackAllocArrayInitializer0() - { - await AssertFormatAsync(""" - F(stackalloc int[] - { - 1, - 2, - }); - """, """ - F(stackalloc int[] - { - 1, - 2, - } ); - """); - } + """; - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/65498")] - public async Task StackAllocArrayInitializer0_Implicit() - { - await AssertFormatAsync(""" - F(stackalloc[] - { - 1, - 2, - } - ); - """, """ - F( stackalloc [] + var expected = """ + class C + { + void M() + { + using (null) + using (null) { - 1, - 2, } - ); - """); - } + } + } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/65498")] - public async Task StackAllocArrayInitializer1() - { - await AssertFormatAsync(""" - F( - stackalloc int[] - { - 1,2, - 3,4 - } - ); - """, """ - F( - stackalloc int[] + """; + + await AssertFormatAsync(expected, code); + } + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530580")] + public async Task NoIndentForNestedUsingWithoutBraces2() + { + var code = """ + class C + { + void M() + { + using (null) + using (null) + using (null) + { + } + } + } + + """; + + var expected = """ + class C + { + void M() + { + using (null) + using (null) + using (null) { - 1,2, - 3,4 } - ); - """); - } + } + } + + """; - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/65498")] - public async Task StackAllocArrayInitializer1_Implicit() - { - await AssertFormatAsync(""" - F( - stackalloc[] + await AssertFormatAsync(expected, code); + } + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530580")] + public async Task NoIndentForNestedUsingWithoutBraces3() + { + var code = """ + class C + { + void M() + { + using (null) + using (null) + using (null) { - 1,2, - 3,4 } - ); - """, """ - F( - stackalloc [] + } + } + + """; + + var expected = """ + class C + { + void M() + { + using (null) + using (null) + using (null) { - 1,2, - 3,4 } - ); - """); - } - - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/65498")] - public async Task StackAllocArrayInitializer2() - { - await AssertFormatAsync(""" - var x = (stackalloc int[] {1,2, - 3 - }); - """, """ - var x = (stackalloc int[] {1,2, - 3 - }); - """); - } + } + } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/65498")] - public async Task StackAllocArrayInitializer2_Implicit() - { - await AssertFormatAsync(""" - var x = (stackalloc[] - {1, - 2, 3 - }); - """, """ - var x = (stackalloc [] - {1, - 2, 3 - }); - """); - } + """; - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537884")] - public async Task CollectionInitializer() - { - await AssertFormatAsync(@"class Program -{ - static void Main(string[] args) - { - var arr = new List {1,2, - 3,4 - }; - } -} -", @"class Program -{ - static void Main(string[] args) - { - var arr = new List {1,2, - 3,4 - }; + await AssertFormatAsync(expected, code); } -} -"); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537916")] - public async Task AddressOfOperator() - { - await AssertFormatAsync(@"unsafe class Class1 -{ - void Method() - { - int a = 12; - int* p = &a; - } -} -", @"unsafe class Class1 -{ - void Method() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546678")] + public async Task UnicodeWhitespace() { - int a = 12; - int* p = &a; + var code = "\u001A"; + + await AssertFormatAsync("", code); } -} -"); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537885")] - public async Task DereferenceOperator() - { - await AssertFormatAsync(@"unsafe class Class1 -{ - void Method() + [Fact, WorkItem(17431, "DevDiv_Projects/Roslyn")] + public async Task NoElasticRuleOnRegularFile() { - int a = 12; - int* p = &a; - Console.WriteLine(*p); + var code = """ + class Consumer + { + public int P + { + } + } + """; + + var expected = """ + class Consumer + { + public int P + { + } + } + """; + + await AssertFormatAsync(expected, code); } -} -", @"unsafe class Class1 -{ - void Method() + + [Fact, WorkItem(584599, "DevDiv_Projects/Roslyn")] + public async Task CaseSection() { - int a = 12; - int* p = & a; - Console.WriteLine(* p); + var code = """ + class C + { + void Method() + { + switch(i) + { + // test1 + case 1: + // test2 + case 2: + // test3 + int i2 = 10; + // test 4 + case 4: + // test 5 + } + } + } + """; + + var expected = """ + class C + { + void Method() + { + switch (i) + { + // test1 + case 1: + // test2 + case 2: + // test3 + int i2 = 10; + // test 4 + case 4: + // test 5 + } + } + } + """; + + await AssertFormatAsync(expected, code); } -} -"); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537905")] - public async Task Namespaces() + [Fact, WorkItem(553654, "DevDiv_Projects/Roslyn")] + public async Task Bugfix_553654_LabelStatementIndenting() + { + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - await AssertFormatAsync(@"using System; -using System.Data;", @"using System; using System.Data;"); - } + { CSharpFormattingOptions2.LabelPositioning, LabelPositionOptions.LeftMost } + }; - [Fact] - public async Task NamespaceDeclaration() - { - await AssertFormatAsync(@"namespace N -{ -}", @"namespace N - { -}"); - } + var code = """ + class Program + { + void F() + { + foreach (var x in new int[] { }) + { + goo: + int a = 1; + } + } + } + """; - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537902")] - public async Task DoWhile1() - { - await AssertFormatAsync(@"class Program -{ - static void Main(string[] args) - { - do { } - while (i < 4); - } -}", @"class Program -{ - static void Main(string[] args) - { - do { } - while (i < 4); + var expected = """ + class Program + { + void F() + { + foreach (var x in new int[] { }) + { + goo: + int a = 1; + } + } + } + """; + await AssertFormatAsync(expected, code, changingOptions); } -}"); - } - [Fact] - public async Task NewConstraint() - { - await AssertFormatAsync(@"class Program -{ - void Test(T t) where T : new() + [Fact, WorkItem(707064, "DevDiv_Projects/Roslyn")] + public async Task Bugfix_707064_SpaceAfterSecondSemiColonInFor() { - } -}", @"class Program -{ - void Test(T t) where T : new ( ) - { - } -}"); - } - - [Fact] - public async Task UnaryExpressionWithInitializer() - { - await AssertFormatAsync(@"using System; -using System.Collections.Generic; -using System.Linq; + var code = """ + class Program + { + void F() + { + for (int i = 0; i < 5;) + { + } + } + } + """; -class Program -{ - static void Main(string[] args) - { - if ((new int[] { 1, 2, 3 }).Any()) - { - return; - } + var expected = """ + class Program + { + void F() + { + for (int i = 0; i < 5;) + { + } + } + } + """; + await AssertFormatAsync(expected, code); } -}", @"using System; -using System.Collections.Generic; -using System.Linq; -class Program -{ - static void Main(string[] args) + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/772313")] + public async Task Bugfix_772313_ReturnKeywordBeforeQueryClauseDoesNotTriggerNewLineOnFormat() { - if ((new int[] { 1, 2, 3 } ).Any()) - { - return; - } + var code = """ + class C + { + int M() + { + return from c in " + select c; + } + } + """; + + var expected = """ + class C + { + int M() + { + return from c in " + select c; + } + } + """; + await AssertFormatAsync(expected, code); } -}"); - } - [Fact] - public async Task Attributes1() - { - await AssertFormatAsync(@"class Program -{ - [Flags] public void Method() { } -}", @"class Program -{ - [ Flags ] public void Method ( ) { } -}"); - } + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/772304")] + public async Task Bugfix_772313_PreserveMethodParameterIndentWhenAttributePresent() + { + var code = """ + class C + { + void M + ( + [In] + bool b + ); + } - [Fact] - public async Task Attributes2() - { - await AssertFormatAsync(@"class Program -{ - [Flags] - public void Method() { } -}", @"class Program -{ - [ Flags ] -public void Method ( ) { } -}"); - } + class C + { + void M + ( + [In] + List b + ); + } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538288")] - public async Task ColonColon1() - { - await AssertFormatAsync(@"class Program -{ - public void Method() - { - throw new global::System.NotImplementedException(); - } -}", @"class Program -{ -public void Method ( ) { - throw new global :: System.NotImplementedException(); -} -}"); - } + class C + { + void M + ( + [In] + [In, In] + List b + ); + } + """; - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538354")] - public async Task BugFix3939() - { - await AssertFormatAsync(@"using - System. - Collections. - Generic;", @" using - System. - Collections. - Generic;"); - } + var expected = """ + class C + { + void M + ( + [In] + bool b + ); + } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538354")] - public async Task Tab1() - => await AssertFormatAsync(@"using System;", @" using System;"); + class C + { + void M + ( + [In] + List b + ); + } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538329")] - public async Task SuppressLinkBreakInIfElseStatement() - { - await AssertFormatAsync(@"class Program -{ - static void Main(string[] args) - { - int a; - if (true) a = 10; - else a = 11; - } -}", @"class Program -{ - static void Main(string[] args) - { - int a; - if (true) a = 10; - else a = 11; + class C + { + void M + ( + [In] + [In, In] + List b + ); + } + """; + await AssertFormatAsync(expected, code); } -}"); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538464")] - public async Task BugFix4087() - { - await AssertFormatAsync(@"class Program -{ - static void Main(string[] args) - { - Func fun = x => { return x + 1; } - } -}", @"class Program -{ - static void Main(string[] args) + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/776513")] + public async Task Bugfix_776513_CheckBraceIfNotMissingBeforeApplyingOperationForBracedBlocks() { - Func fun = x => { return x + 1; } + var code = """ + var alwaysTriggerList = new[] + Dim triggerOnlyWithLettersList = + """; + + var expected = """ + var alwaysTriggerList = new[] + Dim triggerOnlyWithLettersList = + """; + await AssertFormatAsync(expected, code); } -}"); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538511")] - public async Task AttributeTargetSpecifier() - { - var code = @"public class Class1 -{ - [method : - void Test() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/769342")] + public async Task ShouldFormatDocCommentWithIndentSameAsTabSizeWithUseTabTrue() { + var optionSet = new OptionsCollection(LanguageNames.CSharp) { { FormattingOptions2.UseTabs, true } }; + + await AssertFormatAsync(""" + namespace ConsoleApplication1 + { + /// + /// fka;jsgdflkhsjflgkhdsl; + /// + class Program + { + } + } + """, """ + namespace ConsoleApplication1 + { + /// + /// fka;jsgdflkhsjflgkhdsl; + /// + class Program + { + } + } + """, changedOptionSet: optionSet); } -}"; - var expected = @"public class Class1 -{ - [method: - void Test() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/797278")] + public async Task TestSpacingOptionAroundControlFlow() { - } -}"; + const string code = """ - await AssertFormatAsync(expected, code); - } + class Program + { + public void goo() + { + int i; + for(i=0; i<10; i++) + {} - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538635")] - public async Task Finalizer() - { - var code = @"public class Class1 -{ - ~ Class1() { } -}"; + foreach(i in new[] {1,2,3}) + {} - var expected = @"public class Class1 -{ - ~Class1() { } -}"; + if (i==10) + {} - await AssertFormatAsync(expected, code); - } + while(i==10) + {} - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538743")] - public async Task BugFix4442() - { - var code = @"class Program -{ - static void Main(string[] args) - { - string str = ""ab,die|wo""; - string[] a = str.Split(new char[] { ',', '|' }) - ; - } -}"; + switch(i) + { + default: break; + } - await AssertFormatAsync(code, code); - } + do {} while (true); - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538658")] - public async Task BugFix4328() - { - var code = @"class Program -{ - static void Main(string[] args) - { - double d = new double (); - } -}"; - var expected = @"class Program -{ - static void Main(string[] args) - { - double d = new double(); - } -}"; - await AssertFormatAsync(expected, code); - } + try + { } + catch (System.Exception) + { } + catch (System.Exception e) when (true) + { } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538658")] - public async Task BugFix4515() - { - var code = @"class Program -{ - static void Main(string[] args) - { - var t = typeof ( System.Object ) ; - var t1 = default ( System.Object ) ; - var t2 = sizeof ( System.Object ) ; - } -}"; - var expected = @"class Program -{ - static void Main(string[] args) - { - var t = typeof(System.Object); - var t1 = default(System.Object); - var t2 = sizeof(System.Object); - } -}"; - await AssertFormatAsync(expected, code); - } + using(somevar) + { } - [Fact] - public async Task CastExpressionTest() - { - var code = @"class Program -{ - static void Main(string[] args) - { - var a = (int) 1; - } -}"; - var expected = @"class Program -{ - static void Main(string[] args) - { - var a = (int)1; - } -}"; - await AssertFormatAsync(expected, code); - } + lock(somevar) + { } + + fixed(char* p = str) + { } + } + } + """; + const string expected = """ + + class Program + { + public void goo() + { + int i; + for ( i = 0; i < 10; i++ ) + { } + + foreach ( i in new[] { 1, 2, 3 } ) + { } + + if ( i == 10 ) + { } + + while ( i == 10 ) + { } + + switch ( i ) + { + default: break; + } + + do { } while ( true ); - [Fact] - public async Task NamedParameter() + try + { } + catch ( System.Exception ) + { } + catch ( System.Exception e ) when ( true ) + { } + + using ( somevar ) + { } + + lock ( somevar ) + { } + + fixed ( char* p = str ) + { } + } + } + """; + var optionSet = new OptionsCollection(LanguageNames.CSharp) { - var code = @"class Program -{ - static void Main(string[] args) - { - Main ( args : null ) ; + { SpaceBetweenParentheses, SpaceBetweenParentheses.DefaultValue.WithFlagValue( SpacePlacementWithinParentheses.ControlFlowStatements, true) }, + }; + + await AssertFormatAsync(expected, code, changedOptionSet: optionSet); } -}"; - var expected = @"class Program -{ - static void Main(string[] args) + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37031")] + [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/176345")] + public async Task TestSpacingOptionAfterControlFlowKeyword() { - Main(args: null); - } -}"; - await AssertFormatAsync(expected, code); - } + var code = """ - [Fact] - public async Task RefReadonlyParameters() - { - var code = """ - class C + class Program + { + public void goo() { - int this [ ref readonly int x , ref readonly int y ] { get ; set ; } - void M ( ref readonly int x , ref readonly int y ) { } + int i; + for (i=0; i<10; i++) + {} + + foreach (i in new[] {1,2,3}) + {} + + if (i==10) + {} + + while (i==10) + {} + + switch (i) + { + default: break; + } + + do {} while (true); + + try + { } + catch (System.Exception e) when (true) + { } + + using (somevar) + { } + + lock (somevar) + { } + + fixed (somevar) + { } } - """; - var expected = """ - class C + } + """; + var expected = """ + + class Program + { + public void goo() { - int this[ref readonly int x, ref readonly int y] { get; set; } - void M(ref readonly int x, ref readonly int y) { } - } - """; - await AssertFormatAsync(expected, code); - } + int i; + for(i = 0; i < 10; i++) + { } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539259")] - public async Task BugFix5143() - { - var code = @"class Program -{ - static void Main(string[] args) - { - int x = Goo ( - delegate ( int x ) { return x ; } ) ; - } -}"; - var expected = @"class Program -{ - static void Main(string[] args) - { - int x = Goo( - delegate (int x) { return x; }); - } -}"; - await AssertFormatAsync(expected, code); - } + foreach(i in new[] { 1, 2, 3 }) + { } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539338")] - public async Task BugFix5251() - { - var code = @"class Program -{ - public static string Goo { get; private set; } -}"; - var expected = @"class Program -{ - public static string Goo { get; private set; } -}"; - await AssertFormatAsync(expected, code); - } + if(i == 10) + { } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539358")] - public async Task BugFix5277() - { - var code = @" -#if true - #endif -"; - var expected = @" -#if true -#endif -"; - await AssertFormatAsync(expected, code); - } + while(i == 10) + { } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539542")] - public async Task BugFix5544() - { - var code = @" -class Program -{ - unsafe static void Main(string[] args) - { - Program* p; - p -> Goo = 5; - } -} -"; - var expected = @" -class Program -{ - unsafe static void Main(string[] args) - { - Program* p; - p->Goo = 5; - } -} -"; - await AssertFormatAsync(expected, code); - } + switch(i) + { + default: break; + } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539587")] - public async Task BugFix5602() - { - var code = @" class Bug - { - public static void func() - { - long b = // - } - }"; - var expected = @"class Bug -{ - public static void func() - { - long b = // - } -}"; - await AssertFormatAsync(expected, code); - } + do { } while(true); - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539616")] - public async Task BugFix5637() - { - var code = @"class Bug -{ - // test - public static void func() - { - } -}"; - var expected = @"class Bug -{ - // test - public static void func() - { - } -}"; - await AssertFormatAsync(expected, code); - } + try + { } + catch(System.Exception e) when(true) + { } - [Fact] - public async Task GenericType() - { - var code = @"class Bug -{ - class N : Bug< T [ ] > - { - } -}"; - var expected = @"class Bug -{ - class N : Bug - { - } -}"; - await AssertFormatAsync(expected, code); - } + using(somevar) + { } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539878")] - public async Task BugFix5978() - { - var code = @"class Program -{ - static void Main(string[] args) - { - int i = 3; - label4: - if (i < 5) - { - label5: -if (i == 4) -{ -} -else -{ -System.Console.WriteLine(""a""); -} - } + lock(somevar) + { } + + fixed(somevar) + { } + } + } + """; + var optionSet = new OptionsCollection(LanguageNames.CSharp) { { CSharpFormattingOptions2.SpaceAfterControlFlowStatementKeyword, false } }; + await AssertFormatAsync(expected, code, changedOptionSet: optionSet); } -}"; - var expected = @"class Program -{ - static void Main(string[] args) + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/766212")] + public async Task TestOptionForSpacingAroundCommas() { - int i = 3; - label4: - if (i < 5) - { - label5: - if (i == 4) + var code = """ + + class Program { + public void Main() + { + var a = new[] {1,2,3}; + var digits = new List {1,2,3,4}; + } } - else + """; + var expectedDefault = """ + + class Program { - System.Console.WriteLine(""a""); + public void Main() + { + var a = new[] { 1, 2, 3 }; + var digits = new List { 1, 2, 3, 4 }; + } } - } - } -}"; - await AssertFormatAsync(expected, code); - } - - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539878")] - public async Task BugFix5979() - { - var code = @"delegate int del(int i); -class Program -{ - static void Main(string[] args) - { - del q = x => - { - label2: goto label1; - label1: return x; - }; - } -}"; - var expected = @"delegate int del(int i); -class Program -{ - static void Main(string[] args) - { - del q = x => - { - label2: goto label1; - label1: return x; - }; - } -}"; - await AssertFormatAsync(expected, code); - } + """; + await AssertFormatAsync(expectedDefault, code); - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539891")] - public async Task BugFix5993() - { - var code = @"public class MyClass -{ - public static void Main() - { - lab1: - { - lab1:// CS0158 - goto lab1; - } - } -}"; - var expected = @"public class MyClass -{ - public static void Main() - { - lab1: - { - lab1:// CS0158 - goto lab1; - } - } -}"; - await AssertFormatAsync(expected, code); - } + var expectedAfterCommaDisabled = """ - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540315")] - public async Task BugFix6536() - { - var code = @"public class MyClass -{ - public static void Main() - { - int i = - - 1 + + + 1 + - + 1 + - + 1 ; - } -}"; - var expected = @"public class MyClass -{ - public static void Main() - { - int i = - -1 + + +1 + -+1 + -+1; - } -}"; - await AssertFormatAsync(expected, code); - } + class Program + { + public void Main() + { + var a = new[] { 1,2,3 }; + var digits = new List { 1,2,3,4 }; + } + } + """; + var optionSet = new OptionsCollection(LanguageNames.CSharp) { { CSharpFormattingOptions2.SpaceAfterComma, false } }; + await AssertFormatAsync(expectedAfterCommaDisabled, code, changedOptionSet: optionSet); - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540801")] - public async Task BugFix7211() - { - var code = @"class Program -{ - static void Main(string[] args) - { - while (0 > new int[] { 1 }.Length) - { - System.Console.WriteLine(""Hello""); - } - } -}"; + var expectedBeforeCommaEnabled = """ - var expected = @"class Program -{ - static void Main(string[] args) - { - while (0 > new int[] { 1 }.Length) - { - System.Console.WriteLine(""Hello""); - } + class Program + { + public void Main() + { + var a = new[] { 1 ,2 ,3 }; + var digits = new List { 1 ,2 ,3 ,4 }; + } + } + """; + optionSet.Add(CSharpFormattingOptions2.SpaceBeforeComma, true); + await AssertFormatAsync(expectedBeforeCommaEnabled, code, changedOptionSet: optionSet); } -}"; - await AssertFormatAsync(expected, code); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541035")] - public async Task BugFix7564_1() - { - var code = @"class Program -{ - static void Main(string[] args) + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/772308")] + public async Task Bugfix_772308_SeparateSuppressionForEachCaseLabelEvenIfEmpty() { - while (null != new int[] { 1 }) - { - System.Console.WriteLine(""Hello""); - } - } -}"; + var code = """ - var expected = @"class Program -{ - static void Main(string[] args) - { - while (null != new int[] { 1 }) - { - System.Console.WriteLine(""Hello""); - } - } -}"; - await AssertFormatAsync(expected, code); - } + class C + { + int M() + { + switch (1) + { + case 1: return 1; + case 2: return 2; + case 3: + case 4: return 4; + default: + } + } + } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541035")] - public async Task BugFix7564_2() - { - var code = @"class Program -{ - static void Main(string[] args) - { - foreach (var f in new int[] { 5 }) - { - Console.WriteLine(f); - } - } -}"; + """; - var expected = @"class Program -{ - static void Main(string[] args) - { - foreach (var f in new int[] { 5 }) - { - Console.WriteLine(f); - } - } -}"; - await AssertFormatAsync(expected, code); - } + var expected = """ - [Fact, WorkItem(8385, "DevDiv_Projects/Roslyn")] - public async Task NullCoalescingOperator() - { - var code = @"class C -{ - void M() - { - object o2 = null??null; - } -}"; + class C + { + int M() + { + switch (1) + { + case 1: return 1; + case 2: return 2; + case 3: + case 4: return 4; + default: + } + } + } - var expected = @"class C -{ - void M() - { - object o2 = null ?? null; + """; + await AssertFormatAsync(expected, code); } -}"; - await AssertFormatAsync(expected, code); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541925")] - public async Task QueryContinuation() - { - var code = @"using System.Linq; -class C -{ - static void Main(string[] args) + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/844913")] + public async Task QueryExpressionInExpression() { - var temp = from x in ""abc"" - let z = x.ToString() - select z into w - select w; - } -}"; + var code = """ - var expected = @"using System.Linq; -class C -{ - static void Main(string[] args) - { - var temp = from x in ""abc"" - let z = x.ToString() - select z into w - select w; - } -}"; - await AssertFormatAsync(expected, code); - } + class C + { + public void CreateSettingsFile(string path, string comment) { + var xml = new XDocument( + new XDeclaration(1.0, utf8, yes), + new XComment(comment), + new XElement(UserSettings, + new XElement(ToolsOptions, + from t in KnownSettings.DefaultCategories + group t by t.Item1 into cat + select new XElement(ToolsOptionsCategory, + new XAttribute(name, cat.Key), + cat.Select(sc => new XElement(ToolsOptionsSubCategory, new XAttribute(name, sc.Item2))) + ) + ) + ) + ); + UpdateSettingsXml(xml); + xml.Save(path); + SettingsPath = path; + } + } - [Fact] - public async Task QueryContinuation2() - { - var code = @"using System.Linq; -class C -{ - static void Main(string[] args) - { - var temp = from x in ""abc"" select x into - } -}"; + """; - var expected = @"using System.Linq; -class C -{ - static void Main(string[] args) - { - var temp = from x in ""abc"" - select x into - } -}"; - await AssertFormatAsync(expected, code); - } + var expected = """ - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542305")] - public async Task AttributeFormatting1() - { - var code = @"class Program -{ - void AddClass(string name,[OptionalAttribute] object position,[OptionalAttribute] object bases) - { - } -}"; + class C + { + public void CreateSettingsFile(string path, string comment) + { + var xml = new XDocument( + new XDeclaration(1.0, utf8, yes), + new XComment(comment), + new XElement(UserSettings, + new XElement(ToolsOptions, + from t in KnownSettings.DefaultCategories + group t by t.Item1 into cat + select new XElement(ToolsOptionsCategory, + new XAttribute(name, cat.Key), + cat.Select(sc => new XElement(ToolsOptionsSubCategory, new XAttribute(name, sc.Item2))) + ) + ) + ) + ); + UpdateSettingsXml(xml); + xml.Save(path); + SettingsPath = path; + } + } - var expected = @"class Program -{ - void AddClass(string name, [OptionalAttribute] object position, [OptionalAttribute] object bases) - { + """; + await AssertFormatAsync(expected, code); } -}"; - await AssertFormatAsync(expected, code); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542304")] - public async Task CloseBracesInArgumentList() - { - var code = @"class Program -{ - static void Main(string[] args) + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/843479")] + public async Task EmbeddedStatementElse() { - var relativeIndentationGetter = new Lazy(() => + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - var indentationDelta = operation.IndentationDeltaOrPosition * this.OptionSet.IndentationSize; - var baseIndentation = this.tokenStream.GetCurrentColumn(operation.BaseToken); + { CSharpFormattingOptions2.NewLineForElse, false } + }; - return baseIndentation + indentationDelta; - } , isThreadSafe: true); - } -}"; + var code = """ - var expected = @"class Program -{ - static void Main(string[] args) - { - var relativeIndentationGetter = new Lazy(() => - { - var indentationDelta = operation.IndentationDeltaOrPosition * this.OptionSet.IndentationSize; - var baseIndentation = this.tokenStream.GetCurrentColumn(operation.BaseToken); + class C + { + void Method() + { + if (true) + Console.WriteLine(); else + Console.WriteLine(); + } + } - return baseIndentation + indentationDelta; - }, isThreadSafe: true); - } -}"; - await AssertFormatAsync(expected, code); - } + """; + + var expected = """ + + class C + { + void Method() + { + if (true) + Console.WriteLine(); + else + Console.WriteLine(); + } + } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542538")] - public async Task MissingTokens() - { - var code = @"using System; -delegate void myDelegate(int name = 1); -class innerClass -{ - public innerClass() - { - myDelegate x = (int y=1) => { return; }; + """; + await AssertFormatAsync(expected, code, changingOptions); } -}"; - var expected = @"using System; -delegate void myDelegate(int name = 1); -class innerClass -{ - public innerClass() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/772311")] + public async Task LineCommentAtTheEndOfLine() { - myDelegate x = (int y = 1) => { return; }; - } -}"; + var code = """ - await AssertFormatAsync(expected, code); - } + using System; - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542199")] - public async Task ColumnOfVeryFirstToken() - { - var code = @" W )b"; + class Program + { + static void Main(string[] args) + { + Console.WriteLine(); // this is a comment + // that I would like to keep - var expected = @"W )b"; + // properly indented + } + } - await AssertFormatAsync(expected, code); - } + """; - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542718")] - public async Task EmptySuppressionSpan() - { - var code = @"enum E - { - a,, - }"; + var expected = """ - var expected = @"enum E -{ - a,, -}"; + using System; - await AssertFormatAsync(expected, code); - } + class Program + { + static void Main(string[] args) + { + Console.WriteLine(); // this is a comment + // that I would like to keep - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542790")] - public async Task LabelInSwitch() - { - var code = @"class test -{ - public static void Main() - { - string target = ""t1""; - switch (target) - { - case ""t1"": - label1: - goto label1; - case ""t2"": - label2: - goto label2; - } - } -}"; + // properly indented + } + } - var expected = @"class test -{ - public static void Main() - { - string target = ""t1""; - switch (target) - { - case ""t1"": - label1: - goto label1; - case ""t2"": - label2: - goto label2; - } + """; + await AssertFormatAsync(expected, code); } -}"; - - await AssertFormatAsync(expected, code); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543112")] - public void FormatArbitaryNode() - { - var expected = @"public int Prop -{ - get + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38224")] + public async Task BlockCommentAtTheEndOfLine1() { - return c; - } + var code = """ - set - { - c = value; - } -}"; + using System; - var property = SyntaxFactory.PropertyDeclaration( - attributeLists: [], - [PublicKeyword], - SyntaxFactory.ParseTypeName("int"), - null, - SyntaxFactory.Identifier("Prop"), - SyntaxFactory.AccessorList([ - SyntaxFactory.AccessorDeclaration( - SyntaxKind.GetAccessorDeclaration, - SyntaxFactory.Block(SyntaxFactory.ParseStatement("return c;"))), - SyntaxFactory.AccessorDeclaration( - SyntaxKind.SetAccessorDeclaration, - SyntaxFactory.Block(SyntaxFactory.ParseStatement("c = value;")))])); + class Program + { + static void Main(string[] args) + { + Console.WriteLine(); /* this is a comment */ + // that I would like to keep - Assert.NotNull(property); - using var workspace = new AdhocWorkspace(); - var newProperty = Formatter.Format(property, workspace.Services.SolutionServices, CSharpSyntaxFormattingOptions.Default, CancellationToken.None); + // properly indented + } + } - Assert.Equal(expected, newProperty.ToFullString()); - } + """; - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543140")] - public async Task OmittedTypeArgument() - { - var code = @"using System; -using System.Collections.Generic; -using System.Linq; - -class Program -{ - static void Main(string[] args) - { - Console.WriteLine(typeof(Dictionary<, >).IsGenericTypeDefinition); - } -}"; + var expected = """ - var expected = @"using System; -using System.Collections.Generic; -using System.Linq; + using System; -class Program -{ - static void Main(string[] args) - { - Console.WriteLine(typeof(Dictionary<,>).IsGenericTypeDefinition); - } -}"; + class Program + { + static void Main(string[] args) + { + Console.WriteLine(); /* this is a comment */ + // that I would like to keep - await AssertFormatAsync(expected, code); - } + // properly indented + } + } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543131")] - public async Task TryAfterLabel() - { - var code = @"using System; -class Program -{ - static object lockObj = new object(); - static int Main() - { - int sum = 0; - lock (lockObj) - try - { sum = 0; } - catch (Exception ex) - { Console.WriteLine(ex); } - return sum; + """; + await AssertFormatAsync(expected, code); } -}"; - var expected = @"using System; -class Program -{ - static object lockObj = new object(); - static int Main() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38224")] + public async Task BlockCommentAtTheEndOfLine2() { - int sum = 0; - lock (lockObj) - try - { sum = 0; } - catch (Exception ex) - { Console.WriteLine(ex); } - return sum; - } -}"; - - await AssertFormatAsync(expected, code); - } + var code = """ - [Fact] - public async Task QueryContinuation1() - { - var code = @"using System.Linq; + using System; -class Program -{ - static void Main(string[] args) - { - var q = from arg in args - group arg by arg.Length into final - where final - .Select(c => c) - .Distinct() - .Count() > 0 - select final; - } -}"; + class Program + { + static void Main(string[] args) + { + Console.WriteLine(); // this is a comment + /* that I would like to keep */ - var expected = @"using System.Linq; + // properly indented + } + } -class Program -{ - static void Main(string[] args) - { - var q = from arg in args - group arg by arg.Length into final - where final - .Select(c => c) - .Distinct() - .Count() > 0 - select final; - } -}"; + """; - await AssertFormatAsync(expected, code); - } + var expected = """ - [Fact] - public async Task TestCSharpFormattingSpacingOptions() - { - var text = -@" -interface f1 -{ } + using System; -interface f2 : f1 { } + class Program + { + static void Main(string[] args) + { + Console.WriteLine(); // this is a comment + /* that I would like to keep */ -struct d2 : f1 { } + // properly indented + } + } -class goo : System . Object -{ - public int bar = 1* 2; - public void goobar ( ) - { - goobar ( ); - } - public int toofoobar( int i , int j ) - { - int s = ( int ) ( 34 ); - if ( i < 0 ) - { - } - return toofoobar( i,j ); - } - public string parfoobar(string [ ] str) - { - for(int i = 0 ; i < 28 ; i++) { } - return str[ 5 ]; + """; + await AssertFormatAsync(expected, code); } -}"; - var expectedFormattedText = -@" -interface f1 -{ } - -interface f2 : f1 { } -struct d2 : f1 { } - -class goo : System.Object -{ - public int bar = 1 * 2; - public void goobar() - { - goobar(); - } - public int toofoobar(int i, int j) + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38224")] + public async Task BlockCommentAtBeginningOfLine() { - int s = (int)(34); - if (i < 0) - { - } - return toofoobar(i, j); - } - public string parfoobar(string[] str) - { - for (int i = 0; i < 28; i++) { } - return str[5]; - } -}"; + var code = """ - await AssertFormatAsync(expectedFormattedText, text); - } + using System; - [Fact] - public async Task SpacingFixInTokenBasedForIfAndSwitchCase() - { - var code = @"class Class5{ -void bar() -{ -if(x == 1) -x = 2; else x = 3; -switch (x) { -case 1: break; case 2: break; default: break;} -} -}"; - var expectedCode = @"class Class5 -{ - void bar() - { - if (x == 1) - x = 2; - else x = 3; - switch (x) - { - case 1: break; - case 2: break; - default: break; - } + class Program + { + static void Main( + int x, // Some comment + /*A*/ int y) + { + } + } + + """; + await AssertFormatAsync(code, code); } -}"; - await AssertFormatAsync(expectedCode, code); - } - [Fact] - public async Task SpacingInDeconstruction() - { - var code = @"class Class5{ -void bar() -{ -var(x,y)=(1,2); -} -}"; - var expectedCode = @"class Class5 -{ - void bar() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/772311")] + public async Task TestTab() { - var (x, y) = (1, 2); - } -}"; + var code = """ - await AssertFormatAsync(expectedCode, code); - } + using System; - [Fact] - public async Task SpacingInNullableTuple() - { - var code = @"class Class5 -{ - void bar() - { - (int, string) ? x = (1, ""hello""); - } -}"; - var expectedCode = @"class Class5 -{ - void bar() - { - (int, string)? x = (1, ""hello""); - } -}"; + class Program + { + /// + /// This function is the callback used to execute a command when a menu item is clicked. + /// See the Initialize method to see how the menu item is associated to this function using + /// the OleMenuCommandService service and the MenuCommand class. + /// + private void MenuItemCallback(object sender, EventArgs e) { + // Show a Message Box to prove we were here + IVsUIShell uiShell = (IVsUIShell)GetService(typeof(SVsUIShell)); + Guid clsid = Guid.Empty; + int result; + Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(uiShell.ShowMessageBox( + 0, + ref clsid, + Rebracer, + string.Format(CultureInfo.CurrentCulture, Inside {0}.MenuItemCallback(), this.ToString()), + string.Empty, + 0, + OLEMSGBUTTON.OLEMSGBUTTON_OK, + OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST, + OLEMSGICON.OLEMSGICON_INFO, + 0, // false + out result)); + } + } - await AssertFormatAsync(expectedCode, code); - } + """; - [Fact] - public async Task SpacingInTupleArrayCreation() - { - var code = @"class C -{ - void bar() - { - (string a, string b)[] ab = new(string a, string b) [1]; - } -}"; - var expectedCode = @"class C -{ - void bar() - { - (string a, string b)[] ab = new (string a, string b)[1]; - } -}"; + var expected = """ - await AssertFormatAsync(expectedCode, code); - } + using System; - [Fact] - public async Task SpacingInTupleArrayCreation2() - { - var code = @"class C -{ - void bar() - { - (string a, string b)[] ab = new( - } -}"; - var expectedCode = @"class C -{ - void bar() - { - (string a, string b)[] ab = new( - } -}"; + class Program + { + /// + /// This function is the callback used to execute a command when a menu item is clicked. + /// See the Initialize method to see how the menu item is associated to this function using + /// the OleMenuCommandService service and the MenuCommand class. + /// + private void MenuItemCallback(object sender, EventArgs e) + { + // Show a Message Box to prove we were here + IVsUIShell uiShell = (IVsUIShell)GetService(typeof(SVsUIShell)); + Guid clsid = Guid.Empty; + int result; + Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(uiShell.ShowMessageBox( + 0, + ref clsid, + Rebracer, + string.Format(CultureInfo.CurrentCulture, Inside { 0}.MenuItemCallback(), this.ToString()), + string.Empty, + 0, + OLEMSGBUTTON.OLEMSGBUTTON_OK, + OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST, + OLEMSGICON.OLEMSGICON_INFO, + 0, // false + out result)); + } + } - await AssertFormatAsync(expectedCode, code); - } + """; + var optionSet = new OptionsCollection(LanguageNames.CSharp) { { FormattingOptions2.UseTabs, true } }; - [Fact] - public async Task SpacingInImplicitObjectCreation() - { - var code = @"class C -{ - void bar() - { - C a = new (); - } -}"; - var expectedCode = @"class C -{ - void bar() - { - C a = new(); + await AssertFormatAsync(expected, code, changedOptionSet: optionSet); + await AssertFormatAsync(expected, expected, changedOptionSet: optionSet); } -}"; - await AssertFormatAsync(expectedCode, code); - } - - [Fact] - public async Task FormatRecursivePattern_Positional() - { - var code = @"class C -{ - void M() { _ = this is ( 1 , 2 ) ; } -}"; - var expectedCode = @"class C -{ - void M() { _ = this is (1, 2); } -}"; + [Fact] + public async Task LeaveBlockSingleLine_False() + { + var code = """ - await AssertFormatAsync(expectedCode, code); - } + namespace N { class C { int x; } } + """; - [Fact] - public async Task FormatRecursivePattern_Positional_Singleline() - { - var code = @"class C -{ - void M() { -_ = this is ( 1 , 2 ) ; } -}"; - var expectedCode = @"class C -{ - void M() - { - _ = this is (1, 2); - } -}"; + var expected = """ - await AssertFormatAsync(expectedCode, code); - } + namespace N + { + class C + { + int x; + } + } + """; - [Fact] - public async Task FormatRecursivePattern_Positional_Multiline() - { - var code = @"class C -{ - void M() { -_ = this is ( 1 , -2 , -3 ) ; } -}"; - var expectedCode = @"class C -{ - void M() - { - _ = this is (1, - 2, - 3); + var options = new OptionsCollection(LanguageNames.CSharp) { { CSharpFormattingOptions2.WrappingPreserveSingleLine, false } }; + await AssertFormatAsync(expected, code, changedOptionSet: options); } -}"; - await AssertFormatAsync(expectedCode, code); - } - [Fact] - public async Task FormatRecursivePattern_Positional_Multiline2() - { - var code = @"class C -{ - void M() { -_ = this is ( 1 , -2 , -3 ) ; } -}"; - var expectedCode = @"class C -{ - void M() + [Fact] + public async Task LeaveBlockSingleLine_False2() { - _ = this is (1, - 2, - 3); - } -}"; - await AssertFormatAsync(expectedCode, code); - } + var code = """ - [Fact] - public async Task FormatRecursivePattern_Positional_Multiline3() - { - var code = @"class C -{ - void M() { -_ = this is -( 1 , -2 , -3 ) ; } -}"; - var expectedCode = @"class C -{ - void M() - { - _ = this is - (1, - 2, - 3); - } -}"; - await AssertFormatAsync(expectedCode, code); - } + class C { void goo() { } } + """; - [Fact] - public async Task FormatRecursivePattern_Positional_Multiline4() - { - var code = @"class C -{ - void M() { -_ = this is -( 1 , -2 , 3 ) ; } -}"; - var expectedCode = @"class C -{ - void M() - { - _ = this is - (1, - 2, 3); - } -}"; - await AssertFormatAsync(expectedCode, code); - } + var expected = """ - [Fact] - public async Task FormatRecursivePattern_Properties_Singleline() - { - var code = @"class C -{ - void M() { _ = this is C{ P1 : 1 } ; } -}"; - var expectedCode = @"class C -{ - void M() { _ = this is C { P1: 1 }; } -}"; + class C + { + void goo() + { + } + } + """; - await AssertFormatAsync(expectedCode, code); - } + var options = new OptionsCollection(LanguageNames.CSharp) { { CSharpFormattingOptions2.WrappingPreserveSingleLine, false } }; + await AssertFormatAsync(expected, code, changedOptionSet: options); + } - [Fact] - public async Task FormatRecursivePattern_Properties_Multiline() - { - var code = @"class C -{ - void M() { -_ = this is -{ -P1 : 1 , -P2 : 2 -} ; -} -}"; - var expectedCode = @"class C -{ - void M() + [Fact] + public async Task LeaveStatementMethodDeclarationSameLine_False() { - _ = this is - { - P1: 1, - P2: 2 - }; - } -}"; + var code = """ - await AssertFormatAsync(expectedCode, code); - } + class Program + { + void goo() + { + int x = 0; int y = 0; + } + } + """; - [Fact] - public async Task FormatRecursivePattern_Properties_Multiline2() - { - var code = @"class C -{ - void M() { -_ = this is { -P1 : 1 , -P2 : 2 -} ; -} -}"; - var expectedCode = @"class C -{ - void M() - { - _ = this is - { - P1: 1, - P2: 2 - }; - } -}"; + var expected = """ - await AssertFormatAsync(expectedCode, code); - } + class Program + { + void goo() + { + int x = 0; + int y = 0; + } + } + """; - [Fact] - public async Task FormatRecursivePattern_Properties_Multiline3() - { - var code = @"class C -{ - void M() { -_ = this is { -P1 : 1 , -P2 : 2, P3: 3 -} ; -} -}"; - var expectedCode = @"class C -{ - void M() - { - _ = this is - { - P1: 1, - P2: 2, P3: 3 - }; + var options = new OptionsCollection(LanguageNames.CSharp) { { CSharpFormattingOptions2.WrappingKeepStatementsOnSingleLine, false } }; + await AssertFormatAsync(expected, code, changedOptionSet: options); } -}"; - - await AssertFormatAsync(expectedCode, code); - } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/27268")] - public async Task FormatRecursivePattern_NoSpaceBetweenTypeAndPositionalSubpattern() - { - var code = @"class C -{ - void M() { -_ = this is C( 1 , 2 ){} ; } -}"; - var expectedCode = @"class C -{ - void M() + [Fact] + public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_0000() { - _ = this is C(1, 2) { }; - } -}"; - // no space separates the type and the positional pattern - await AssertFormatAsync(expectedCode, code); - } + var code = """ + + class Program + { + int[ ] x; + int[ , ] y; + int[ , , ] z = new int[1,2,3]; + var a = new[ ] { 0 }; + } + """; - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/27268")] - public async Task FormatRecursivePattern_PreferSpaceBetweenTypeAndPositionalSubpattern() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) + var expected = """ + + class Program { - { CSharpFormattingOptions2.SpaceAfterMethodCallName, true } - }; - var code = @"class C -{ - void M() { -_ = this is C( 1 , 2 ){} ; } -}"; - var expectedCode = @"class C -{ - void M() - { - _ = this is C (1, 2) { }; - } -}"; - await AssertFormatAsync(expectedCode, code, changedOptionSet: changingOptions); - } + int[] x; + int[,] y; + int[,,] z = new int[1,2,3]; + var a = new[] { 0 }; + } + """; - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/27268")] - public async Task FormatRecursivePattern_PreferSpaceInsidePositionalSubpatternParentheses() + var options = new OptionsCollection(LanguageNames.CSharp) { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) - { - { CSharpFormattingOptions2.SpaceWithinMethodCallParentheses, true } - }; - var code = @"class C -{ - void M() { -_ = this is C( 1 , 2 ){} ; -_ = this is C( ){} ; } -}"; - var expectedCode = @"class C -{ - void M() - { - _ = this is C( 1, 2 ) { }; - _ = this is C() { }; + { SpaceBetweenEmptySquareBrackets, false }, + { SpaceWithinSquareBrackets, false }, + { SpaceBeforeComma, false }, + { SpaceAfterComma, false }, + }; + await AssertFormatAsync(expected, code, changedOptionSet: options); } -}"; - await AssertFormatAsync(expectedCode, code, changedOptionSet: changingOptions); - } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/27268")] - public async Task FormatRecursivePattern_PreferSpaceInsideEmptyPositionalSubpatternParentheses() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) - { - { CSharpFormattingOptions2.SpaceBetweenEmptyMethodCallParentheses, true } - }; - var code = @"class C -{ - void M() { -_ = this is C( 1 , 2 ){} ; -_ = this is C( ){} ; } -}"; - var expectedCode = @"class C -{ - void M() + [Fact] + public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_0001() { - _ = this is C(1, 2) { }; - _ = this is C( ) { }; - } -}"; - await AssertFormatAsync(expectedCode, code, changedOptionSet: changingOptions); - } + var code = """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/34683")] - public async Task FormatRecursivePattern_InBinaryOperation() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) + class Program { - { CSharpFormattingOptions2.SpaceWithinMethodCallParentheses, true } - }; - var code = @"class C -{ - void M() - { - return - typeWithAnnotations is { } && true; - } -}"; - var expectedCode = code; - await AssertFormatAsync(expectedCode, code, changedOptionSet: changingOptions); - } + int[ ] x; + int[ , ] y; + int[ , , ] z = new int[1,2,3]; + var a = new[ ] { 0 }; + } + """; - [Fact] - public async Task FormatPropertyPattern_MultilineAndEmpty() - { - var code = @"class C -{ - void M() { -_ = this is + var expected = """ + + class Program { - }; -} -}"; - var expectedCode = @"class C -{ - void M() - { - _ = this is + int[] x; + int[,] y; + int[,,] z = new int[1, 2, 3]; + var a = new[] { 0 }; + } + """; + + var options = new OptionsCollection(LanguageNames.CSharp) { + { SpaceBetweenEmptySquareBrackets, false }, + { SpaceWithinSquareBrackets, false }, + { SpaceBeforeComma, false }, + { SpaceAfterComma, true }, }; + await AssertFormatAsync(expected, code, changedOptionSet: options); } -}"; - await AssertFormatAsync(expectedCode, code); - } - [Fact] - public async Task FormatSwitchExpression_IndentArms() - { - var code = @"class C -{ - void M() { -_ = this switch -{ -{ P1: 1} => true, -(0, 1) => true, -_ => false -}; - -} -}"; - var expectedCode = @"class C -{ - void M() + [Fact] + public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_0010() { - _ = this switch + var code = """ + + class Program + { + int[ ] x; + int[ , ] y; + int[ , , ] z = new int[1,2,3]; + var a = new[ ] { 0 }; + } + """; + + var expected = """ + + class Program + { + int[] x; + int[,] y; + int[,,] z = new int[1 ,2 ,3]; + var a = new[] { 0 }; + } + """; + + var options = new OptionsCollection(LanguageNames.CSharp) { - { P1: 1 } => true, - (0, 1) => true, - _ => false + { SpaceBetweenEmptySquareBrackets, false }, + { SpaceWithinSquareBrackets, false }, + { SpaceBeforeComma, true }, + { SpaceAfterComma, false }, }; - + await AssertFormatAsync(expected, code, changedOptionSet: options); } -}"; - await AssertFormatAsync(expectedCode, code); - } - [Fact] - public async Task FormatPropertyPattern_FollowedByInvocation() - { - var code = @"class C -{ - void M() { -_ = this is { } -M(); -} -}"; - var expectedCode = @"class C -{ - void M() + [Fact] + public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_0011() { - _ = this is { } - M(); - } -}"; - // although 'M' will be parsed into the pattern on line above, we should not wrap the pattern - await AssertFormatAsync(expectedCode, code); - } + var code = """ - [Fact] - public async Task FormatPositionalPattern_FollowedByInvocation() + class Program + { + int[ ] x; + int[ , ] y; + int[ , , ] z = new int[1,2,3]; + var a = new[ ] { 0 }; + } + """; + + var expected = """ + + class Program + { + int[] x; + int[,] y; + int[,,] z = new int[1 , 2 , 3]; + var a = new[] { 0 }; + } + """; + + var options = new OptionsCollection(LanguageNames.CSharp) { - var code = @"class C -{ - void M() { -_ = this is (1, 2) { } -M(); -} -}"; - var expectedCode = @"class C -{ - void M() - { - _ = this is (1, 2) { } - M(); + { SpaceBetweenEmptySquareBrackets, false }, + { SpaceWithinSquareBrackets, false }, + { SpaceBeforeComma, true }, + { SpaceAfterComma, true }, + }; + await AssertFormatAsync(expected, code, changedOptionSet: options); } -}"; - // although 'M' will be parsed into the pattern on line above, we should not wrap the pattern - await AssertFormatAsync(expectedCode, code); - } - [Fact] - public async Task FormatPositionalPattern_FollowedByScope() - { - var code = @"class C -{ - void M() { -_ = this is (1, 2) -{ - M(); -} -} -}"; - var expectedCode = @"class C -{ - void M() + [Fact] + public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_0100() { - _ = this is (1, 2) + var code = """ + + class Program + { + int[ ] x; + int[, ] y; + int[, , ] z = new int[1,2,3]; + var a = new[ ] { 0 }; + } + """; + + var expected = """ + + class Program + { + int[] x; + int[,] y; + int[,,] z = new int[ 1,2,3 ]; + var a = new[] { 0 }; + } + """; + + var options = new OptionsCollection(LanguageNames.CSharp) { - M(); + { SpaceBetweenEmptySquareBrackets, false }, + { SpaceWithinSquareBrackets, true }, + { SpaceBeforeComma, false }, + { SpaceAfterComma, false }, + }; + await AssertFormatAsync(expected, code, changedOptionSet: options); } -} -}"; - // You should not invoke Format on incomplete code and expect nice results - await AssertFormatAsync(expectedCode, code); - } - [Fact] - public async Task FormatSwitchExpression_MultilineAndNoArms() - { - var code = @"class C -{ - void M() { -_ = this switch -{ - }; -} -}"; - var expectedCode = @"class C -{ - void M() + [Fact] + public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_0101() { - _ = this switch + var code = """ + + class Program + { + int[ ] x; + int[, ] y; + int[, , ] z = new int[1,2,3]; + var a = new[ ] { 0 }; + } + """; + + var expected = """ + + class Program + { + int[] x; + int[,] y; + int[,,] z = new int[ 1, 2, 3 ]; + var a = new[] { 0 }; + } + """; + + var options = new OptionsCollection(LanguageNames.CSharp) { + { SpaceBetweenEmptySquareBrackets, false }, + { SpaceWithinSquareBrackets, true }, + { SpaceBeforeComma, false }, + { SpaceAfterComma, true }, }; + await AssertFormatAsync(expected, code, changedOptionSet: options); } -}"; - await AssertFormatAsync(expectedCode, code); - } - - [Fact] - public async Task FormatSwitchExpression_ExpressionAnchoredToArm() - { - var code = @"class C -{ - void M() { -_ = this switch -{ -{ P1: 1} -=> true, -(0, 1) - => true, -_ - => false -}; -} -}"; - var expectedCode = @"class C -{ - void M() + [Fact] + public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_0110() { - _ = this switch - { - { P1: 1 } - => true, - (0, 1) - => true, - _ - => false - }; + var code = """ - } -}"; - await AssertFormatAsync(expectedCode, code); - } + class Program + { + int[ ] x; + int[, ] y; + int[, , ] z = new int[1,2,3]; + var a = new[ ] { 0 }; + } + """; - [Fact] - public async Task FormatSwitchExpression_NoSpaceBeforeColonInArm() - { - var code = @"class C -{ - void M() { -_ = this switch -{ -{ P1: 1} -=> true, -(0, 1) - => true, -_ - => false -}; + var expected = """ -} -}"; - var expectedCode = @"class C -{ - void M() - { - _ = this switch + class Program + { + int[] x; + int[,] y; + int[,,] z = new int[ 1 ,2 ,3 ]; + var a = new[] { 0 }; + } + """; + + var options = new OptionsCollection(LanguageNames.CSharp) { - { P1: 1 } - => true, - (0, 1) - => true, - _ - => false + { SpaceBetweenEmptySquareBrackets, false }, + { SpaceWithinSquareBrackets, true }, + { SpaceBeforeComma, true }, + { SpaceAfterComma, false }, }; - + await AssertFormatAsync(expected, code, changedOptionSet: options); } -}"; - await AssertFormatAsync(expectedCode, code); - } - - [Fact] - public async Task FormatSwitchExpression_ArmCommaWantsNewline() - { - var code = @"class C -{ - void M() { -_ = this switch -{ -{ P1: 1} => true, -(0, 1) => true, _ => false -}; -} -}"; - var expectedCode = @"class C -{ - void M() + [Fact] + public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_0111() { - _ = this switch - { - { P1: 1 } => true, - (0, 1) => true, - _ => false - }; + var code = """ - } -}"; - await AssertFormatAsync(expectedCode, code); - } + class Program + { + int[ ] x; + int[, ] y; + int[, , ] z = new int[1,2,3]; + var a = new[ ] { 0 }; + } + """; - [Fact] - public async Task FormatSwitchExpression_ArmCommaPreservesLines() - { - var code = @"class C -{ - void M() { -_ = this switch -{ -{ P1: 1} => true, + var expected = """ -(0, 1) => true, _ => false -}; + class Program + { + int[] x; + int[,] y; + int[,,] z = new int[ 1 , 2 , 3 ]; + var a = new[] { 0 }; + } + """; -} -}"; - var expectedCode = @"class C -{ - void M() - { - _ = this switch + var options = new OptionsCollection(LanguageNames.CSharp) { - { P1: 1 } => true, - - (0, 1) => true, - _ => false + { SpaceBetweenEmptySquareBrackets, false }, + { SpaceWithinSquareBrackets, true }, + { SpaceBeforeComma, true }, + { SpaceAfterComma, true }, }; - + await AssertFormatAsync(expected, code, changedOptionSet: options); } -}"; - await AssertFormatAsync(expectedCode, code); - } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/33839")] - public async Task FormatSwitchExpression_ExpressionBody() - { - var code = @" -public class Test -{ - public object Method(int i) - => i switch -{ -1 => 'a', -2 => 'b', -_ => null, -}; -}"; - var expectedCode = @" -public class Test -{ - public object Method(int i) - => i switch - { - 1 => 'a', - 2 => 'b', - _ => null, - }; -}"; + [Fact] + public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_1000() + { + var code = """ - await AssertFormatAsync(expectedCode, code); - } + class Program + { + int[] x; + int[ ,] y; + int[ , ,] z = new int[1,2,3]; + var a = new[] { 0 }; + } + """; - [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/72196")] - [InlineData("[]")] - [InlineData("[a]")] - [InlineData("[a, b]")] - [InlineData("[..]")] - [InlineData("[var a, .., var b]")] - [InlineData("[{ } a, null]")] - [InlineData("[a, []]")] - public async Task FormatSwitchExpression_ListPatternAligned(string listPattern) - { - var code = $$""" - class C - { - void M() - { - _ = Array.Empty() switch - { - {{listPattern}} => 0, - _ => 1, - }; - } - } - """; - var expectedCode = $$""" - class C - { - void M() - { - _ = Array.Empty() switch - { - {{listPattern}} => 0, - _ => 1, - }; - } - } - """; - await AssertFormatAsync(expectedCode, code); - } + var expected = """ - [Fact] - public async Task FormatSwitchWithPropertyPattern() - { - var code = @"class C -{ - void M() - { - switch (this) + class Program + { + int[ ] x; + int[ , ] y; + int[ , , ] z = new int[1,2,3]; + var a = new[ ] { 0 }; + } + """; + + var options = new OptionsCollection(LanguageNames.CSharp) { - case { P1: 1, P2: { P3: 3, P4: 4 } }: - break; - } + { SpaceBetweenEmptySquareBrackets, true }, + { SpaceWithinSquareBrackets, false }, + { SpaceBeforeComma, false }, + { SpaceAfterComma, false }, + }; + await AssertFormatAsync(expected, code, changedOptionSet: options); } -}"; - var expectedCode = @"class C -{ - void M() + + [Fact] + public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_1001() { - switch (this) + var code = """ + + class Program + { + int[] x; + int[ ,] y; + int[ , ,] z = new int[1,2,3]; + var a = new[] { 0 }; + } + """; + + var expected = """ + + class Program + { + int[ ] x; + int[ , ] y; + int[ , , ] z = new int[1, 2, 3]; + var a = new[ ] { 0 }; + } + """; + + var options = new OptionsCollection(LanguageNames.CSharp) { - case { P1: 1, P2: { P3: 3, P4: 4 } }: - break; - } + { SpaceBetweenEmptySquareBrackets, true }, + { SpaceWithinSquareBrackets, false }, + { SpaceBeforeComma, false }, + { SpaceAfterComma, true }, + }; + await AssertFormatAsync(expected, code, changedOptionSet: options); } -}"; - await AssertFormatAsync(expectedCode, code); - } - [Fact] - public async Task FormatSwitchWithPropertyPattern_Singleline() - { - var code = @"class C -{ - void M() + [Fact] + public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_1010() { - switch (this) + var code = """ + + class Program + { + int[] x; + int[ ,] y; + int[ , ,] z = new int[1,2,3]; + var a = new[] { 0 }; + } + """; + + var expected = """ + + class Program + { + int[ ] x; + int[ , ] y; + int[ , , ] z = new int[1 ,2 ,3]; + var a = new[ ] { 0 }; + } + """; + + var options = new OptionsCollection(LanguageNames.CSharp) { - case { P1: 1, P2: { P3: 3, P4: 4 } }: break; - } + { SpaceBetweenEmptySquareBrackets, true }, + { SpaceWithinSquareBrackets, false }, + { SpaceBeforeComma, true }, + { SpaceAfterComma, false }, + }; + await AssertFormatAsync(expected, code, changedOptionSet: options); } -}"; - var expectedCode = @"class C -{ - void M() + + [Fact] + public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_1011() { - switch (this) - { - case { P1: 1, P2: { P3: 3, P4: 4 } }: break; - } - } -}"; + var code = """ - await AssertFormatAsync(expectedCode, code); - } + class Program + { + int[] x; + int[ ,] y; + int[ , ,] z = new int[1,2,3]; + var a = new[] { 0 }; + } + """; - [Fact] - public async Task FormatSwitchWithPropertyPattern_Singleline2() - { - var code = @"class C -{ - void M() - { - switch (this) + var expected = """ + + class Program + { + int[ ] x; + int[ , ] y; + int[ , , ] z = new int[1 , 2 , 3]; + var a = new[ ] { 0 }; + } + """; + + var options = new OptionsCollection(LanguageNames.CSharp) { - case { P1: 1, P2: { P3: 3, P4: 4 } }: System.Console.Write(1); - break; - } + { SpaceBetweenEmptySquareBrackets, true }, + { SpaceWithinSquareBrackets, false }, + { SpaceBeforeComma, true }, + { SpaceAfterComma, true }, + }; + await AssertFormatAsync(expected, code, changedOptionSet: options); } -}"; - var expectedCode = @"class C -{ - void M() + + [Fact] + public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_1100() { - switch (this) - { - case { P1: 1, P2: { P3: 3, P4: 4 } }: - System.Console.Write(1); - break; - } - } -}"; - await AssertFormatAsync(expectedCode, code); - } + var code = """ + + class Program + { + int[ ] x; + int[ , ] y; + int[ , , ] z = new int[1,2,3]; + var a = new[ ] { 0 }; + } + """; - [Fact] - public async Task SpacingInTupleExtension() - { - var code = @"static class Class5 -{ - static void Extension(this(int, string) self) { } -}"; - var expectedCode = @"static class Class5 -{ - static void Extension(this (int, string) self) { } -}"; + var expected = """ - await AssertFormatAsync(expectedCode, code); - } + class Program + { + int[ ] x; + int[ , ] y; + int[ , , ] z = new int[ 1,2,3 ]; + var a = new[ ] { 0 }; + } + """; - [Fact] - public async Task SpacingInNestedDeconstruction() + var options = new OptionsCollection(LanguageNames.CSharp) { - var code = @"class Class5{ -void bar() -{ -( int x1 , var( x2,x3 ) )=(1,(2,3)); -} -}"; - var expectedCode = @"class Class5 -{ - void bar() - { - (int x1, var (x2, x3)) = (1, (2, 3)); + { SpaceBetweenEmptySquareBrackets, true }, + { SpaceWithinSquareBrackets, true }, + { SpaceBeforeComma, false }, + { SpaceAfterComma, false }, + }; + await AssertFormatAsync(expected, code, changedOptionSet: options); } -}"; - await AssertFormatAsync(expectedCode, code); - } + [Fact] + public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_1101() + { + var code = """ + + class Program + { + int[ ] x; + int[ , ] y; + int[ , , ] z = new int[1,2,3]; + var a = new[ ] { 0 }; + } + """; + + var expected = """ + + class Program + { + int[ ] x; + int[ , ] y; + int[ , , ] z = new int[ 1, 2, 3 ]; + var a = new[ ] { 0 }; + } + """; - [Fact] - public async Task SpacingInSuppressNullableWarningExpression() + var options = new OptionsCollection(LanguageNames.CSharp) { - var code = -@"class C -{ - static object F() - { - object? o[] = null; - object? x = null; - object? y = null; - return x ! ?? (y) ! ?? o[0] !; + { SpaceBetweenEmptySquareBrackets, true }, + { SpaceWithinSquareBrackets, true }, + { SpaceBeforeComma, false }, + { SpaceAfterComma, true }, + }; + await AssertFormatAsync(expected, code, changedOptionSet: options); } -}"; - var expectedCode = -@"class C -{ - static object F() + + [Fact] + public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_1110() { - object? o[] = null; - object? x = null; - object? y = null; - return x! ?? (y)! ?? o[0]!; - } -}"; + var code = """ - await AssertFormatAsync(expectedCode, code); - } + class Program + { + int[ ] x; + int[ , ] y; + int[ , , ] z = new int[1,2,3]; + var a = new[ ] { 0 }; + } + """; + + var expected = """ - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545335")] - public async Task PreprocessorOnSameLine() + class Program + { + int[ ] x; + int[ , ] y; + int[ , , ] z = new int[ 1 ,2 ,3 ]; + var a = new[ ] { 0 }; + } + """; + + var options = new OptionsCollection(LanguageNames.CSharp) { - var code = @"class C -{ -}#line default + { SpaceBetweenEmptySquareBrackets, true }, + { SpaceWithinSquareBrackets, true }, + { SpaceBeforeComma, true }, + { SpaceAfterComma, false }, + }; + await AssertFormatAsync(expected, code, changedOptionSet: options); + } -#line hidden"; + [Fact] + public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_1111() + { + var code = """ - var expected = @"class C -{ -}#line default + class Program + { + int[ ] x; + int[ , ] y; + int[ , , ] z = new int[1,2,3]; + var a = new[ ] { 0 }; + } + """; -#line hidden"; + var expected = """ - await AssertFormatAsync(expected, code); - } + class Program + { + int[ ] x; + int[ , ] y; + int[ , , ] z = new int[ 1 , 2 , 3 ]; + var a = new[ ] { 0 }; + } + """; - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545626")] - public async Task ArraysInAttributes() + var options = new OptionsCollection(LanguageNames.CSharp) { - var code = @"[A(X = new int[] { 1 })] -public class A : Attribute -{ - public int[] X; -}"; + { SpaceBetweenEmptySquareBrackets, true }, + { SpaceWithinSquareBrackets, true }, + { SpaceBeforeComma, true }, + { SpaceAfterComma, true }, + }; + await AssertFormatAsync(expected, code, changedOptionSet: options); + } - var expected = @"[A(X = new int[] { 1 })] -public class A : Attribute -{ - public int[] X; -}"; + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14128")] + public async Task SpaceBeforeCommasInLocalFunctionParameters() + { + var code = """ - await AssertFormatAsync(expected, code); - } + class Program + { + void Goo() + { + void LocalFunction(int i, string s) + { + } + } + } + """; + + var expected = """ + + class Program + { + void Goo() + { + void LocalFunction(int i , string s) + { + } + } + } + """; - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530580")] - public async Task NoNewLineAfterBraceInExpression() + var options = new OptionsCollection(LanguageNames.CSharp) { - var code = @"public class A -{ - void Method() - { - var po = cancellationToken.CanBeCanceled ? - new ParallelOptions() { CancellationToken = cancellationToken } : - defaultParallelOptions; + { SpaceBeforeComma, true }, + }; + await AssertFormatAsync(expected, code, changedOptionSet: options); } -}"; - var expected = @"public class A -{ - void Method() + [Fact] + public async Task ArrayDeclarationShouldFollowEmptySquareBrackets() { - var po = cancellationToken.CanBeCanceled ? - new ParallelOptions() { CancellationToken = cancellationToken } : - defaultParallelOptions; - } -}"; + const string code = """ - await AssertFormatAsync(expected, code); - } + class Program + { + var t = new Goo(new[ ] { "a", "b" }); + } + """; - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530580")] - public async Task NoIndentForNestedUsingWithoutBraces() - { - var code = @"class C -{ -void M() -{ -using (null) -using (null) -{ -} -} -} -"; + const string expected = """ - var expected = @"class C -{ - void M() - { - using (null) - using (null) + class Program + { + var t = new Goo(new[] { "a", "b" }); + } + """; + + var options = new OptionsCollection(LanguageNames.CSharp) { - } + { CSharpFormattingOptions2.SpaceWithinSquareBrackets, true }, + { CSharpFormattingOptions2.SpaceBetweenEmptySquareBrackets, false } + }; + await AssertFormatAsync(expected, code, changedOptionSet: options); } -} -"; - - await AssertFormatAsync(expected, code); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530580")] - public async Task NoIndentForNestedUsingWithoutBraces2() - { - var code = @"class C -{ - void M() + [Fact] + public async Task SquareBracesBefore_True() { - using (null) - using (null) - using (null) + var code = """ + + class Program + { + int[] x; + } + """; + + var expected = """ + + class Program { + int [] x; } + """; + + var options = new OptionsCollection(LanguageNames.CSharp) { { CSharpFormattingOptions2.SpaceBeforeOpenSquareBracket, true } }; + await AssertFormatAsync(expected, code, changedOptionSet: options); } -} -"; - var expected = @"class C -{ - void M() + [Fact] + public async Task SquareBracesAndValue_True() { - using (null) - using (null) - using (null) - { - } - } -} -"; + var code = """ - await AssertFormatAsync(expected, code); - } + class Program + { + int[3] x; + } + """; - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530580")] - public async Task NoIndentForNestedUsingWithoutBraces3() - { - var code = @"class C -{ - void M() - { - using (null) - using (null) - using (null) - { - } + var expected = """ + + class Program + { + int[ 3 ] x; + } + """; + + var options = new OptionsCollection(LanguageNames.CSharp) { { CSharpFormattingOptions2.SpaceWithinSquareBrackets, true } }; + await AssertFormatAsync(expected, code, changedOptionSet: options); } -} -"; - var expected = @"class C -{ - void M() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/917351")] + public async Task TestLockStatement() { - using (null) - using (null) - using (null) - { - } - } -} -"; + var code = """ - await AssertFormatAsync(expected, code); - } + class Program + { + public void Method() + { + lock (expression) + { + // goo + } + } + } + """; - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546678")] - public async Task UnicodeWhitespace() - { - var code = "\u001A"; + var expected = """ - await AssertFormatAsync("", code); - } + class Program + { + public void Method() + { + lock (expression) { + // goo + } + } + } + """; - [Fact, WorkItem(17431, "DevDiv_Projects/Roslyn")] - public async Task NoElasticRuleOnRegularFile() + var options = new OptionsCollection(LanguageNames.CSharp) { - var code = @"class Consumer -{ - public int P + { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ControlBlocks, false) } + }; + + await AssertFormatAsync(expected, code, changedOptionSet: options); + } + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/962416")] + public async Task TestCheckedAndUncheckedStatement() { + var code = """ + + class Program + { + public void Method() + { + checked + { + // goo + } + unchecked + { + } } -}"; + } + """; - var expected = @"class Consumer -{ - public int P - { - } -}"; + var expected = """ - await AssertFormatAsync(expected, code); - } + class Program + { + public void Method() + { + checked { + // goo + } + unchecked { + } + } + } + """; - [Fact, WorkItem(584599, "DevDiv_Projects/Roslyn")] - public async Task CaseSection() - { - var code = @"class C -{ - void Method() - { - switch(i) + var options = new OptionsCollection(LanguageNames.CSharp) { - // test1 - case 1: - // test2 - case 2: - // test3 - int i2 = 10; - // test 4 - case 4: -// test 5 - } + { NewLineBeforeOpenBrace , NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ControlBlocks, false) } + }; + + await AssertFormatAsync(expected, code, changedOptionSet: options); } -}"; - var expected = @"class C -{ - void Method() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/953535")] + public async Task ConditionalMemberAccess() { - switch (i) - { - // test1 - case 1: - // test2 - case 2: - // test3 - int i2 = 10; - // test 4 - case 4: - // test 5 - } - } -}"; + var code = """ - await AssertFormatAsync(expected, code); - } + using System; + class A + { + public A a; + } - [Fact, WorkItem(553654, "DevDiv_Projects/Roslyn")] - public async Task Bugfix_553654_LabelStatementIndenting() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) + class Program { - { CSharpFormattingOptions2.LabelPositioning, LabelPositionOptions.LeftMost } - }; + static void Main(string[] args) + { + A a = null; + A ?.a = null; + System.Console.WriteLine(args ?[0]); + System.Console.WriteLine(args ?.Length); + } + } + """; - var code = @"class Program -{ - void F() - { - foreach (var x in new int[] { }) - { - goo: - int a = 1; - } + var expected = """ + + using System; + class A + { + public A a; + } + + class Program + { + static void Main(string[] args) + { + A a = null; + A?.a = null; + System.Console.WriteLine(args?[0]); + System.Console.WriteLine(args?.Length); + } + } + """; + var parseOptions = new CSharpParseOptions(); + await AssertFormatAsync(expected, code, parseOptions: parseOptions); } -}"; - var expected = @"class Program -{ - void F() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/924172")] + public async Task IgnoreSpacesInDeclarationStatementEnabled() { - foreach (var x in new int[] { }) + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { -goo: - int a = 1; - } + { CSharpFormattingOptions2.SpacesIgnoreAroundVariableDeclaration, true } + }; + var code = """ + + class Program + { + static void Main(string[] args) + { + int s; + } + } + """; + + var expected = """ + + class Program + { + static void Main(string[] args) + { + int s; + } + } + """; + await AssertFormatAsync(expected, code, changedOptionSet: changingOptions); } -}"; - await AssertFormatAsync(expected, code, changingOptions); - } - [Fact, WorkItem(707064, "DevDiv_Projects/Roslyn")] - public async Task Bugfix_707064_SpaceAfterSecondSemiColonInFor() - { - var code = @"class Program -{ - void F() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/899492")] + public async Task CommentIsLeadingTriviaOfStatementNotLabel() { - for (int i = 0; i < 5;) - { - } + var code = """ + + class C + { + void M() + { + label: + // comment + M(); + M(); + } + } + """; + + var expected = """ + + class C + { + void M() + { + label: + // comment + M(); + M(); + } + } + """; + await AssertFormatAsync(expected, code); } -}"; - var expected = @"class Program -{ - void F() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/991547")] + public async Task DoNotWrappingTryCatchFinallyIfOnSingleLine() { - for (int i = 0; i < 5;) - { - } + var code = """ + + class C + { + void M() + { + try { } + catch { } + finally { } + } + } + """; + + var expected = """ + + class C + { + void M() + { + try { } + catch { } + finally { } + } + } + """; + await AssertFormatAsync(expected, code); } -}"; - await AssertFormatAsync(expected, code); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/772313")] - public async Task Bugfix_772313_ReturnKeywordBeforeQueryClauseDoesNotTriggerNewLineOnFormat() - { - var code = @"class C -{ - int M() - { - return from c in "" - select c; + [Fact] + public async Task InterpolatedStrings1() + { + var code = """ + + class C + { + void M() + { + var a = "World"; + var b = $"Hello, {a}"; + } + } + """; + + var expected = """ + + class C + { + void M() + { + var a = "World"; + var b = $"Hello, {a}"; + } + } + """; + + await AssertFormatAsync(expected, code); } -}"; - var expected = @"class C -{ - int M() + [Fact] + public async Task InterpolatedStrings2() { - return from c in "" - select c; - } -}"; - await AssertFormatAsync(expected, code); - } + var code = """ - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/772304")] - public async Task Bugfix_772313_PreserveMethodParameterIndentWhenAttributePresent() - { - var code = @"class C -{ - void M - ( - [In] - bool b - ); -} + class C + { + void M() + { + var a = "Hello"; + var b = "World"; + var c = $"{a}, {b}"; + } + } + """; -class C -{ - void M - ( - [In] - List b - ); -} + var expected = """ -class C -{ - void M - ( - [In] - [In, In] - List b - ); -}"; - - var expected = @"class C -{ - void M - ( - [In] - bool b - ); -} + class C + { + void M() + { + var a = "Hello"; + var b = "World"; + var c = $"{a}, {b}"; + } + } + """; -class C -{ - void M - ( - [In] - List b - ); -} + await AssertFormatAsync(expected, code); + } -class C -{ - void M - ( - [In] - [In, In] - List b - ); -}"; - await AssertFormatAsync(expected, code); - } + [Fact] + public async Task InterpolatedStrings3() + { + var code = """ - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/776513")] - public async Task Bugfix_776513_CheckBraceIfNotMissingBeforeApplyingOperationForBracedBlocks() - { - var code = @"var alwaysTriggerList = new[] - Dim triggerOnlyWithLettersList ="; + class C + { + void M() + { + var a = "World"; + var b = $"Hello, { a }"; + } + } + """; - var expected = @"var alwaysTriggerList = new[] - Dim triggerOnlyWithLettersList ="; - await AssertFormatAsync(expected, code); - } + var expected = """ - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/769342")] - public async Task ShouldFormatDocCommentWithIndentSameAsTabSizeWithUseTabTrue() - { - var optionSet = new OptionsCollection(LanguageNames.CSharp) { { FormattingOptions2.UseTabs, true } }; + class C + { + void M() + { + var a = "World"; + var b = $"Hello, {a}"; + } + } + """; - await AssertFormatAsync(@"namespace ConsoleApplication1 -{ - /// - /// fka;jsgdflkhsjflgkhdsl; - /// - class Program - { - } -}", @"namespace ConsoleApplication1 -{ - /// - /// fka;jsgdflkhsjflgkhdsl; - /// - class Program - { + await AssertFormatAsync(expected, code); } -}", changedOptionSet: optionSet); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/797278")] - public async Task TestSpacingOptionAroundControlFlow() - { - const string code = @" -class Program -{ - public void goo() + [Fact] + public async Task InterpolatedRawStrings3() { - int i; - for(i=0; i<10; i++) - {} + var code = """" - foreach(i in new[] {1,2,3}) - {} + class C + { + void M() + { + var a = "World"; + var b = $"""Hello, { a }"""; + } + } + """"; - if (i==10) - {} + var expected = """" - while(i==10) - {} + class C + { + void M() + { + var a = "World"; + var b = $"""Hello, {a}"""; + } + } + """"; - switch(i) - { - default: break; - } + await AssertFormatAsync(expected, code); + } - do {} while (true); + [Fact] + public async Task InterpolatedStrings4() + { + var code = """ - try - { } - catch (System.Exception) - { } - catch (System.Exception e) when (true) - { } + class C + { + void M() + { + var a = "Hello"; + var b = "World"; + var c = $"{ a }, { b }"; + } + } + """; - using(somevar) - { } + var expected = """ - lock(somevar) - { } + class C + { + void M() + { + var a = "Hello"; + var b = "World"; + var c = $"{a}, {b}"; + } + } + """; - fixed(char* p = str) - { } + await AssertFormatAsync(expected, code); } -}"; - const string expected = @" -class Program -{ - public void goo() - { - int i; - for ( i = 0; i < 10; i++ ) - { } - foreach ( i in new[] { 1, 2, 3 } ) - { } + [Fact] + public async Task InterpolatedStrings5() + { + var code = """ - if ( i == 10 ) - { } + class C + { + void M() + { + var a = "World"; + var b = $@"Hello, {a}"; + } + } + """; - while ( i == 10 ) - { } + var expected = """ - switch ( i ) - { - default: break; - } + class C + { + void M() + { + var a = "World"; + var b = $@"Hello, {a}"; + } + } + """; - do { } while ( true ); + await AssertFormatAsync(expected, code); + } - try - { } - catch ( System.Exception ) - { } - catch ( System.Exception e ) when ( true ) - { } + [Fact] + public async Task InterpolatedStrings6() + { + var code = """ - using ( somevar ) - { } + class C + { + void M() + { + var a = "Hello"; + var b = "World"; + var c = $@"{a}, {b}"; + } + } + """; - lock ( somevar ) - { } + var expected = """ - fixed ( char* p = str ) - { } - } -}"; - var optionSet = new OptionsCollection(LanguageNames.CSharp) + class C { - { SpaceBetweenParentheses, SpaceBetweenParentheses.DefaultValue.WithFlagValue( SpacePlacementWithinParentheses.ControlFlowStatements, true) }, - }; + void M() + { + var a = "Hello"; + var b = "World"; + var c = $@"{a}, {b}"; + } + } + """; - await AssertFormatAsync(expected, code, changedOptionSet: optionSet); - } + await AssertFormatAsync(expected, code); + } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37031")] - [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/176345")] - public async Task TestSpacingOptionAfterControlFlowKeyword() - { - var code = @" -class Program -{ - public void goo() + [Fact] + public async Task InterpolatedStrings7() { - int i; - for (i=0; i<10; i++) - {} + var code = """ - foreach (i in new[] {1,2,3}) - {} + class C + { + void M() + { + var a = "World"; + var b = $@"Hello, { a }"; + } + } + """; - if (i==10) - {} + var expected = """ - while (i==10) - {} + class C + { + void M() + { + var a = "World"; + var b = $@"Hello, {a}"; + } + } + """; - switch (i) - { - default: break; - } + await AssertFormatAsync(expected, code); + } - do {} while (true); + [Fact] + public async Task InterpolatedStrings8() + { + var code = """ - try - { } - catch (System.Exception e) when (true) - { } + class C + { + void M() + { + var a = "Hello"; + var b = "World"; + var c = $@"{ a }, { b }"; + } + } + """; - using (somevar) - { } + var expected = """ - lock (somevar) - { } + class C + { + void M() + { + var a = "Hello"; + var b = "World"; + var c = $@"{a}, {b}"; + } + } + """; - fixed (somevar) - { } + await AssertFormatAsync(expected, code); } -}"; - var expected = @" -class Program -{ - public void goo() + + [Fact] + public async Task InterpolatedStrings9() { - int i; - for(i = 0; i < 10; i++) - { } + var code = """ - foreach(i in new[] { 1, 2, 3 }) - { } + class C + { + void M() + { + var a = "Hello"; + var c = $"{ a }, World"; + } + } + """; - if(i == 10) - { } + var expected = """ - while(i == 10) - { } + class C + { + void M() + { + var a = "Hello"; + var c = $"{a}, World"; + } + } + """; - switch(i) - { - default: break; - } + await AssertFormatAsync(expected, code); + } - do { } while(true); + [Fact] + public async Task InterpolatedStrings10() + { + var code = """ - try - { } - catch(System.Exception e) when(true) - { } + class C + { + void M() + { + var s = $"{42 , -4 :x}"; + } + } + """; - using(somevar) - { } + var expected = """ - lock(somevar) - { } + class C + { + void M() + { + var s = $"{42,-4:x}"; + } + } + """; - fixed(somevar) - { } + await AssertFormatAsync(expected, code); } -}"; - var optionSet = new OptionsCollection(LanguageNames.CSharp) { { CSharpFormattingOptions2.SpaceAfterControlFlowStatementKeyword, false } }; - await AssertFormatAsync(expected, code, changedOptionSet: optionSet); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/766212")] - public async Task TestOptionForSpacingAroundCommas() - { - var code = @" -class Program -{ - public void Main() - { - var a = new[] {1,2,3}; - var digits = new List {1,2,3,4}; - } -}"; - var expectedDefault = @" -class Program -{ - public void Main() + [Fact] + public async Task InterpolatedRawStrings10() { - var a = new[] { 1, 2, 3 }; - var digits = new List { 1, 2, 3, 4 }; - } -}"; - await AssertFormatAsync(expectedDefault, code); + var code = """" - var expectedAfterCommaDisabled = @" -class Program -{ - public void Main() - { - var a = new[] { 1,2,3 }; - var digits = new List { 1,2,3,4 }; - } -}"; - var optionSet = new OptionsCollection(LanguageNames.CSharp) { { CSharpFormattingOptions2.SpaceAfterComma, false } }; - await AssertFormatAsync(expectedAfterCommaDisabled, code, changedOptionSet: optionSet); + class C + { + void M() + { + var s = $"""{42 , -4 :x}"""; + } + } + """"; - var expectedBeforeCommaEnabled = @" -class Program -{ - public void Main() - { - var a = new[] { 1 ,2 ,3 }; - var digits = new List { 1 ,2 ,3 ,4 }; + var expected = """" + + class C + { + void M() + { + var s = $"""{42,-4:x}"""; + } + } + """"; + + await AssertFormatAsync(expected, code); } -}"; - optionSet.Add(CSharpFormattingOptions2.SpaceBeforeComma, true); - await AssertFormatAsync(expectedBeforeCommaEnabled, code, changedOptionSet: optionSet); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/772308")] - public async Task Bugfix_772308_SeparateSuppressionForEachCaseLabelEvenIfEmpty() - { - var code = @" -class C -{ - int M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/59811")] + public async Task InterpolatedStrings11() { - switch (1) - { - case 1: return 1; - case 2: return 2; - case 3: - case 4: return 4; - default: - } + var code = """ + + class C + { + void M() + { + var hostAddress = "host"; + var nasTypeId = "nas"; + var version = "1.2"; + var c = $"{ hostAddress?? ""}/{nasTypeId }/{version??""}"; + } + } + """; + + var expected = """ + + class C + { + void M() + { + var hostAddress = "host"; + var nasTypeId = "nas"; + var version = "1.2"; + var c = $"{hostAddress ?? ""}/{nasTypeId}/{version ?? ""}"; + } + } + """; + + await AssertFormatAsync(expected, code); } -} -"; - var expected = @" -class C -{ - int M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/59811")] + public async Task InterpolatedStrings12() { - switch (1) - { - case 1: return 1; - case 2: return 2; - case 3: - case 4: return 4; - default: - } - } -} -"; - await AssertFormatAsync(expected, code); - } + var code = """ - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/844913")] - public async Task QueryExpressionInExpression() - { - var code = @" -class C -{ - public void CreateSettingsFile(string path, string comment) { - var xml = new XDocument( - new XDeclaration(1.0, utf8, yes), - new XComment(comment), - new XElement(UserSettings, - new XElement(ToolsOptions, - from t in KnownSettings.DefaultCategories - group t by t.Item1 into cat - select new XElement(ToolsOptionsCategory, - new XAttribute(name, cat.Key), - cat.Select(sc => new XElement(ToolsOptionsSubCategory, new XAttribute(name, sc.Item2))) - ) - ) - ) - ); - UpdateSettingsXml(xml); - xml.Save(path); - SettingsPath = path; - } - } -"; + class C + { + void M() + { + var a = 1.2M; + var c = $"{ a : 000.00 }"; + } + } + """; - var expected = @" -class C -{ - public void CreateSettingsFile(string path, string comment) - { - var xml = new XDocument( - new XDeclaration(1.0, utf8, yes), - new XComment(comment), - new XElement(UserSettings, - new XElement(ToolsOptions, - from t in KnownSettings.DefaultCategories - group t by t.Item1 into cat - select new XElement(ToolsOptionsCategory, - new XAttribute(name, cat.Key), - cat.Select(sc => new XElement(ToolsOptionsSubCategory, new XAttribute(name, sc.Item2))) - ) - ) - ) - ); - UpdateSettingsXml(xml); - xml.Save(path); - SettingsPath = path; - } -} -"; - await AssertFormatAsync(expected, code); - } + var expected = """ - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/843479")] - public async Task EmbeddedStatementElse() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) + class C { - { CSharpFormattingOptions2.NewLineForElse, false } - }; + void M() + { + var a = 1.2M; + var c = $"{a: 000.00 }"; + } + } + """; - var code = @" -class C -{ - void Method() - { - if (true) - Console.WriteLine(); else - Console.WriteLine(); + await AssertFormatAsync(expected, code); } -} -"; - var expected = @" -class C -{ - void Method() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/59811")] + public async Task InterpolatedStrings13() { - if (true) - Console.WriteLine(); - else - Console.WriteLine(); - } -} -"; - await AssertFormatAsync(expected, code, changingOptions); - } + var code = """ - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/772311")] - public async Task LineCommentAtTheEndOfLine() - { - var code = @" -using System; + class C + { + void M() + { + var a = 1.2M; + var c = $"{ (a > 2?"a":"b"}"; + } + } + """; -class Program -{ - static void Main(string[] args) - { - Console.WriteLine(); // this is a comment - // that I would like to keep + var expected = """ - // properly indented - } -} -"; + class C + { + void M() + { + var a = 1.2M; + var c = $"{(a > 2 ? "a" : "b"}"; + } + } + """; - var expected = @" -using System; + await AssertFormatAsync(expected, code); + } -class Program -{ - static void Main(string[] args) + [Fact] + public async Task InterpolatedStrings14() { - Console.WriteLine(); // this is a comment - // that I would like to keep + var code = """ - // properly indented - } -} -"; - await AssertFormatAsync(expected, code); - } + class C + { + void M() + { + var s = $"{ 42 , -4 :x}"; + } + } + """; - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38224")] - public async Task BlockCommentAtTheEndOfLine1() - { - var code = @" -using System; + var expected = """ -class Program -{ - static void Main(string[] args) - { - Console.WriteLine(); /* this is a comment */ - // that I would like to keep + class C + { + void M() + { + var s = $"{42,-4:x}"; + } + } + """; - // properly indented + await AssertFormatAsync(expected, code); } -} -"; - var expected = @" -using System; - -class Program -{ - static void Main(string[] args) + [Fact] + public async Task InterpolatedStrings15() { - Console.WriteLine(); /* this is a comment */ - // that I would like to keep + var code = """ + + class C + { + void M() + { + var s = $"{ 42 , -4 }"; + } + } + """; + + var expected = """ + + class C + { + void M() + { + var s = $"{42,-4}"; + } + } + """; - // properly indented + await AssertFormatAsync(expected, code); } -} -"; - await AssertFormatAsync(expected, code); - } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38224")] - public async Task BlockCommentAtTheEndOfLine2() - { - var code = @" -using System; - -class Program -{ - static void Main(string[] args) + [Fact] + public async Task InterpolatedStrings16() { - Console.WriteLine(); // this is a comment - /* that I would like to keep */ + var code = """ - // properly indented - } -} -"; + class C + { + void M() + { + var s = $"{ 42 , -4 : x }"; + } + } + """; - var expected = @" -using System; + var expected = """ -class Program -{ - static void Main(string[] args) - { - Console.WriteLine(); // this is a comment - /* that I would like to keep */ + class C + { + void M() + { + var s = $"{42,-4: x }"; + } + } + """; - // properly indented + await AssertFormatAsync(expected, code); } -} -"; - await AssertFormatAsync(expected, code); - } - - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38224")] - public async Task BlockCommentAtBeginningOfLine() - { - var code = @" -using System; -class Program -{ - static void Main( - int x, // Some comment - /*A*/ int y) + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/1151")] + [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1041787")] + public async Task ReconstructWhitespaceStringUsingTabs_SingleLineComment() { - } -} -"; - await AssertFormatAsync(code, code); - } + var optionSet = new OptionsCollection(LanguageNames.CSharp) { { FormattingOptions2.UseTabs, true } }; + await AssertFormatAsync(""" + using System; - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/772311")] - public async Task TestTab() - { - var code = @" -using System; + class Program + { + static void Main(string[] args) + { + Console.WriteLine(""); // GooBar + } + } + """, """ + using System; -class Program -{ - /// - /// This function is the callback used to execute a command when a menu item is clicked. - /// See the Initialize method to see how the menu item is associated to this function using - /// the OleMenuCommandService service and the MenuCommand class. - /// - private void MenuItemCallback(object sender, EventArgs e) { - // Show a Message Box to prove we were here - IVsUIShell uiShell = (IVsUIShell)GetService(typeof(SVsUIShell)); - Guid clsid = Guid.Empty; - int result; - Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(uiShell.ShowMessageBox( - 0, - ref clsid, - Rebracer, - string.Format(CultureInfo.CurrentCulture, Inside {0}.MenuItemCallback(), this.ToString()), - string.Empty, - 0, - OLEMSGBUTTON.OLEMSGBUTTON_OK, - OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST, - OLEMSGICON.OLEMSGICON_INFO, - 0, // false - out result)); - } + class Program + { + static void Main(string[] args) + { + Console.WriteLine(""); // GooBar + } + } + """, optionSet); } -"; - var expected = @" -using System; - -class Program -{ - /// - /// This function is the callback used to execute a command when a menu item is clicked. - /// See the Initialize method to see how the menu item is associated to this function using - /// the OleMenuCommandService service and the MenuCommand class. - /// - private void MenuItemCallback(object sender, EventArgs e) - { - // Show a Message Box to prove we were here - IVsUIShell uiShell = (IVsUIShell)GetService(typeof(SVsUIShell)); - Guid clsid = Guid.Empty; - int result; - Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(uiShell.ShowMessageBox( - 0, - ref clsid, - Rebracer, - string.Format(CultureInfo.CurrentCulture, Inside { 0}.MenuItemCallback(), this.ToString()), - string.Empty, - 0, - OLEMSGBUTTON.OLEMSGBUTTON_OK, - OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST, - OLEMSGICON.OLEMSGICON_INFO, - 0, // false - out result)); - } -} -"; - var optionSet = new OptionsCollection(LanguageNames.CSharp) { { FormattingOptions2.UseTabs, true } }; + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/1151")] + [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/961559")] + [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1041787")] + public async Task ReconstructWhitespaceStringUsingTabs_MultiLineComment() + { + var optionSet = new OptionsCollection(LanguageNames.CSharp) { { FormattingOptions2.UseTabs, true } }; + await AssertFormatAsync(""" + using System; - await AssertFormatAsync(expected, code, changedOptionSet: optionSet); - await AssertFormatAsync(expected, expected, changedOptionSet: optionSet); - } + class Program + { + static void Main(string[] args) + { + Console.WriteLine(""); /* GooBar */ + } + } + """, """ + using System; - [Fact] - public async Task LeaveBlockSingleLine_False() - { - var code = @" -namespace N { class C { int x; } }"; + class Program + { + static void Main(string[] args) + { + Console.WriteLine(""); /* GooBar */ + } + } + """, optionSet); + } - var expected = @" -namespace N -{ - class C + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1100920")] + public async Task NoLineOperationAroundInterpolationSyntax() { - int x; + await AssertFormatAsync(""" + class Program + { + static string F(int a, int b, int c) + { + return $"{a} (index: 0x{b}, size: {c}): " + } + } + """, """ + class Program + { + static string F(int a, int b, int c) + { + return $"{a} (index: 0x{ b}, size: { c}): " + } + } + """); } -}"; - - var options = new OptionsCollection(LanguageNames.CSharp) { { CSharpFormattingOptions2.WrappingPreserveSingleLine, false } }; - await AssertFormatAsync(expected, code, changedOptionSet: options); - } - - [Fact] - public async Task LeaveBlockSingleLine_False2() - { - var code = @" -class C { void goo() { } }"; - var expected = @" -class C -{ - void goo() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/62")] + public async Task SpaceAfterWhenInExceptionFilter() { - } -}"; + const string expected = """ + class C + { + void M() + { + try + { + if (x) + { + G(); + } + } + catch (Exception e) when (H(e)) + { - var options = new OptionsCollection(LanguageNames.CSharp) { { CSharpFormattingOptions2.WrappingPreserveSingleLine, false } }; - await AssertFormatAsync(expected, code, changedOptionSet: options); - } + } + } + } + """; - [Fact] - public async Task LeaveStatementMethodDeclarationSameLine_False() - { - var code = @" -class Program -{ - void goo() - { - int x = 0; int y = 0; - } -}"; + const string code = """ + class C + { + void M() + { + try + { + if(x){ + G(); + } + } + catch(Exception e) when (H(e)) + { - var expected = @" -class Program -{ - void goo() - { - int x = 0; - int y = 0; + } + } + } + """; + await AssertFormatAsync(expected, code); } -}"; - - var options = new OptionsCollection(LanguageNames.CSharp) { { CSharpFormattingOptions2.WrappingKeepStatementsOnSingleLine, false } }; - await AssertFormatAsync(expected, code, changedOptionSet: options); - } - [Fact] - public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_0000() - { - var code = @" -class Program -{ - int[ ] x; - int[ , ] y; - int[ , , ] z = new int[1,2,3]; - var a = new[ ] { 0 }; -}"; - - var expected = @" -class Program -{ - int[] x; - int[,] y; - int[,,] z = new int[1,2,3]; - var a = new[] { 0 }; -}"; - - var options = new OptionsCollection(LanguageNames.CSharp) - { - { SpaceBetweenEmptySquareBrackets, false }, - { SpaceWithinSquareBrackets, false }, - { SpaceBeforeComma, false }, - { SpaceAfterComma, false }, - }; - await AssertFormatAsync(expected, code, changedOptionSet: options); - } + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1089196")] + [WorkItem("https://github.com/dotnet/roslyn/issues/285")] + public async Task FormatHashInBadDirectiveToZeroColumnAnywhereInsideIfDef() + { + const string code = """ + class MyClass + { + static void Main(string[] args) + { + #if false - [Fact] - public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_0001() - { - var code = @" -class Program -{ - int[ ] x; - int[ , ] y; - int[ , , ] z = new int[1,2,3]; - var a = new[ ] { 0 }; -}"; - - var expected = @" -class Program -{ - int[] x; - int[,] y; - int[,,] z = new int[1, 2, 3]; - var a = new[] { 0 }; -}"; - - var options = new OptionsCollection(LanguageNames.CSharp) - { - { SpaceBetweenEmptySquareBrackets, false }, - { SpaceWithinSquareBrackets, false }, - { SpaceBeforeComma, false }, - { SpaceAfterComma, true }, - }; - await AssertFormatAsync(expected, code, changedOptionSet: options); - } + # - [Fact] - public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_0010() - { - var code = @" -class Program -{ - int[ ] x; - int[ , ] y; - int[ , , ] z = new int[1,2,3]; - var a = new[ ] { 0 }; -}"; - - var expected = @" -class Program -{ - int[] x; - int[,] y; - int[,,] z = new int[1 ,2 ,3]; - var a = new[] { 0 }; -}"; - - var options = new OptionsCollection(LanguageNames.CSharp) - { - { SpaceBetweenEmptySquareBrackets, false }, - { SpaceWithinSquareBrackets, false }, - { SpaceBeforeComma, true }, - { SpaceAfterComma, false }, - }; - await AssertFormatAsync(expected, code, changedOptionSet: options); - } + #endif + } + } + """; - [Fact] - public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_0011() - { - var code = @" -class Program -{ - int[ ] x; - int[ , ] y; - int[ , , ] z = new int[1,2,3]; - var a = new[ ] { 0 }; -}"; - - var expected = @" -class Program -{ - int[] x; - int[,] y; - int[,,] z = new int[1 , 2 , 3]; - var a = new[] { 0 }; -}"; - - var options = new OptionsCollection(LanguageNames.CSharp) - { - { SpaceBetweenEmptySquareBrackets, false }, - { SpaceWithinSquareBrackets, false }, - { SpaceBeforeComma, true }, - { SpaceAfterComma, true }, - }; - await AssertFormatAsync(expected, code, changedOptionSet: options); - } + const string expected = """ + class MyClass + { + static void Main(string[] args) + { + #if false - [Fact] - public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_0100() - { - var code = @" -class Program -{ - int[ ] x; - int[, ] y; - int[, , ] z = new int[1,2,3]; - var a = new[ ] { 0 }; -}"; - - var expected = @" -class Program -{ - int[] x; - int[,] y; - int[,,] z = new int[ 1,2,3 ]; - var a = new[] { 0 }; -}"; - - var options = new OptionsCollection(LanguageNames.CSharp) - { - { SpaceBetweenEmptySquareBrackets, false }, - { SpaceWithinSquareBrackets, true }, - { SpaceBeforeComma, false }, - { SpaceAfterComma, false }, - }; - await AssertFormatAsync(expected, code, changedOptionSet: options); - } + # - [Fact] - public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_0101() - { - var code = @" -class Program -{ - int[ ] x; - int[, ] y; - int[, , ] z = new int[1,2,3]; - var a = new[ ] { 0 }; -}"; - - var expected = @" -class Program -{ - int[] x; - int[,] y; - int[,,] z = new int[ 1, 2, 3 ]; - var a = new[] { 0 }; -}"; - - var options = new OptionsCollection(LanguageNames.CSharp) - { - { SpaceBetweenEmptySquareBrackets, false }, - { SpaceWithinSquareBrackets, true }, - { SpaceBeforeComma, false }, - { SpaceAfterComma, true }, - }; - await AssertFormatAsync(expected, code, changedOptionSet: options); - } + #endif + } + } + """; + await AssertFormatAsync(expected, code); + } - [Fact] - public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_0110() - { - var code = @" -class Program -{ - int[ ] x; - int[, ] y; - int[, , ] z = new int[1,2,3]; - var a = new[ ] { 0 }; -}"; - - var expected = @" -class Program -{ - int[] x; - int[,] y; - int[,,] z = new int[ 1 ,2 ,3 ]; - var a = new[] { 0 }; -}"; - - var options = new OptionsCollection(LanguageNames.CSharp) - { - { SpaceBetweenEmptySquareBrackets, false }, - { SpaceWithinSquareBrackets, true }, - { SpaceBeforeComma, true }, - { SpaceAfterComma, false }, - }; - await AssertFormatAsync(expected, code, changedOptionSet: options); - } + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1089196")] + [WorkItem("https://github.com/dotnet/roslyn/issues/285")] + public async Task FormatHashElseToZeroColumnAnywhereInsideIfDef() + { + const string code = """ + class MyClass + { + static void Main(string[] args) + { + #if false - [Fact] - public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_0111() - { - var code = @" -class Program -{ - int[ ] x; - int[, ] y; - int[, , ] z = new int[1,2,3]; - var a = new[ ] { 0 }; -}"; - - var expected = @" -class Program -{ - int[] x; - int[,] y; - int[,,] z = new int[ 1 , 2 , 3 ]; - var a = new[] { 0 }; -}"; - - var options = new OptionsCollection(LanguageNames.CSharp) - { - { SpaceBetweenEmptySquareBrackets, false }, - { SpaceWithinSquareBrackets, true }, - { SpaceBeforeComma, true }, - { SpaceAfterComma, true }, - }; - await AssertFormatAsync(expected, code, changedOptionSet: options); - } + #else + Appropriate indentation should be here though # + #endif + } + } + """; - [Fact] - public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_1000() - { - var code = @" -class Program -{ - int[] x; - int[ ,] y; - int[ , ,] z = new int[1,2,3]; - var a = new[] { 0 }; -}"; - - var expected = @" -class Program -{ - int[ ] x; - int[ , ] y; - int[ , , ] z = new int[1,2,3]; - var a = new[ ] { 0 }; -}"; - - var options = new OptionsCollection(LanguageNames.CSharp) - { - { SpaceBetweenEmptySquareBrackets, true }, - { SpaceWithinSquareBrackets, false }, - { SpaceBeforeComma, false }, - { SpaceAfterComma, false }, - }; - await AssertFormatAsync(expected, code, changedOptionSet: options); - } + const string expected = """ + class MyClass + { + static void Main(string[] args) + { + #if false - [Fact] - public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_1001() - { - var code = @" -class Program -{ - int[] x; - int[ ,] y; - int[ , ,] z = new int[1,2,3]; - var a = new[] { 0 }; -}"; - - var expected = @" -class Program -{ - int[ ] x; - int[ , ] y; - int[ , , ] z = new int[1, 2, 3]; - var a = new[ ] { 0 }; -}"; - - var options = new OptionsCollection(LanguageNames.CSharp) - { - { SpaceBetweenEmptySquareBrackets, true }, - { SpaceWithinSquareBrackets, false }, - { SpaceBeforeComma, false }, - { SpaceAfterComma, true }, - }; - await AssertFormatAsync(expected, code, changedOptionSet: options); - } + #else + Appropriate indentation should be here though # + #endif + } + } + """; + await AssertFormatAsync(expected, code); + } - [Fact] - public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_1010() - { - var code = @" -class Program -{ - int[] x; - int[ ,] y; - int[ , ,] z = new int[1,2,3]; - var a = new[] { 0 }; -}"; - - var expected = @" -class Program -{ - int[ ] x; - int[ , ] y; - int[ , , ] z = new int[1 ,2 ,3]; - var a = new[ ] { 0 }; -}"; - - var options = new OptionsCollection(LanguageNames.CSharp) - { - { SpaceBetweenEmptySquareBrackets, true }, - { SpaceWithinSquareBrackets, false }, - { SpaceBeforeComma, true }, - { SpaceAfterComma, false }, - }; - await AssertFormatAsync(expected, code, changedOptionSet: options); - } + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1089196")] + [WorkItem("https://github.com/dotnet/roslyn/issues/285")] + public async Task FormatHashsToZeroColumnAnywhereInsideIfDef() + { + const string code = """ + class MyClass + { + static void Main(string[] args) + { + #if false - [Fact] - public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_1011() - { - var code = @" -class Program -{ - int[] x; - int[ ,] y; - int[ , ,] z = new int[1,2,3]; - var a = new[] { 0 }; -}"; - - var expected = @" -class Program -{ - int[ ] x; - int[ , ] y; - int[ , , ] z = new int[1 , 2 , 3]; - var a = new[ ] { 0 }; -}"; - - var options = new OptionsCollection(LanguageNames.CSharp) - { - { SpaceBetweenEmptySquareBrackets, true }, - { SpaceWithinSquareBrackets, false }, - { SpaceBeforeComma, true }, - { SpaceAfterComma, true }, - }; - await AssertFormatAsync(expected, code, changedOptionSet: options); - } + #else + # - [Fact] - public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_1100() - { - var code = @" -class Program -{ - int[ ] x; - int[ , ] y; - int[ , , ] z = new int[1,2,3]; - var a = new[ ] { 0 }; -}"; - - var expected = @" -class Program -{ - int[ ] x; - int[ , ] y; - int[ , , ] z = new int[ 1,2,3 ]; - var a = new[ ] { 0 }; -}"; - - var options = new OptionsCollection(LanguageNames.CSharp) - { - { SpaceBetweenEmptySquareBrackets, true }, - { SpaceWithinSquareBrackets, true }, - { SpaceBeforeComma, false }, - { SpaceAfterComma, false }, - }; - await AssertFormatAsync(expected, code, changedOptionSet: options); - } + #endif + } + } + """; - [Fact] - public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_1101() - { - var code = @" -class Program -{ - int[ ] x; - int[ , ] y; - int[ , , ] z = new int[1,2,3]; - var a = new[ ] { 0 }; -}"; - - var expected = @" -class Program -{ - int[ ] x; - int[ , ] y; - int[ , , ] z = new int[ 1, 2, 3 ]; - var a = new[ ] { 0 }; -}"; - - var options = new OptionsCollection(LanguageNames.CSharp) - { - { SpaceBetweenEmptySquareBrackets, true }, - { SpaceWithinSquareBrackets, true }, - { SpaceBeforeComma, false }, - { SpaceAfterComma, true }, - }; - await AssertFormatAsync(expected, code, changedOptionSet: options); - } + const string expected = """ + class MyClass + { + static void Main(string[] args) + { + #if false - [Fact] - public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_1110() - { - var code = @" -class Program -{ - int[ ] x; - int[ , ] y; - int[ , , ] z = new int[1,2,3]; - var a = new[ ] { 0 }; -}"; - - var expected = @" -class Program -{ - int[ ] x; - int[ , ] y; - int[ , , ] z = new int[ 1 ,2 ,3 ]; - var a = new[ ] { 0 }; -}"; - - var options = new OptionsCollection(LanguageNames.CSharp) - { - { SpaceBetweenEmptySquareBrackets, true }, - { SpaceWithinSquareBrackets, true }, - { SpaceBeforeComma, true }, - { SpaceAfterComma, false }, - }; - await AssertFormatAsync(expected, code, changedOptionSet: options); - } + #else + # - [Fact] - public async Task SpaceWithinEmptyBracketPrecedencesSpaceBeforeOrAfterComma_1111() - { - var code = @" -class Program -{ - int[ ] x; - int[ , ] y; - int[ , , ] z = new int[1,2,3]; - var a = new[ ] { 0 }; -}"; - - var expected = @" -class Program -{ - int[ ] x; - int[ , ] y; - int[ , , ] z = new int[ 1 , 2 , 3 ]; - var a = new[ ] { 0 }; -}"; - - var options = new OptionsCollection(LanguageNames.CSharp) - { - { SpaceBetweenEmptySquareBrackets, true }, - { SpaceWithinSquareBrackets, true }, - { SpaceBeforeComma, true }, - { SpaceAfterComma, true }, - }; - await AssertFormatAsync(expected, code, changedOptionSet: options); - } + #endif + } + } + """; + await AssertFormatAsync(expected, code); + } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14128")] - public async Task SpaceBeforeCommasInLocalFunctionParameters() - { - var code = @" -class Program -{ - void Goo() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/1118")] + public void DoNotAssumeCertainNodeAreAlwaysParented() { - void LocalFunction(int i, string s) - { - } + var block = SyntaxFactory.Block(); + Formatter.Format(block, new AdhocWorkspace().Services.SolutionServices, CSharpSyntaxFormattingOptions.Default, CancellationToken.None); } -}"; - var expected = @" -class Program -{ - void Goo() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/776")] + public async Task SpacingRulesAroundMethodCallAndParenthesisAppliedInAttributeNonDefault() { - void LocalFunction(int i , string s) + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - } + { CSharpFormattingOptions2.SpaceAfterMethodCallName, true }, + { CSharpFormattingOptions2.SpaceBetweenEmptyMethodCallParentheses, true }, + { CSharpFormattingOptions2.SpaceWithinMethodCallParentheses, true } + }; + await AssertFormatAsync(""" + [Obsolete ( "Test" ), Obsolete ( )] + class Program + { + static void Main(string[] args) + { + } + } + """, """ + [Obsolete("Test"), Obsolete()] + class Program + { + static void Main(string[] args) + { + } + } + """, changingOptions); } -}"; - var options = new OptionsCollection(LanguageNames.CSharp) + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/776")] + public async Task SpacingRulesAroundMethodCallAndParenthesisAppliedInAttribute() + { + var code = """ + [Obsolete("Test"), Obsolete()] + class Program { - { SpaceBeforeComma, true }, - }; - await AssertFormatAsync(expected, code, changedOptionSet: options); - } - - [Fact] - public async Task ArrayDeclarationShouldFollowEmptySquareBrackets() - { - const string code = @" -class Program -{ - var t = new Goo(new[ ] { ""a"", ""b"" }); -}"; + static void Main(string[] args) + { + } + } + """; + await AssertFormatAsync(code, code); + } - const string expected = @" -class Program -{ - var t = new Goo(new[] { ""a"", ""b"" }); -}"; + [Fact] + public async Task SpacingInMethodCallArguments_True() + { + const string code = """ - var options = new OptionsCollection(LanguageNames.CSharp) + [Bar(A=1,B=2)] + class Program { - { CSharpFormattingOptions2.SpaceWithinSquareBrackets, true }, - { CSharpFormattingOptions2.SpaceBetweenEmptySquareBrackets, false } - }; - await AssertFormatAsync(expected, code, changedOptionSet: options); - } + public void goo() + { + var a = typeof(A); + var b = M(a); + var c = default(A); + var d = sizeof(A); + M(); + } + } + """; + const string expected = """ - [Fact] - public async Task SquareBracesBefore_True() + [Bar ( A = 1, B = 2 )] + class Program + { + public void goo() + { + var a = typeof ( A ); + var b = M ( a ); + var c = default ( A ); + var d = sizeof ( A ); + M ( ); + } + } + """; + var optionSet = new OptionsCollection(LanguageNames.CSharp) { - var code = @" -class Program -{ - int[] x; -}"; + { CSharpFormattingOptions2.SpaceWithinMethodCallParentheses, true }, + { CSharpFormattingOptions2.SpaceAfterMethodCallName, true }, + { CSharpFormattingOptions2.SpaceBetweenEmptyMethodCallParentheses, true }, + }; + await AssertFormatAsync(expected, code, changedOptionSet: optionSet); + } - var expected = @" -class Program -{ - int [] x; -}"; + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/1298")] + public async Task DoNotforceAccessorsToNewLineWithPropertyInitializers() + { + var code = """ + using System.Collections.Generic; - var options = new OptionsCollection(LanguageNames.CSharp) { { CSharpFormattingOptions2.SpaceBeforeOpenSquareBracket, true } }; - await AssertFormatAsync(expected, code, changedOptionSet: options); - } + class Program + { + public List ValidationExcludeFilters { get; } + = new List(); + } - [Fact] - public async Task SquareBracesAndValue_True() - { - var code = @" -class Program -{ - int[3] x; -}"; + public class ExcludeValidation + { + } + """; - var expected = @" -class Program -{ - int[ 3 ] x; -}"; + var expected = """ + using System.Collections.Generic; - var options = new OptionsCollection(LanguageNames.CSharp) { { CSharpFormattingOptions2.SpaceWithinSquareBrackets, true } }; - await AssertFormatAsync(expected, code, changedOptionSet: options); - } + class Program + { + public List ValidationExcludeFilters { get; } + = new List(); + } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/917351")] - public async Task TestLockStatement() - { - var code = @" -class Program -{ - public void Method() - { - lock (expression) + public class ExcludeValidation { - // goo -} + } + """; + await AssertFormatAsync(expected, code); } -}"; - var expected = @" -class Program -{ - public void Method() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/1339")] + public async Task DoNotFormatAutoPropertyInitializerIfNotDifferentLine() { - lock (expression) { - // goo - } + var code = """ + class Program + { + public int d { get; } + = 3; + static void Main(string[] args) + { + } + } + """; + await AssertFormatAsync(code, code); } -}"; - var options = new OptionsCollection(LanguageNames.CSharp) - { - { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ControlBlocks, false) } - }; + [Fact] + public async Task SpacingForForStatementInfiniteLoop() + { + var code = """ - await AssertFormatAsync(expected, code, changedOptionSet: options); - } + class Program + { + void Main() + { + for ( ;;) + { + } + } + } + """; + var expected = """ - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/962416")] - public async Task TestCheckedAndUncheckedStatement() - { - var code = @" -class Program -{ - public void Method() - { - checked + class Program { - // goo -} - unchecked + void Main() + { + for (; ; ) { + } + } } + """; + await AssertFormatAsync(expected, code); } -}"; - var expected = @" -class Program -{ - public void Method() + [Fact] + public async Task SpacingForForStatementInfiniteLoopWithNoSpaces() { - checked { - // goo - } - unchecked { - } - } -}"; + var code = """ - var options = new OptionsCollection(LanguageNames.CSharp) + class Program { - { NewLineBeforeOpenBrace , NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ControlBlocks, false) } - }; - - await AssertFormatAsync(expected, code, changedOptionSet: options); - } + void Main() + { + for ( ; ; ) + { + } + } + } + """; + var expected = """ - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/953535")] - public async Task ConditionalMemberAccess() + class Program + { + void Main() + { + for (;;) + { + } + } + } + """; + var optionSet = new OptionsCollection(LanguageNames.CSharp) { - var code = @" -using System; -class A -{ - public A a; -} + { CSharpFormattingOptions2.SpaceAfterSemicolonsInForStatement, false }, + }; -class Program -{ - static void Main(string[] args) - { - A a = null; - A ?.a = null; - System.Console.WriteLine(args ?[0]); - System.Console.WriteLine(args ?.Length); + await AssertFormatAsync(expected, code, changedOptionSet: optionSet); } -}"; - - var expected = @" -using System; -class A -{ - public A a; -} -class Program -{ - static void Main(string[] args) + [Fact] + public async Task SpacingForForStatementInfiniteLoopWithSpacesBefore() { - A a = null; - A?.a = null; - System.Console.WriteLine(args?[0]); - System.Console.WriteLine(args?.Length); - } -}"; - var parseOptions = new CSharpParseOptions(); - await AssertFormatAsync(expected, code, parseOptions: parseOptions); - } + var code = """ - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/924172")] - public async Task IgnoreSpacesInDeclarationStatementEnabled() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) + class Program { - { CSharpFormattingOptions2.SpacesIgnoreAroundVariableDeclaration, true } - }; - var code = @" -class Program -{ - static void Main(string[] args) - { - int s; + void Main() + { + for (;; ) + { + } + } + } + """; + var expected = """ + + class Program + { + void Main() + { + for ( ; ;) + { + } + } + } + """; + var optionSet = new OptionsCollection(LanguageNames.CSharp) + { + { CSharpFormattingOptions2.SpaceBeforeSemicolonsInForStatement, true }, + { CSharpFormattingOptions2.SpaceAfterSemicolonsInForStatement, false }, + }; + + await AssertFormatAsync(expected, code, changedOptionSet: optionSet); } -}"; - var expected = @" -class Program -{ - static void Main(string[] args) + [Fact] + public async Task SpacingForForStatementInfiniteLoopWithSpacesBeforeAndAfter() { - int s; - } -}"; - await AssertFormatAsync(expected, code, changedOptionSet: changingOptions); - } + var code = """ + + class Program + { + void Main() + { + for (;;) + { + } + } + } + """; + var expected = """ - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/899492")] - public async Task CommentIsLeadingTriviaOfStatementNotLabel() + class Program + { + void Main() + { + for ( ; ; ) + { + } + } + } + """; + var optionSet = new OptionsCollection(LanguageNames.CSharp) { - var code = @" -class C -{ - void M() - { - label: - // comment - M(); - M(); - } -}"; + { CSharpFormattingOptions2.SpaceBeforeSemicolonsInForStatement, true }, + }; - var expected = @" -class C -{ - void M() - { - label: - // comment - M(); - M(); + await AssertFormatAsync(expected, code, changedOptionSet: optionSet); } -}"; - await AssertFormatAsync(expected, code); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/991547")] - public async Task DoNotWrappingTryCatchFinallyIfOnSingleLine() - { - var code = @" -class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/4240")] + [WorkItem("https://github.com/dotnet/roslyn/issues/4421")] + public async Task VerifySpacingAfterMethodDeclarationName_Default() { - try { } - catch { } - finally { } + var code = """ + class Program + { + public static Program operator + (Program p1, Program p2) { return null; } + public static implicit operator string (Program p) { return null; } + public static void M () { } + public void F () { } + } + """; + var expected = """ + class Program + { + public static Program operator +(Program p1, Program p2) { return null; } + public static implicit operator string(Program p) { return null; } + public static void M() { } + public void F() { } + } + """; + await AssertFormatAsync(expected, code); } -}"; - var expected = @" -class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/4421")] + [WorkItem("https://github.com/dotnet/roslyn/issues/4240")] + public async Task VerifySpacingAfterMethodDeclarationName_NonDefault() { - try { } - catch { } - finally { } + var changingOptions = new OptionsCollection(LanguageNames.CSharp) + { + { CSharpFormattingOptions2.SpacingAfterMethodDeclarationName, true } + }; + var code = """ + class Program + { + public static Program operator + (Program p1, Program p2) { return null; } + public static implicit operator string (Program p) { return null; } + public static void M () { } + public void F () { } + } + """; + var expected = """ + class Program + { + public static Program operator + (Program p1, Program p2) { return null; } + public static implicit operator string (Program p) { return null; } + public static void M () { } + public void F () { } + } + """; + await AssertFormatAsync(expected, code, changedOptionSet: changingOptions); } -}"; - await AssertFormatAsync(expected, code); - } - [Fact] - public async Task InterpolatedStrings1() - { - var code = @" -class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/939")] + public async Task DoNotFormatInsideArrayInitializers() { - var a = ""World""; - var b = $""Hello, {a}""; + var code = """ + class Program + { + static void Main(string[] args) + { + int[] sss = new[] { + //Comment1 + 2, + 5, 324534, 345345, + //Comment2 + //This comment should not line up with the previous comment + 234234 + //Comment3 + , 234, + 234234 + /* + This is a multiline comment + */ + //Comment4 + }; + } + } + """; + await AssertFormatAsync(code, code); } -}"; - var expected = @" -class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/4280")] + [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1184285")] + public async Task FormatDictionaryInitializers() { - var a = ""World""; - var b = $""Hello, {a}""; + var code = """ + class Program + { + void Main() + { + var sample = new Dictionary {["x"] = "d" ,["z"] = "XX" }; + } + } + """; + var expected = """ + class Program + { + void Main() + { + var sample = new Dictionary { ["x"] = "d", ["z"] = "XX" }; + } + } + """; + await AssertFormatAsync(expected, code); } -}"; - - await AssertFormatAsync(expected, code); - } - [Fact] - public async Task InterpolatedStrings2() - { - var code = @" -class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/3256")] + public async Task SwitchSectionHonorsNewLineForBracesinControlBlockOption_Default() { - var a = ""Hello""; - var b = ""World""; - var c = $""{a}, {b}""; + var code = """ + class Program + { + public void goo() + { + int f = 1; + switch (f) { + case 1: { + // DO nothing + break; + } + } + } + } + """; + var expected = """ + class Program + { + public void goo() + { + int f = 1; + switch (f) + { + case 1: + { + // DO nothing + break; + } + } + } + } + """; + await AssertFormatAsync(expected, code); } -}"; - var expected = @" -class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/3256")] + public async Task SwitchSectionHonorsNewLineForBracesinControlBlockOption_NonDefault() { - var a = ""Hello""; - var b = ""World""; - var c = $""{a}, {b}""; - } -}"; + var changingOptions = new OptionsCollection(LanguageNames.CSharp) + { + { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ControlBlocks, false) } + }; + var code = """ + class Program + { + public void goo() + { + int f = 1; + switch (f) + { + case 1: + { + // DO nothing + break; + } + } + } + } + """; - await AssertFormatAsync(expected, code); - } + var expected = """ + class Program + { + public void goo() + { + int f = 1; + switch (f) { + case 1: { + // DO nothing + break; + } + } + } + } + """; + await AssertFormatAsync(expected, code, changedOptionSet: changingOptions); + } - [Fact] - public async Task InterpolatedStrings3() - { - var code = @" -class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/4014")] + public async Task FormattingCodeWithMissingTokensShouldRespectFormatTabsOption1() { - var a = ""World""; - var b = $""Hello, { a }""; + var optionSet = new OptionsCollection(LanguageNames.CSharp) { { FormattingOptions2.UseTabs, true } }; + + await AssertFormatAsync(""" + class Program + { + static void Main() + { + return // Note the missing semicolon + } // The tab here should stay a tab + } + """, """ + class Program + { + static void Main() + { + return // Note the missing semicolon + } // The tab here should stay a tab + } + """, changedOptionSet: optionSet); } -}"; - var expected = @" -class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/4014")] + public async Task FormattingCodeWithMissingTokensShouldRespectFormatTabsOption2() { - var a = ""World""; - var b = $""Hello, {a}""; - } -}"; + var optionSet = new OptionsCollection(LanguageNames.CSharp) { { FormattingOptions2.UseTabs, true } }; - await AssertFormatAsync(expected, code); - } + await AssertFormatAsync(""" + struct Goo + { + private readonly string bar; - [Fact] - public async Task InterpolatedRawStrings3() - { - var code = @" -class C -{ - void M() - { - var a = ""World""; - var b = $""""""Hello, { a }""""""; + public Goo(readonly string bar) + { + } + } + """, """ + struct Goo + { + private readonly string bar; + + public Goo(readonly string bar) + { + } + } + """, changedOptionSet: optionSet); } -}"; - var expected = @" -class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/4014")] + public async Task FormattingCodeWithBrokenLocalDeclarationShouldRespectFormatTabsOption() { - var a = ""World""; - var b = $""""""Hello, {a}""""""; - } -}"; + var optionSet = new OptionsCollection(LanguageNames.CSharp) { { FormattingOptions2.UseTabs, true } }; - await AssertFormatAsync(expected, code); - } + await AssertFormatAsync(""" + class AClass + { + void AMethod(Object anArgument) + { + if (anArgument == null) + { + throw new ArgumentNullException(nameof(anArgument)); + } + anArgument + + DoSomething(); + } + + void DoSomething() + { + } + } + """, """ + class AClass + { + void AMethod(Object anArgument) + { + if (anArgument == null) + { + throw new ArgumentNullException(nameof(anArgument)); + }anArgument + + DoSomething(); + } + + void DoSomething() + { + } + } + """, changedOptionSet: optionSet); + } - [Fact] - public async Task InterpolatedStrings4() - { - var code = @" -class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/4014")] + public async Task FormattingCodeWithBrokenInterpolatedStringShouldRespectFormatTabsOption() { - var a = ""Hello""; - var b = ""World""; - var c = $""{ a }, { b }""; + var optionSet = new OptionsCollection(LanguageNames.CSharp) { { FormattingOptions2.UseTabs, true } }; + + await AssertFormatAsync(""" + class AClass + { + void Main() + { + Test($"\"_{\""); + Console.WriteLine(args); + } + } + """, """ + class AClass + { + void Main() + { + Test($"\"_{\""); + Console.WriteLine(args); + } + } + """, changedOptionSet: optionSet); } -}"; - var expected = @" -class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/84")] + [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/849870")] + public async Task NewLinesForBracesInPropertiesTest() { - var a = ""Hello""; - var b = ""World""; - var c = $""{a}, {b}""; - } -}"; + var changingOptions = new OptionsCollection(LanguageNames.CSharp) + { + { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.Properties, false) }, + }; + await AssertFormatAsync(""" + class Class2 + { + int Goo { + get + { + return 1; + } + } - await AssertFormatAsync(expected, code); - } + int MethodGoo() + { + return 42; + } + } + """, """ + class Class2 + { + int Goo + { + get + { + return 1; + } + } - [Fact] - public async Task InterpolatedStrings5() - { - var code = @" -class C -{ - void M() - { - var a = ""World""; - var b = $@""Hello, {a}""; + int MethodGoo() + { + return 42; + } + } + """, changingOptions); } -}"; - var expected = @" -class C -{ - void M() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/849870")] + [WorkItem("https://github.com/dotnet/roslyn/issues/84")] + public async Task NewLinesForBracesInAccessorsTest() { - var a = ""World""; - var b = $@""Hello, {a}""; - } -}"; + var changingOptions = new OptionsCollection(LanguageNames.CSharp) + { + { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.Accessors, false) }, + }; + await AssertFormatAsync(""" + class Class2 + { + int Goo + { + get { + return 1; + } + } - await AssertFormatAsync(expected, code); - } + int MethodGoo() + { + return 42; + } + } + """, """ + class Class2 + { + int Goo + { + get + { + return 1; + } + } - [Fact] - public async Task InterpolatedStrings6() - { - var code = @" -class C -{ - void M() - { - var a = ""Hello""; - var b = ""World""; - var c = $@""{a}, {b}""; + int MethodGoo() + { + return 42; + } + } + """, changingOptions); } -}"; - var expected = @" -class C -{ - void M() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/849870")] + [WorkItem("https://github.com/dotnet/roslyn/issues/84")] + public async Task NewLinesForBracesInPropertiesAndAccessorsTest() { - var a = ""Hello""; - var b = ""World""; - var c = $@""{a}, {b}""; - } -}"; + var changingOptions = new OptionsCollection(LanguageNames.CSharp) + { + { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue + .WithFlagValue(NewLineBeforeOpenBracePlacement.Properties, false) + .WithFlagValue(NewLineBeforeOpenBracePlacement.Accessors, false)}, + }; + await AssertFormatAsync(""" + class Class2 + { + int Goo { + get { + return 1; + } + } - await AssertFormatAsync(expected, code); - } + int MethodGoo() + { + return 42; + } + } + """, """ + class Class2 + { + int Goo + { + get + { + return 1; + } + } - [Fact] - public async Task InterpolatedStrings7() - { - var code = @" -class C -{ - void M() - { - var a = ""World""; - var b = $@""Hello, { a }""; + int MethodGoo() + { + return 42; + } + } + """, changingOptions); } -}"; - var expected = @" -class C -{ - void M() + [Fact, WorkItem(111079, "devdiv.visualstudio.com")] + public async Task TestThrowInIfOnSingleLine() { - var a = ""World""; - var b = $@""Hello, {a}""; - } -}"; + var code = """ - await AssertFormatAsync(expected, code); - } + class C + { + void M() + { + if (true) throw new Exception( + "message"); + } + } - [Fact] - public async Task InterpolatedStrings8() - { - var code = @" -class C -{ - void M() - { - var a = ""Hello""; - var b = ""World""; - var c = $@""{ a }, { b }""; - } -}"; + """; - var expected = @" -class C -{ - void M() - { - var a = ""Hello""; - var b = ""World""; - var c = $@""{a}, {b}""; + await AssertFormatAsync(code, code); } -}"; - - await AssertFormatAsync(expected, code); - } - [Fact] - public async Task InterpolatedStrings9() - { - var code = @" -class C -{ - void M() + [Fact, WorkItem("https://connect.microsoft.com/VisualStudio/feedback/details/1711675/autoformatting-issues")] + public async Task SingleLinePropertiesPreservedWithLeaveStatementsAndMembersOnSingleLineFalse() { - var a = ""Hello""; - var c = $""{ a }, World""; - } -}"; + var changedOptionSet = new OptionsCollection(LanguageNames.CSharp) + { + { CSharpFormattingOptions2.WrappingPreserveSingleLine, true }, + { CSharpFormattingOptions2.WrappingKeepStatementsOnSingleLine, false}, + }; - var expected = @" -class C -{ - void M() - { - var a = ""Hello""; - var c = $""{a}, World""; - } -}"; + await AssertFormatAsync(""" - await AssertFormatAsync(expected, code); - } + class C + { + string Name { get; set; } + } + """, """ - [Fact] - public async Task InterpolatedStrings10() - { - var code = @" -class C -{ - void M() - { - var s = $""{42 , -4 :x}""; + class C + { + string Name { get ; set ; } + } + """, changedOptionSet: changedOptionSet); } -}"; - var expected = @" -class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/4720")] + public async Task KeepAccessorWithAttributeOnSingleLine() { - var s = $""{42,-4:x}""; - } -}"; + await AssertFormatAsync(""" - await AssertFormatAsync(expected, code); - } + class Program + { + public Int32 PaymentMethodID + { + [System.Diagnostics.DebuggerStepThrough] + get { return 10; } + } + } + """, """ - [Fact] - public async Task InterpolatedRawStrings10() - { - var code = @" -class C -{ - void M() - { - var s = $""""""{42 , -4 :x}""""""; + class Program + { + public Int32 PaymentMethodID + { + [System.Diagnostics.DebuggerStepThrough] + get { return 10; } + } + } + """); } -}"; - var expected = @" -class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/6905")] + public async Task KeepConstructorBodyInSameLineAsBaseConstructorInitializer() { - var s = $""""""{42,-4:x}""""""; - } -}"; - - await AssertFormatAsync(expected, code); - } + var code = """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/59811")] - public async Task InterpolatedStrings11() - { - var code = @" -class C -{ - void M() - { - var hostAddress = ""host""; - var nasTypeId = ""nas""; - var version = ""1.2""; - var c = $""{ hostAddress?? """"}/{nasTypeId }/{version??""""}""; + class C + { + public C(int s) + : base() { } + public C() + { + } + } + """; + await AssertFormatAsync(code, code); } -}"; - var expected = @" -class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/6905")] + public async Task KeepConstructorBodyInSameLineAsThisConstructorInitializer() { - var hostAddress = ""host""; - var nasTypeId = ""nas""; - var version = ""1.2""; - var c = $""{hostAddress ?? """"}/{nasTypeId}/{version ?? """"}""; - } -}"; + var code = """ - await AssertFormatAsync(expected, code); - } - - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/59811")] - public async Task InterpolatedStrings12() - { - var code = @" -class C -{ - void M() - { - var a = 1.2M; - var c = $""{ a : 000.00 }""; + class C + { + public C(int s) + : this() { } + public C() + { + } + } + """; + await AssertFormatAsync(code, code); } -}"; - var expected = @" -class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/6905")] + public async Task KeepConstructorBodyInSameLineAsThisConstructorInitializerAdjustSpace() { - var a = 1.2M; - var c = $""{a: 000.00 }""; - } -}"; + await AssertFormatAsync(""" - await AssertFormatAsync(expected, code); - } + class C + { + public C(int s) + : this() { } + public C() + { + } + } + """, """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/59811")] - public async Task InterpolatedStrings13() - { - var code = @" -class C -{ - void M() - { - var a = 1.2M; - var c = $""{ (a > 2?""a"":""b""}""; + class C + { + public C(int s) + : this() { } + public C() + { + } + } + """); } -}"; - var expected = @" -class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/4720")] + public async Task OneSpaceBetweenAccessorsAndAttributes() { - var a = 1.2M; - var c = $""{(a > 2 ? ""a"" : ""b""}""; - } -}"; + await AssertFormatAsync(""" - await AssertFormatAsync(expected, code); - } + class Program + { + public int SomeProperty { [SomeAttribute] get; [SomeAttribute] private set; } + } + """, """ - [Fact] - public async Task InterpolatedStrings14() - { - var code = @" -class C -{ - void M() - { - var s = $""{ 42 , -4 :x}""; + class Program + { + public int SomeProperty { [SomeAttribute] get; [SomeAttribute] private set; } + } + """); } -}"; - var expected = @" -class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/7900")] + public async Task FormatEmbeddedStatementInsideLockStatement() { - var s = $""{42,-4:x}""; - } -}"; + await AssertFormatAsync(""" - await AssertFormatAsync(expected, code); - } + class C + { + private object _l = new object(); + public void M() + { + lock (_l) Console.WriteLine("d"); + } + } + """, """ - [Fact] - public async Task InterpolatedStrings15() - { - var code = @" -class C -{ - void M() - { - var s = $""{ 42 , -4 }""; + class C + { + private object _l = new object(); + public void M() + { + lock (_l) Console.WriteLine("d"); + } + } + """); } -}"; - var expected = @" -class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/7900")] + public async Task FormatEmbeddedStatementInsideLockStatementDifferentLine() { - var s = $""{42,-4}""; - } -}"; + await AssertFormatAsync(""" - await AssertFormatAsync(expected, code); - } + class C + { + private object _l = new object(); + public void M() + { + lock (_l) + Console.WriteLine("d"); + } + } + """, """ - [Fact] - public async Task InterpolatedStrings16() - { - var code = @" -class C -{ - void M() - { - var s = $""{ 42 , -4 : x }""; + class C + { + private object _l = new object(); + public void M() + { + lock (_l) + Console.WriteLine("d"); + } + } + """); } -}"; - var expected = @" -class C -{ - void M() + [Fact] + public async Task PropertyDeclarationSimple() { - var s = $""{42,-4: x }""; + var expected = @"if (o is Point p)"; + await AssertFormatBodyAsync(expected, expected); + await AssertFormatBodyAsync(expected, @"if (o is Point p)"); + await AssertFormatBodyAsync(expected, @"if (o is Point p )"); } -}"; - await AssertFormatAsync(expected, code); - } + [Fact] + public async Task PropertyDeclarationTypeOnNewLine() + { + var expected = """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/1151")] - [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1041787")] - public async Task ReconstructWhitespaceStringUsingTabs_SingleLineComment() - { - var optionSet = new OptionsCollection(LanguageNames.CSharp) { { FormattingOptions2.UseTabs, true } }; - await AssertFormatAsync(@"using System; + var y = o is + Point p; + """; + await AssertFormatBodyAsync(expected, expected); + await AssertFormatBodyAsync(expected, """ -class Program -{ - static void Main(string[] args) - { - Console.WriteLine(""""); // GooBar - } -}", @"using System; + var y = o is + Point p; + """); -class Program -{ - static void Main(string[] args) - { - Console.WriteLine(""""); // GooBar - } -}", optionSet); - } + await AssertFormatBodyAsync(expected, """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/1151")] - [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/961559")] - [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1041787")] - public async Task ReconstructWhitespaceStringUsingTabs_MultiLineComment() - { - var optionSet = new OptionsCollection(LanguageNames.CSharp) { { FormattingOptions2.UseTabs, true } }; - await AssertFormatAsync(@"using System; + var y = o is + Point p ; + """); -class Program -{ - static void Main(string[] args) - { - Console.WriteLine(""""); /* GooBar */ - } -}", @"using System; + await AssertFormatBodyAsync(expected, """ -class Program -{ - static void Main(string[] args) - { - Console.WriteLine(""""); /* GooBar */ + var y = o is + Point p ; + """); } -}", optionSet); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1100920")] - public async Task NoLineOperationAroundInterpolationSyntax() - { - await AssertFormatAsync(@"class Program -{ - static string F(int a, int b, int c) - { - return $""{a} (index: 0x{b}, size: {c}): "" - } -}", @"class Program -{ - static string F(int a, int b, int c) + [Fact] + public async Task CasePatternDeclarationSimple() { - return $""{a} (index: 0x{ b}, size: { c}): "" - } -}"); - } + var expected = """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/62")] - public async Task SpaceAfterWhenInExceptionFilter() - { - const string expected = @"class C -{ - void M() - { - try - { - if (x) + switch (o) { - G(); + case Point p: } - } - catch (Exception e) when (H(e)) - { + """; - } - } -}"; + await AssertFormatBodyAsync(expected, expected); + await AssertFormatBodyAsync(expected, """ - const string code = @"class C -{ - void M() - { - try - { - if(x){ - G(); + switch (o) + { + case Point p : } - } - catch(Exception e) when (H(e)) - { - - } - } -}"; - await AssertFormatAsync(expected, code); - } - - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1089196")] - [WorkItem("https://github.com/dotnet/roslyn/issues/285")] - public async Task FormatHashInBadDirectiveToZeroColumnAnywhereInsideIfDef() - { - const string code = @"class MyClass -{ - static void Main(string[] args) - { -#if false + """); - # + await AssertFormatBodyAsync(expected, """ -#endif + switch (o) + { + case Point p : + } + """); } -}"; - const string expected = @"class MyClass -{ - static void Main(string[] args) + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23703")] + public async Task FormatNullableArray() { -#if false + var code = """ -# - -#endif + class C + { + object[]? F = null; + } + """; + await AssertFormatAsync(code, code); } -}"; - await AssertFormatAsync(expected, code); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1089196")] - [WorkItem("https://github.com/dotnet/roslyn/issues/285")] - public async Task FormatHashElseToZeroColumnAnywhereInsideIfDef() - { - const string code = @"class MyClass -{ - static void Main(string[] args) + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23703")] + public async Task FormatConditionalWithArrayAccess() { -#if false + var code = """ - #else - Appropriate indentation should be here though # -#endif + class C + { + void M() + { + _ = array[1] ? 2 : 3; + } + } + """; + await AssertFormatAsync(code, code); } -}"; - const string expected = @"class MyClass -{ - static void Main(string[] args) + private Task AssertFormatBodyAsync(string expected, string input) { -#if false + static string transform(string s) + { + var lines = s.Split([Environment.NewLine], StringSplitOptions.None); + for (var i = 0; i < lines.Length; i++) + { + if (!string.IsNullOrEmpty(lines[i])) + { + lines[i] = new string(' ', count: 8) + lines[i]; + } + } -#else - Appropriate indentation should be here though # -#endif - } -}"; - await AssertFormatAsync(expected, code); + return string.Join(Environment.NewLine, lines); } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1089196")] - [WorkItem("https://github.com/dotnet/roslyn/issues/285")] - public async Task FormatHashsToZeroColumnAnywhereInsideIfDef() - { - const string code = @"class MyClass -{ - static void Main(string[] args) - { -#if false + var pattern = """ - #else - # + class C + {{ + void M() + {{ + {0} + }} + }} + """; -#endif + expected = string.Format(pattern, transform(expected)); + input = string.Format(pattern, transform(input)); + return AssertFormatAsync(expected, input); } -}"; - const string expected = @"class MyClass -{ - static void Main(string[] args) + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/6628")] + public async Task FormatElseBlockBracesOnDifferentLineToNewLines() { -#if false - -#else -# + await AssertFormatAsync(""" -#endif - } -}"; - await AssertFormatAsync(expected, code); - } - - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/1118")] - public void DoNotAssumeCertainNodeAreAlwaysParented() - { - var block = SyntaxFactory.Block(); - Formatter.Format(block, new AdhocWorkspace().Services.SolutionServices, CSharpSyntaxFormattingOptions.Default, CancellationToken.None); - } + class C + { + public void M() + { + if (true) + { + } + else + { + } + } + } + """, """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/776")] - public async Task SpacingRulesAroundMethodCallAndParenthesisAppliedInAttributeNonDefault() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) + class C { - { CSharpFormattingOptions2.SpaceAfterMethodCallName, true }, - { CSharpFormattingOptions2.SpaceBetweenEmptyMethodCallParentheses, true }, - { CSharpFormattingOptions2.SpaceWithinMethodCallParentheses, true } - }; - await AssertFormatAsync(@"[Obsolete ( ""Test"" ), Obsolete ( )] -class Program -{ - static void Main(string[] args) - { - } -}", @"[Obsolete(""Test""), Obsolete()] -class Program -{ - static void Main(string[] args) - { + public void M() + { + if (true) + { + } + else { + } + } + } + """); } -}", changingOptions); - } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/776")] - public async Task SpacingRulesAroundMethodCallAndParenthesisAppliedInAttribute() - { - var code = @"[Obsolete(""Test""), Obsolete()] -class Program -{ - static void Main(string[] args) + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/6628")] + public async Task FormatOnElseBlockBracesOnSameLineRemainsInSameLine_1() { + var code = """ + + class C + { + public void M() + { + if (true) + { + } + else { } + } + } + """; + await AssertFormatAsync(code, code); } -}"; - await AssertFormatAsync(code, code); - } - [Fact] - public async Task SpacingInMethodCallArguments_True() - { - const string code = @" -[Bar(A=1,B=2)] -class Program -{ - public void goo() - { - var a = typeof(A); - var b = M(a); - var c = default(A); - var d = sizeof(A); - M(); - } -}"; - const string expected = @" -[Bar ( A = 1, B = 2 )] -class Program -{ - public void goo() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/11572")] + public async Task FormatAttributeOnSameLineAsField() { - var a = typeof ( A ); - var b = M ( a ); - var c = default ( A ); - var d = sizeof ( A ); - M ( ); - } -}"; - var optionSet = new OptionsCollection(LanguageNames.CSharp) + await AssertFormatAsync( + """ + + class C { - { CSharpFormattingOptions2.SpaceWithinMethodCallParentheses, true }, - { CSharpFormattingOptions2.SpaceAfterMethodCallName, true }, - { CSharpFormattingOptions2.SpaceBetweenEmptyMethodCallParentheses, true }, - }; - await AssertFormatAsync(expected, code, changedOptionSet: optionSet); - } + [Attr] int i; + } + """, + """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/1298")] - public async Task DoNotforceAccessorsToNewLineWithPropertyInitializers() - { - var code = @"using System.Collections.Generic; + class C { + [Attr] int i; + } + """); + } -class Program -{ - public List ValidationExcludeFilters { get; } - = new List(); -} + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/21789")] + public async Task FormatMultipleAttributeOnSameLineAsField1() + { + await AssertFormatAsync( + """ -public class ExcludeValidation -{ -}"; + class C + { + [Attr1] + [Attr2] + [Attr3][Attr4] int i; + } + """, + """ - var expected = @"using System.Collections.Generic; + class C { + [Attr1] + [Attr2] + [Attr3][Attr4] int i; + } + """); + } -class Program -{ - public List ValidationExcludeFilters { get; } - = new List(); -} + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/21789")] + public async Task FormatMultipleAttributesOnSameLineAsField2() + { + await AssertFormatAsync( + """ -public class ExcludeValidation -{ -}"; - await AssertFormatAsync(expected, code); - } + class C + { + [Attr1] + [Attr2] + [Attr3][Attr4] int i; + } + """, + """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/1339")] - public async Task DoNotFormatAutoPropertyInitializerIfNotDifferentLine() - { - var code = @"class Program -{ - public int d { get; } - = 3; - static void Main(string[] args) - { + class C { + [Attr1][Attr2] + [Attr3][Attr4] int i; + } + """); } -}"; - await AssertFormatAsync(code, code); - } - [Fact] - public async Task SpacingForForStatementInfiniteLoop() - { - var code = @" -class Program -{ - void Main() - { - for ( ;;) - { - } - } -}"; - var expected = @" -class Program -{ - void Main() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/21789")] + public async Task FormatMultipleAttributeOnSameLineAndFieldOnNewLine() { - for (; ; ) - { - } + await AssertFormatAsync( + """ + + class C + { + [Attr1] + [Attr2] + int i; + } + """, + """ + + class C { + [Attr1][Attr2] + int i; + } + """); } -}"; - await AssertFormatAsync(expected, code); - } - [Fact] - public async Task SpacingForForStatementInfiniteLoopWithNoSpaces() - { - var code = @" -class Program -{ - void Main() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/6628")] + public async Task FormatOnElseBlockBracesOnSameLineRemainsInSameLine_2() { - for ( ; ; ) - { - } + var code = """ + + class C + { + public void M() + { + if (true) + { + } + else + { } + } + } + """; + await AssertFormatAsync(code, code); } -}"; - var expected = @" -class Program -{ - void Main() + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/25098")] + public void FormatSingleStructDeclaration() + => Formatter.Format(SyntaxFactory.StructDeclaration("S"), DefaultWorkspace.Services.SolutionServices, CSharpSyntaxFormattingOptions.Default, CancellationToken.None); + + [Fact] + public async Task FormatIndexExpression() { - for (;;) - { - } - } -}"; - var optionSet = new OptionsCollection(LanguageNames.CSharp) + await AssertFormatAsync(""" + + class C { - { CSharpFormattingOptions2.SpaceAfterSemicolonsInForStatement, false }, - }; + void M() + { + object x = ^1; + object y = ^1 + } + } + """, """ - await AssertFormatAsync(expected, code, changedOptionSet: optionSet); - } + class C + { + void M() + { + object x = ^1; + object y = ^1 + } + } + """); + } - [Fact] - public async Task SpacingForForStatementInfiniteLoopWithSpacesBefore() - { - var code = @" -class Program -{ - void Main() + [Fact] + public async Task FormatRangeExpression_NoOperands() { - for (;; ) - { - } + await AssertFormatAsync(""" + + class C + { + void M() + { + object x = ..; + object y = .. + } + } + """, """ + + class C + { + void M() + { + object x = ..; + object y = .. + } + } + """); } -}"; - var expected = @" -class Program -{ - void Main() + + [Fact] + public async Task FormatRangeExpression_RightOperand() { - for ( ; ;) - { - } - } -}"; - var optionSet = new OptionsCollection(LanguageNames.CSharp) + await AssertFormatAsync(""" + + class C { - { CSharpFormattingOptions2.SpaceBeforeSemicolonsInForStatement, true }, - { CSharpFormattingOptions2.SpaceAfterSemicolonsInForStatement, false }, - }; + void M() + { + object x = ..1; + object y = ..1 + } + } + """, """ - await AssertFormatAsync(expected, code, changedOptionSet: optionSet); - } + class C + { + void M() + { + object x = ..1; + object y = ..1 + } + } + """); + } - [Fact] - public async Task SpacingForForStatementInfiniteLoopWithSpacesBeforeAndAfter() - { - var code = @" -class Program -{ - void Main() + [Fact] + public async Task FormatRangeExpression_LeftOperand() { - for (;;) - { - } + await AssertFormatAsync(""" + + class C + { + void M() + { + object x = 1..; + object y = 1.. + } + } + """, """ + + class C + { + void M() + { + object x = 1..; + object y = 1.. + } + } + """); } -}"; - var expected = @" -class Program -{ - void Main() + + [Fact] + public async Task FormatRangeExpression_BothOperands() { - for ( ; ; ) - { - } - } -}"; - var optionSet = new OptionsCollection(LanguageNames.CSharp) + await AssertFormatAsync(""" + + class C { - { CSharpFormattingOptions2.SpaceBeforeSemicolonsInForStatement, true }, - }; + void M() + { + object x = 1..2; + object y = 1..2 + } + } + """, """ - await AssertFormatAsync(expected, code, changedOptionSet: optionSet); - } + class C + { + void M() + { + object x = 1..2; + object y = 1..2 + } + } + """); + } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/4240")] - [WorkItem("https://github.com/dotnet/roslyn/issues/4421")] - public async Task VerifySpacingAfterMethodDeclarationName_Default() - { - var code = @"class Program -{ - public static Program operator + (Program p1, Program p2) { return null; } - public static implicit operator string (Program p) { return null; } - public static void M () { } - public void F () { } -}"; - var expected = @"class Program -{ - public static Program operator +(Program p1, Program p2) { return null; } - public static implicit operator string(Program p) { return null; } - public static void M() { } - public void F() { } -}"; - await AssertFormatAsync(expected, code); - } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/32113")] + public async Task FormatCommaAfterCloseBrace_CommaRemainIntheSameLine() + { + await AssertFormatAsync( + """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/4421")] - [WorkItem("https://github.com/dotnet/roslyn/issues/4240")] - public async Task VerifySpacingAfterMethodDeclarationName_NonDefault() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) + public class Test { - { CSharpFormattingOptions2.SpacingAfterMethodDeclarationName, true } - }; - var code = @"class Program -{ - public static Program operator + (Program p1, Program p2) { return null; } - public static implicit operator string (Program p) { return null; } - public static void M () { } - public void F () { } -}"; - var expected = @"class Program -{ - public static Program operator + (Program p1, Program p2) { return null; } - public static implicit operator string (Program p) { return null; } - public static void M () { } - public void F () { } -}"; - await AssertFormatAsync(expected, code, changedOptionSet: changingOptions); - } + public void Foo() + { + (Action, Action, Action) tuple = ( + () => { Console.WriteLine(2.997e8); }, + () => { Console.WriteLine(6.67e-11); }, + () => { Console.WriteLine(1.602e-19); } + ); + } + } + """, + """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/939")] - public async Task DoNotFormatInsideArrayInitializers() - { - var code = @"class Program -{ - static void Main(string[] args) - { - int[] sss = new[] { - //Comment1 - 2, - 5, 324534, 345345, - //Comment2 - //This comment should not line up with the previous comment - 234234 - //Comment3 - , 234, - 234234 - /* - This is a multiline comment - */ - //Comment4 - }; - } -}"; - await AssertFormatAsync(code, code); - } + public class Test + { + public void Foo() + { + (Action, Action, Action) tuple = ( + () => { Console.WriteLine(2.997e8); }, + () => { Console.WriteLine(6.67e-11); }, + () => { Console.WriteLine(1.602e-19); } + ); + } + } + """); + } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/4280")] - [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1184285")] - public async Task FormatDictionaryInitializers() - { - var code = @"class Program -{ - void Main() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/32113")] + public async Task FormatCommaAfterCloseBrace_SpaceSurroundWillBeRemoved() { - var sample = new Dictionary {[""x""] = ""d"" ,[""z""] = ""XX"" }; + await AssertFormatAsync( + """ + + public class Test + { + public void Foo() + { + (Action, Action, Action) tuple = ( + () => { Console.WriteLine(2.997e8); }, + () => { Console.WriteLine(6.67e-11); }, + () => { Console.WriteLine(1.602e-19); } + ); + } + } + """, + """ + + public class Test + { + public void Foo() + { + (Action, Action, Action) tuple = ( + () => { Console.WriteLine(2.997e8); } , + () => { Console.WriteLine(6.67e-11); } , + () => { Console.WriteLine(1.602e-19); } + ); + } + } + """); } -}"; - var expected = @"class Program -{ - void Main() + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/31571")] + [WorkItem("https://github.com/dotnet/roslyn/issues/33910")] + [CombinatorialData] + public async Task ConversionOperator_CorrectlySpaceArgumentList( + [CombinatorialValues("implicit", "explicit")] string operatorType, + [CombinatorialValues("string", "string[]", "System.Action", "int?", "int*", "(int, int)")] string targetType, + bool spacingAfterMethodDeclarationName) { - var sample = new Dictionary { [""x""] = ""d"", [""z""] = ""XX"" }; + var expectedSpacing = spacingAfterMethodDeclarationName ? " " : ""; + var initialSpacing = spacingAfterMethodDeclarationName ? "" : " "; + var changedOptionSet = new OptionsCollection(LanguageNames.CSharp) { { SpacingAfterMethodDeclarationName, spacingAfterMethodDeclarationName } }; + await AssertFormatAsync( + $$""" + + public unsafe class Test + { + public static {{operatorType}} operator {{targetType}}{{expectedSpacing}}() => throw null; + } + """, + $$""" + + public unsafe class Test + { + public static {{operatorType}} operator {{targetType}}{{initialSpacing}}() => throw null; + } + """, + changedOptionSet: changedOptionSet); } -}"; - await AssertFormatAsync(expected, code); - } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/3256")] - public async Task SwitchSectionHonorsNewLineForBracesinControlBlockOption_Default() - { - var code = @"class Program -{ - public void goo() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/31868")] + public async Task SpaceAroundDeclaration() { - int f = 1; - switch (f) { - case 1: { - // DO nothing - break; + var changingOptions = new OptionsCollection(LanguageNames.CSharp) + { + { CSharpFormattingOptions2.SpacesIgnoreAroundVariableDeclaration, true } + }; + await AssertFormatAsync( + """ + + class Program + { + public void FixMyType() + { + var myint = 0; } - } + } + """, + """ + + class Program + { + public void FixMyType() + { + var myint = 0; + } + } + """, changedOptionSet: changingOptions); } -}"; - var expected = @"class Program -{ - public void goo() + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/31868")] + public async Task SpaceAroundDeclarationAndPreserveSingleLine() { - int f = 1; - switch (f) + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - case 1: + { CSharpFormattingOptions2.SpacesIgnoreAroundVariableDeclaration, true }, + { CSharpFormattingOptions2.WrappingKeepStatementsOnSingleLine, false } + }; + await AssertFormatAsync( + """ + + class Program + { + public void FixMyType() { - // DO nothing - break; + var myint = 0; } - } - } -}"; - await AssertFormatAsync(expected, code); - } + } + """, + """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/3256")] - public async Task SwitchSectionHonorsNewLineForBracesinControlBlockOption_NonDefault() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) + class Program { - { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ControlBlocks, false) } - }; - var code = @"class Program -{ - public void goo() - { - int f = 1; - switch (f) - { - case 1: + public void FixMyType() { - // DO nothing - break; + var myint = 0; } - } + } + """, changedOptionSet: changingOptions); } -}"; - var expected = @"class Program -{ - public void goo() + [Fact] + public async Task ClassConstraint() { - int f = 1; - switch (f) { - case 1: { - // DO nothing - break; - } - } - } -}"; - await AssertFormatAsync(expected, code, changedOptionSet: changingOptions); - } + await AssertFormatAsync( + """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/4014")] - public async Task FormattingCodeWithMissingTokensShouldRespectFormatTabsOption1() - { - var optionSet = new OptionsCollection(LanguageNames.CSharp) { { FormattingOptions2.UseTabs, true } }; + class Program + where T : class? + { + } + """, + """ - await AssertFormatAsync(@"class Program -{ - static void Main() - { - return // Note the missing semicolon - } // The tab here should stay a tab -}", @"class Program -{ - static void Main() - { - return // Note the missing semicolon - } // The tab here should stay a tab -}", changedOptionSet: optionSet); - } + class Program + where T : class ? + { + } + """); + } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/4014")] - public async Task FormattingCodeWithMissingTokensShouldRespectFormatTabsOption2() - { - var optionSet = new OptionsCollection(LanguageNames.CSharp) { { FormattingOptions2.UseTabs, true } }; + [Fact] + public async Task SingleLinePropertyPattern1() + { + await AssertFormatAsync( + """ - await AssertFormatAsync(@"struct Goo -{ - private readonly string bar; + using System.Collections.Generic; + class Program + { + public void FixMyType() + { + _ = new List() is + { + Count: { }, + }; + } + } + """, + """ - public Goo(readonly string bar) - { - } -}", @"struct Goo -{ - private readonly string bar; + using System.Collections.Generic; + class Program + { + public void FixMyType() + { + _ = new List() is + { + Count:{}, + }; + } + } + """); + } - public Goo(readonly string bar) - { - } -}", changedOptionSet: optionSet); - } + [Fact] + public async Task SingleLinePropertyPattern2() + { + await AssertFormatAsync( + """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/4014")] - public async Task FormattingCodeWithBrokenLocalDeclarationShouldRespectFormatTabsOption() - { - var optionSet = new OptionsCollection(LanguageNames.CSharp) { { FormattingOptions2.UseTabs, true } }; + using System.Collections.Generic; + class Program + { + public void FixMyType(object o) + { + _ = o is List { Count: { } }; + } + } + """, + """ - await AssertFormatAsync(@"class AClass -{ - void AMethod(Object anArgument) - { - if (anArgument == null) - { - throw new ArgumentNullException(nameof(anArgument)); - } - anArgument - - DoSomething(); - } - - void DoSomething() - { - } -}", @"class AClass -{ - void AMethod(Object anArgument) - { - if (anArgument == null) - { - throw new ArgumentNullException(nameof(anArgument)); - }anArgument - - DoSomething(); - } - - void DoSomething() - { - } -}", changedOptionSet: optionSet); - } + using System.Collections.Generic; + class Program + { + public void FixMyType(object o) + { + _ = o is List{Count:{}}; + } + } + """); + } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/4014")] - public async Task FormattingCodeWithBrokenInterpolatedStringShouldRespectFormatTabsOption() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37030")] + public async Task SpaceAroundEnumMemberDeclarationIgnored() + { + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - var optionSet = new OptionsCollection(LanguageNames.CSharp) { { FormattingOptions2.UseTabs, true } }; + { CSharpFormattingOptions2.SpacesIgnoreAroundVariableDeclaration, true } + }; + await AssertFormatAsync( + """ - await AssertFormatAsync(@"class AClass -{ - void Main() - { - Test($""\""_{\""""); - Console.WriteLine(args); - } -}", @"class AClass -{ - void Main() - { - Test($""\""_{\""""); - Console.WriteLine(args); - } -}", changedOptionSet: optionSet); - } + enum TestEnum + { + Short = 1, + LongItemName = 2 + } + """, + """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/84")] - [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/849870")] - public async Task NewLinesForBracesInPropertiesTest() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) + enum TestEnum { - { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.Properties, false) }, - }; - await AssertFormatAsync(@"class Class2 -{ - int Goo { - get - { - return 1; - } + Short = 1, + LongItemName = 2 + } + """, changedOptionSet: changingOptions); } - int MethodGoo() - { - return 42; - } -}", @"class Class2 -{ - int Goo + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37030")] + public async Task SpaceAroundEnumMemberDeclarationSingle() { - get + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - return 1; - } - } + { CSharpFormattingOptions2.SpacesIgnoreAroundVariableDeclaration, false } + }; + await AssertFormatAsync( + """ - int MethodGoo() - { - return 42; - } -}", changingOptions); - } + enum TestEnum + { + Short = 1, + LongItemName = 2 + } + """, + """ - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/849870")] - [WorkItem("https://github.com/dotnet/roslyn/issues/84")] - public async Task NewLinesForBracesInAccessorsTest() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) + enum TestEnum { - { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.Accessors, false) }, - }; - await AssertFormatAsync(@"class Class2 -{ - int Goo - { - get { - return 1; - } + Short = 1, + LongItemName = 2 + } + """, changedOptionSet: changingOptions); } - int MethodGoo() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38895")] + public async Task FormattingNbsp() { - return 42; + await AssertFormatAsync( + """ + + class C + { + List list = new List + { + new C() + }; + } + """, + """ + + class C + { + List list = new List + { +             new C() + }; + } + """.Replace(" ", "\u00A0")); } -}", @"class Class2 -{ - int Goo + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/47438")] + public async Task IndentationForMultilineWith() { - get - { - return 1; - } + var code = """ + record C(int X) + { + C M() + { + return this with + { + X = 1 + }; + } + } + """; + var expectedCode = """ + record C(int X) + { + C M() + { + return this with + { + X = 1 + }; + } + } + """; + + await AssertFormatAsync(expectedCode, code); } - int MethodGoo() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/47438")] + public async Task IndentationForMultilineWith_ArrowBody() { - return 42; + var code = """ + record C(int X) + { + C M() + => this with + { + X = 1 + }; + } + """; + var expectedCode = """ + record C(int X) + { + C M() + => this with + { + X = 1 + }; + } + """; + + await AssertFormatAsync(expectedCode, code); } -}", changingOptions); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/849870")] - [WorkItem("https://github.com/dotnet/roslyn/issues/84")] - public async Task NewLinesForBracesInPropertiesAndAccessorsTest() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/47438")] + public async Task IndentationForMultilineWith_ArrowBody_WithTrailingComma() + { + var code = """ + record C(int X) { - { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue - .WithFlagValue(NewLineBeforeOpenBracePlacement.Properties, false) - .WithFlagValue(NewLineBeforeOpenBracePlacement.Accessors, false)}, + C M() + => this with + { + X = 1, }; - await AssertFormatAsync(@"class Class2 -{ - int Goo { - get { - return 1; - } + } + """; + var expectedCode = """ + record C(int X) + { + C M() + => this with + { + X = 1, + }; + } + """; + + await AssertFormatAsync(expectedCode, code); } - int MethodGoo() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41022")] + public async Task SpacingAfterAttribute() { - return 42; + var code = """ + class C + { + void M([My]string?[]?[] x) + { + } + } + """; + var expectedCode = """ + class C + { + void M([My] string?[]?[] x) + { + } + } + """; + + await AssertFormatAsync(expectedCode, code); } -}", @"class Class2 -{ - int Goo + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41022")] + public async Task SpacingAfterAttribute_Multiple() { - get - { - return 1; - } + var code = """ + class C + { + void M([My][My] int x) + { + } + } + """; + var expectedCode = """ + class C + { + void M([My][My] int x) + { + } + } + """; + + await AssertFormatAsync(expectedCode, code); } - int MethodGoo() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41022")] + public async Task SpacingAfterAttribute_Multiple2() { - return 42; + var code = """ + class C + { + void M([My] [My] int x) + { + } + } + """; + var expectedCode = """ + class C + { + void M([My][My] int x) + { + } + } + """; + + await AssertFormatAsync(expectedCode, code); } -}", changingOptions); - } - [Fact, WorkItem(111079, "devdiv.visualstudio.com")] - public async Task TestThrowInIfOnSingleLine() - { - var code = @" -class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41022")] + public async Task SpacingAfterAttribute_MultipleOnDeclaration() { - if (true) throw new Exception( - ""message""); + var code = """ + class C + { + [My] [My] void M() + { + } + } + """; + var expectedCode = """ + class C + { + [My] + [My] + void M() + { + } + } + """; + + await AssertFormatAsync(expectedCode, code); } -} -"; - await AssertFormatAsync(code, code); - } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/47442")] + public async Task IndentImplicitObjectCreationInitializer() + { + var code = """ - [Fact, WorkItem("https://connect.microsoft.com/VisualStudio/feedback/details/1711675/autoformatting-issues")] - public async Task SingleLinePropertiesPreservedWithLeaveStatementsAndMembersOnSingleLineFalse() - { - var changedOptionSet = new OptionsCollection(LanguageNames.CSharp) + class C { - { CSharpFormattingOptions2.WrappingPreserveSingleLine, true }, - { CSharpFormattingOptions2.WrappingKeepStatementsOnSingleLine, false}, - }; + public string Name { get; set; } + public static C Create1(string name) + => new C() + { + Name = name + }; + public static C Create2(string name) + => new() + { + Name = name + }; + } + """; + var expectedCode = """ - await AssertFormatAsync(@" -class C -{ - string Name { get; set; } -}", @" -class C -{ - string Name { get ; set ; } -}", changedOptionSet: changedOptionSet); - } + class C + { + public string Name { get; set; } + public static C Create1(string name) + => new C() + { + Name = name + }; + public static C Create2(string name) + => new() + { + Name = name + }; + } + """; - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/4720")] - public async Task KeepAccessorWithAttributeOnSingleLine() - { - await AssertFormatAsync(@" -class Program -{ - public Int32 PaymentMethodID - { - [System.Diagnostics.DebuggerStepThrough] - get { return 10; } - } -}", @" -class Program -{ - public Int32 PaymentMethodID - { - [System.Diagnostics.DebuggerStepThrough] - get { return 10; } + await AssertFormatAsync(expectedCode, code); } -}"); - } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/6905")] - public async Task KeepConstructorBodyInSameLineAsBaseConstructorInitializer() - { - var code = @" -class C -{ - public C(int s) - : base() { } - public C() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36913")] + public async Task NewLinesForBraces_SwitchExpression_Default() { - } -}"; - await AssertFormatAsync(code, code); - } + await AssertFormatAsync( + """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/6905")] - public async Task KeepConstructorBodyInSameLineAsThisConstructorInitializer() - { - var code = @" -class C -{ - public C(int s) - : this() { } - public C() - { - } -}"; - await AssertFormatAsync(code, code); - } + class A + { + void br() + { + var msg = 1 switch + { + _ => null + }; + } + } + """, + """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/6905")] - public async Task KeepConstructorBodyInSameLineAsThisConstructorInitializerAdjustSpace() - { - await AssertFormatAsync(@" -class C -{ - public C(int s) - : this() { } - public C() - { - } -}", @" -class C -{ - public C(int s) - : this() { } - public C() - { + class A + { + void br() + { + var msg = 1 switch { + _ => null + }; + } + } + """); } -}"); - } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/4720")] - public async Task OneSpaceBetweenAccessorsAndAttributes() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36913")] + public async Task NewLinesForBraces_SwitchExpression_NonDefault() + { + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - await AssertFormatAsync(@" -class Program -{ - public int SomeProperty { [SomeAttribute] get; [SomeAttribute] private set; } -}", @" -class Program -{ - public int SomeProperty { [SomeAttribute] get; [SomeAttribute] private set; } -}"); - } + { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers, false) }, + }; + await AssertFormatAsync( + """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/7900")] - public async Task FormatEmbeddedStatementInsideLockStatement() - { - await AssertFormatAsync(@" -class C -{ - private object _l = new object(); - public void M() - { - lock (_l) Console.WriteLine(""d""); - } -}", @" -class C -{ - private object _l = new object(); - public void M() - { - lock (_l) Console.WriteLine(""d""); - } -}"); - } + class A + { + void br() + { + var msg = 1 switch { + _ => null + }; + } + } + """, + """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/7900")] - public async Task FormatEmbeddedStatementInsideLockStatementDifferentLine() - { - await AssertFormatAsync(@" -class C -{ - private object _l = new object(); - public void M() - { - lock (_l) - Console.WriteLine(""d""); + class A + { + void br() + { + var msg = 1 switch + { + _ => null + }; + } + } + """, changedOptionSet: changingOptions); } -}", @" -class C -{ - private object _l = new object(); - public void M() + + [Fact, WorkItem("https://github.com/dotnet/roslyn/discussions/49725")] + public async Task NewLinesForBraces_RecordWithInitializer_Default() { - lock (_l) - Console.WriteLine(""d""); - } -}"); - } + await AssertFormatAsync( + """ - [Fact] - public async Task PropertyDeclarationSimple() - { - var expected = @"if (o is Point p)"; - await AssertFormatBodyAsync(expected, expected); - await AssertFormatBodyAsync(expected, @"if (o is Point p)"); - await AssertFormatBodyAsync(expected, @"if (o is Point p )"); - } + record R(int X); + class C + { + void Goo(R r) + { + var r2 = r with + { + X = 0 + }; + } + } + """, + """ - [Fact] - public async Task PropertyDeclarationTypeOnNewLine() - { - var expected = @" -var y = o is -Point p;"; - await AssertFormatBodyAsync(expected, expected); - await AssertFormatBodyAsync(expected, @" -var y = o is -Point p; "); - - await AssertFormatBodyAsync(expected, @" -var y = o is -Point p ;"); - - await AssertFormatBodyAsync(expected, @" -var y = o is -Point p ;"); - } + record R(int X); + class C + { + void Goo(R r) + { + var r2 = r with { + X = 0 + }; + } + } + """); + } - [Fact] - public async Task CasePatternDeclarationSimple() + [Fact, WorkItem("https://github.com/dotnet/roslyn/discussions/49725")] + public async Task NewLinesForBraces_RecordWithInitializer_NonDefault() + { + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - var expected = @" -switch (o) -{ - case Point p: -}"; + { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers, false) }, + }; + await AssertFormatAsync( + """ - await AssertFormatBodyAsync(expected, expected); - await AssertFormatBodyAsync(expected, @" -switch (o) -{ - case Point p : -}"); + record R(int X); + class C + { + void Goo(R r) + { + var r2 = r with { + X = 0 + }; + } + } + """, + """ - await AssertFormatBodyAsync(expected, @" -switch (o) -{ - case Point p : -}"); - } + record R(int X); + class C + { + void Goo(R r) + { + var r2 = r with + { + X = 0 + }; + } + } + """, changedOptionSet: changingOptions); + } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23703")] - public async Task FormatNullableArray() - { - var code = @" -class C -{ - object[]? F = null; -}"; - await AssertFormatAsync(code, code); - } + [Fact] + public async Task NoSpacesInPropertyPatterns() + { + var code = """ + class C + { + int IntProperty { get; set; } + void M() + { + _ = this is { IntProperty : 2 }; + } + } + """; + var expectedCode = """ + class C + { + int IntProperty { get; set; } + void M() + { + _ = this is { IntProperty: 2 }; + } + } + """; + await AssertFormatAsync(expectedCode, code); + } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23703")] - public async Task FormatConditionalWithArrayAccess() - { - var code = @" -class C -{ - void M() + [Fact] + public async Task NoSpacesInExtendedPropertyPatterns() { - _ = array[1] ? 2 : 3; + var code = """ + class C + { + C CProperty { get; set; } + int IntProperty { get; set; } + void M() + { + _ = this is { CProperty . IntProperty : 2 }; + } + } + """; + var expectedCode = """ + class C + { + C CProperty { get; set; } + int IntProperty { get; set; } + void M() + { + _ = this is { CProperty.IntProperty: 2 }; + } + } + """; + await AssertFormatAsync(expectedCode, code); } -}"; - await AssertFormatAsync(code, code); - } - private Task AssertFormatBodyAsync(string expected, string input) - { - static string transform(string s) + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/52413")] + public async Task NewLinesForBraces_PropertyPatternClauses_Default() + { + await AssertFormatAsync( + """ + + class A { - var lines = s.Split([Environment.NewLine], StringSplitOptions.None); - for (var i = 0; i < lines.Length; i++) + public string Name { get; } + + public bool IsFoo(A a) { - if (!string.IsNullOrEmpty(lines[i])) + return a is { - lines[i] = new string(' ', count: 8) + lines[i]; - } + Name: "foo", + }; } - - return string.Join(Environment.NewLine, lines); } + """, + """ - var pattern = @" -class C -{{ - void M() - {{ -{0} - }} -}}"; - - expected = string.Format(pattern, transform(expected)); - input = string.Format(pattern, transform(input)); - return AssertFormatAsync(expected, input); - } + class A + { + public string Name { get; } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/6628")] - public async Task FormatElseBlockBracesOnDifferentLineToNewLines() - { - await AssertFormatAsync(@" -class C -{ - public void M() - { - if (true) - { - } - else - { - } + public bool IsFoo(A a) + { + return a is { + Name: "foo", + }; + } + } + """); } -}", @" -class C -{ - public void M() + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/52413")] + public async Task NewLinesForBraces_PropertyPatternClauses_NonDefault() { - if (true) + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - } - else { - } + { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers, false) }, + }; + await AssertFormatAsync( + """ + + class A + { + public string Name { get; } + + public bool IsFoo(A a) + { + return a is { + Name: "foo", + }; + } + } + """, + """ + + class A + { + public string Name { get; } + + public bool IsFoo(A a) + { + return a is + { + Name: "foo", + }; + } + } + """, changedOptionSet: changingOptions); } -}"); - } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/6628")] - public async Task FormatOnElseBlockBracesOnSameLineRemainsInSameLine_1() - { - var code = @" -class C -{ - public void M() + [Fact, Trait(Traits.Feature, Traits.Features.Formatting)] + [WorkItem(57854, "https://github.com/dotnet/roslyn/issues/57854")] + public async Task NewLinesForBraces_PropertyPatternClauses_NonDefaultInSwitchExpression() { - if (true) + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - } - else { } - } -}"; - await AssertFormatAsync(code, code); - } + { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers, false) }, + }; + await AssertFormatAsync( + """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/11572")] - public async Task FormatAttributeOnSameLineAsField() - { - await AssertFormatAsync( -@" -class C -{ - [Attr] int i; -}", -@" -class C { - [Attr] int i; -}"); - } + class A + { + public string Name { get; } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/21789")] - public async Task FormatMultipleAttributeOnSameLineAsField1() - { - await AssertFormatAsync( -@" -class C -{ - [Attr1] - [Attr2] - [Attr3][Attr4] int i; -}", -@" -class C { - [Attr1] - [Attr2] - [Attr3][Attr4] int i; -}"); - } + public bool IsFoo(A a) + { + return a switch { + { Name: "foo" } => true, + _ => false, + }; + } + } + """, + """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/21789")] - public async Task FormatMultipleAttributesOnSameLineAsField2() - { - await AssertFormatAsync( -@" -class C -{ - [Attr1] - [Attr2] - [Attr3][Attr4] int i; -}", -@" -class C { - [Attr1][Attr2] - [Attr3][Attr4] int i; -}"); - } + class A + { + public string Name { get; } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/21789")] - public async Task FormatMultipleAttributeOnSameLineAndFieldOnNewLine() - { - await AssertFormatAsync( -@" -class C -{ - [Attr1] - [Attr2] - int i; -}", -@" -class C { - [Attr1][Attr2] - int i; -}"); - } + public bool IsFoo(A a) + { + return a switch + { + { Name: "foo" } => true, + _ => false, + }; + } + } + """, changedOptionSet: changingOptions); + } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/6628")] - public async Task FormatOnElseBlockBracesOnSameLineRemainsInSameLine_2() - { - var code = @" -class C -{ - public void M() + [Theory, CombinatorialData] + [WorkItem("https://github.com/dotnet/roslyn/issues/52413")] + public async Task NewLinesForBraces_PropertyPatternClauses_SingleLine(bool option) { - if (true) + var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - } - else - { } - } -}"; - await AssertFormatAsync(code, code); - } + { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers, option) }, + }; + var code = """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/25098")] - public void FormatSingleStructDeclaration() - => Formatter.Format(SyntaxFactory.StructDeclaration("S"), DefaultWorkspace.Services.SolutionServices, CSharpSyntaxFormattingOptions.Default, CancellationToken.None); + class A + { + public string Name { get; } - [Fact] - public async Task FormatIndexExpression() - { - await AssertFormatAsync(@" -class C -{ - void M() - { - object x = ^1; - object y = ^1 - } -}", @" -class C -{ - void M() - { - object x = ^1; - object y = ^1 + public bool IsFoo(A a) + { + return a is { Name: "foo" }; + } + } + """; + await AssertFormatAsync(code, code, changedOptionSet: changingOptions); } -}"); - } - [Fact] - public async Task FormatRangeExpression_NoOperands() - { - await AssertFormatAsync(@" -class C -{ - void M() - { - object x = ..; - object y = .. - } -}", @" -class C -{ - void M() + [Fact] + public async Task RecordClass() { - object x = ..; - object y = .. - } -}"); - } + await AssertFormatAsync( + """ - [Fact] - public async Task FormatRangeExpression_RightOperand() - { - await AssertFormatAsync(@" -class C -{ - void M() - { - object x = ..1; - object y = ..1 - } -}", @" -class C -{ - void M() - { - object x = ..1; - object y = ..1 - } -}"); - } + record class R(int X); - [Fact] - public async Task FormatRangeExpression_LeftOperand() - { - await AssertFormatAsync(@" -class C -{ - void M() - { - object x = 1..; - object y = 1.. - } -}", @" -class C -{ - void M() - { - object x = 1..; - object y = 1.. - } -}"); - } + """, + """ - [Fact] - public async Task FormatRangeExpression_BothOperands() - { - await AssertFormatAsync(@" -class C -{ - void M() - { - object x = 1..2; - object y = 1..2 - } -}", @" -class C -{ - void M() - { - object x = 1..2; - object y = 1..2 + record class R(int X); + + """); } -}"); - } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/32113")] - public async Task FormatCommaAfterCloseBrace_CommaRemainIntheSameLine() - { - await AssertFormatAsync( - @" -public class Test -{ - public void Foo() + [Fact] + public async Task Class() { - (Action, Action, Action) tuple = ( - () => { Console.WriteLine(2.997e8); }, - () => { Console.WriteLine(6.67e-11); }, - () => { Console.WriteLine(1.602e-19); } - ); + await AssertFormatAsync( + """ + + class R(int X); + + """, + """ + + class R(int X) ; + + """); } -}", - @" -public class Test -{ - public void Foo() + + [Fact] + public async Task Interface() { - (Action, Action, Action) tuple = ( - () => { Console.WriteLine(2.997e8); }, - () => { Console.WriteLine(6.67e-11); }, - () => { Console.WriteLine(1.602e-19); } - ); + await AssertFormatAsync( + """ + + interface R(int X); + + """, + """ + + interface R(int X) ; + + """); } -}"); - } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/32113")] - public async Task FormatCommaAfterCloseBrace_SpaceSurroundWillBeRemoved() - { - await AssertFormatAsync( - @" -public class Test -{ - public void Foo() + [Fact] + public async Task RecordStruct() { - (Action, Action, Action) tuple = ( - () => { Console.WriteLine(2.997e8); }, - () => { Console.WriteLine(6.67e-11); }, - () => { Console.WriteLine(1.602e-19); } - ); + await AssertFormatAsync( + """ + + record struct R(int X); + + """, + """ + + record struct R(int X); + + """); } -}", - @" -public class Test -{ - public void Foo() + + [Fact] + public async Task Struct() { - (Action, Action, Action) tuple = ( - () => { Console.WriteLine(2.997e8); } , - () => { Console.WriteLine(6.67e-11); } , - () => { Console.WriteLine(1.602e-19); } - ); - } -}"); - } + await AssertFormatAsync( + """ - [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/31571")] - [WorkItem("https://github.com/dotnet/roslyn/issues/33910")] - [CombinatorialData] - public async Task ConversionOperator_CorrectlySpaceArgumentList( - [CombinatorialValues("implicit", "explicit")] string operatorType, - [CombinatorialValues("string", "string[]", "System.Action", "int?", "int*", "(int, int)")] string targetType, - bool spacingAfterMethodDeclarationName) - { - var expectedSpacing = spacingAfterMethodDeclarationName ? " " : ""; - var initialSpacing = spacingAfterMethodDeclarationName ? "" : " "; - var changedOptionSet = new OptionsCollection(LanguageNames.CSharp) { { SpacingAfterMethodDeclarationName, spacingAfterMethodDeclarationName } }; - await AssertFormatAsync( - $@" -public unsafe class Test -{{ - public static {operatorType} operator {targetType}{expectedSpacing}() => throw null; -}}", - $@" -public unsafe class Test -{{ - public static {operatorType} operator {targetType}{initialSpacing}() => throw null; -}}", - changedOptionSet: changedOptionSet); - } + struct R(int X); - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/31868")] - public async Task SpaceAroundDeclaration() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) - { - { CSharpFormattingOptions2.SpacesIgnoreAroundVariableDeclaration, true } - }; - await AssertFormatAsync( - @" -class Program -{ - public void FixMyType() - { - var myint = 0; + """, + """ + + struct R(int X) ; + + """); } -}", - @" -class Program -{ - public void FixMyType() + + [Fact] + public async Task FormatListPattern() { - var myint = 0; - } -}", changedOptionSet: changingOptions); - } + var code = """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/31868")] - public async Task SpaceAroundDeclarationAndPreserveSingleLine() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) + class C { - { CSharpFormattingOptions2.SpacesIgnoreAroundVariableDeclaration, true }, - { CSharpFormattingOptions2.WrappingKeepStatementsOnSingleLine, false } - }; - await AssertFormatAsync( - @" -class Program -{ - public void FixMyType() - { - var myint = 0; - } -}", - @" -class Program -{ - public void FixMyType() - { - var myint = 0; - } -}", changedOptionSet: changingOptions); - } + void M() { + _ = this is[1,2,>=3]; + } + } + """; + await AssertFormatAsync(code: code, expected: """ - [Fact] - public async Task ClassConstraint() - { - await AssertFormatAsync( - @" -class Program - where T : class? -{ -}", - @" -class Program - where T : class ? -{ -}"); - } + class C + { + void M() + { + _ = this is [1, 2, >= 3]; + } + } + """); - [Fact] - public async Task SingleLinePropertyPattern1() - { - await AssertFormatAsync( - @" -using System.Collections.Generic; -class Program -{ - public void FixMyType() - { - _ = new List() is - { - Count: { }, - }; - } -}", - @" -using System.Collections.Generic; -class Program -{ - public void FixMyType() - { - _ = new List() is + var options = new OptionsCollection(LanguageNames.CSharp) { - Count:{}, + { SpaceBetweenEmptySquareBrackets, false }, + { SpaceWithinSquareBrackets, false }, + { SpaceBeforeComma, false }, + { SpaceAfterComma, false }, }; - } -}"); - } - [Fact] - public async Task SingleLinePropertyPattern2() - { - await AssertFormatAsync( - @" -using System.Collections.Generic; -class Program -{ - public void FixMyType(object o) - { - _ = o is List { Count: { } }; - } -}", - @" -using System.Collections.Generic; -class Program -{ - public void FixMyType(object o) - { - _ = o is List{Count:{}}; - } -}"); - } + await AssertFormatAsync(code: code, changedOptionSet: options, expected: """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37030")] - public async Task SpaceAroundEnumMemberDeclarationIgnored() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) + class C { - { CSharpFormattingOptions2.SpacesIgnoreAroundVariableDeclaration, true } - }; - await AssertFormatAsync( - @" -enum TestEnum -{ - Short = 1, - LongItemName = 2 -}", - @" -enum TestEnum -{ - Short = 1, - LongItemName = 2 -}", changedOptionSet: changingOptions); - } + void M() + { + _ = this is [1,2,>= 3]; + } + } + """); - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37030")] - public async Task SpaceAroundEnumMemberDeclarationSingle() + options = new OptionsCollection(LanguageNames.CSharp) { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) - { - { CSharpFormattingOptions2.SpacesIgnoreAroundVariableDeclaration, false } - }; - await AssertFormatAsync( - @" -enum TestEnum -{ - Short = 1, - LongItemName = 2 -}", - @" -enum TestEnum -{ - Short = 1, - LongItemName = 2 -}", changedOptionSet: changingOptions); - } + { SpaceBeforeOpenSquareBracket, false }, // ignored + { SpaceBetweenEmptySquareBrackets, true }, + { SpaceWithinSquareBrackets, true }, + { SpaceBeforeComma, true }, + { SpaceAfterComma, true }, + }; - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38895")] - public async Task FormattingNbsp() - { - await AssertFormatAsync( - @" -class C -{ - List list = new List - { -new C() - }; -}", - @" -class C -{ - List list = new List - { -            new C() - }; -}".Replace(" ", "\u00A0")); - } + await AssertFormatAsync(code: code, changedOptionSet: options, expected: """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/47438")] - public async Task IndentationForMultilineWith() - { - var code = @"record C(int X) -{ - C M() - { - return this with -{ -X = 1 -}; + class C + { + void M() + { + _ = this is [ 1 , 2 , >= 3 ]; + } + } + """); } -}"; - var expectedCode = @"record C(int X) -{ - C M() + + [Fact] + public async Task FormatListPattern_Parentheses() { - return this with - { - X = 1 - }; - } -}"; + var code = """ - await AssertFormatAsync(expectedCode, code); - } + class C + { + void M((int[], int[]) a) { + _ = a is([1,2,>=3],[1,2]); + } + } + """; + await AssertFormatAsync(code: code, expected: """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/47438")] - public async Task IndentationForMultilineWith_ArrowBody() - { - var code = @"record C(int X) -{ - C M() - => this with -{ -X = 1 -}; -}"; - var expectedCode = @"record C(int X) -{ - C M() - => this with + class C + { + void M((int[], int[]) a) + { + _ = a is ([1, 2, >= 3], [1, 2]); + } + } + """); + + var options = new OptionsCollection(LanguageNames.CSharp) { - X = 1 + { SpaceBetweenEmptySquareBrackets, false }, + { SpaceWithinSquareBrackets, false }, + { SpaceBeforeComma, false }, + { SpaceAfterComma, false }, }; -}"; - await AssertFormatAsync(expectedCode, code); - } + await AssertFormatAsync(code: code, changedOptionSet: options, expected: """ + + class C + { + void M((int[], int[]) a) + { + _ = a is ([1,2,>= 3],[1,2]); + } + } + """); - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/47438")] - public async Task IndentationForMultilineWith_ArrowBody_WithTrailingComma() - { - var code = @"record C(int X) -{ - C M() - => this with -{ -X = 1, -}; -}"; - var expectedCode = @"record C(int X) -{ - C M() - => this with + options = new OptionsCollection(LanguageNames.CSharp) { - X = 1, + { SpaceBeforeOpenSquareBracket, false }, // ignored + { SpaceBetweenEmptySquareBrackets, true }, + { SpaceWithinSquareBrackets, true }, + { SpaceBeforeComma, true }, + { SpaceAfterComma, true }, }; -}"; - await AssertFormatAsync(expectedCode, code); - } + await AssertFormatAsync(code: code, changedOptionSet: options, expected: """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41022")] - public async Task SpacingAfterAttribute() - { - var code = @"class C -{ - void M([My]string?[]?[] x) - { + class C + { + void M((int[ ], int[ ]) a) + { + _ = a is ([ 1 , 2 , >= 3 ], [ 1 , 2 ]); + } + } + """); } -}"; - var expectedCode = @"class C -{ - void M([My] string?[]?[] x) + + [Fact] + public async Task FormatListPattern_TrailingComma() { - } -}"; + var code = """ - await AssertFormatAsync(expectedCode, code); - } + class C + { + void M() { + _ = this is[1,2,>=3,]; + } + } + """; + await AssertFormatAsync(code: code, expected: """ + + class C + { + void M() + { + _ = this is [1, 2, >= 3,]; + } + } + """); - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41022")] - public async Task SpacingAfterAttribute_Multiple() + var options = new OptionsCollection(LanguageNames.CSharp) { - var code = @"class C -{ - void M([My][My] int x) - { - } -}"; - var expectedCode = @"class C -{ - void M([My][My] int x) - { - } -}"; + { SpaceBetweenEmptySquareBrackets, false }, + { SpaceWithinSquareBrackets, false }, + { SpaceBeforeComma, false }, + { SpaceAfterComma, false }, + }; - await AssertFormatAsync(expectedCode, code); - } + await AssertFormatAsync(code: code, changedOptionSet: options, expected: """ + + class C + { + void M() + { + _ = this is [1,2,>= 3,]; + } + } + """); - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41022")] - public async Task SpacingAfterAttribute_Multiple2() + options = new OptionsCollection(LanguageNames.CSharp) { - var code = @"class C -{ - void M([My] [My] int x) - { - } -}"; - var expectedCode = @"class C -{ - void M([My][My] int x) - { - } -}"; + { SpaceBeforeOpenSquareBracket, false }, // ignored + { SpaceBetweenEmptySquareBrackets, true }, + { SpaceWithinSquareBrackets, true }, + { SpaceBeforeComma, true }, + { SpaceAfterComma, true }, + }; - await AssertFormatAsync(expectedCode, code); - } + await AssertFormatAsync(code: code, changedOptionSet: options, expected: """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41022")] - public async Task SpacingAfterAttribute_MultipleOnDeclaration() - { - var code = @"class C -{ - [My] [My] void M() - { + class C + { + void M() + { + _ = this is [ 1 , 2 , >= 3 , ]; + } + } + """); } -}"; - var expectedCode = @"class C -{ - [My] - [My] - void M() + + [Fact] + public async Task FormatListPattern_WithNewline() { - } -}"; + var code = """ - await AssertFormatAsync(expectedCode, code); - } + class C + { + void M() { + _ = this is + [1,2,>=3 + ]; + } + } + """; + await AssertFormatAsync(code: code, expected: """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/47442")] - public async Task IndentImplicitObjectCreationInitializer() - { - var code = @" -class C -{ - public string Name { get; set; } - public static C Create1(string name) - => new C() - { - Name = name - }; - public static C Create2(string name) - => new() - { - Name = name - }; -}"; - var expectedCode = @" -class C -{ - public string Name { get; set; } - public static C Create1(string name) - => new C() - { - Name = name - }; - public static C Create2(string name) - => new() + class C + { + void M() + { + _ = this is + [1, 2, >= 3 + ]; + } + } + """); + + var options = new OptionsCollection(LanguageNames.CSharp) { - Name = name + { SpaceBetweenEmptySquareBrackets, false }, + { SpaceWithinSquareBrackets, false }, + { SpaceBeforeComma, false }, + { SpaceAfterComma, false }, }; -}"; - await AssertFormatAsync(expectedCode, code); - } + await AssertFormatAsync(code: code, changedOptionSet: options, expected: """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36913")] - public async Task NewLinesForBraces_SwitchExpression_Default() - { - await AssertFormatAsync( - @" -class A -{ - void br() - { - var msg = 1 switch + class C + { + void M() + { + _ = this is + [1,2,>= 3 + ]; + } + } + """); + + options = new OptionsCollection(LanguageNames.CSharp) { - _ => null - }; - } -}", - @" -class A -{ - void br() - { - var msg = 1 switch { - _ => null + { SpaceBeforeOpenSquareBracket, false }, // ignored + { SpaceBetweenEmptySquareBrackets, true }, + { SpaceWithinSquareBrackets, true }, + { SpaceBeforeComma, true }, + { SpaceAfterComma, true }, }; - } -}"); - } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36913")] - public async Task NewLinesForBraces_SwitchExpression_NonDefault() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) + await AssertFormatAsync(code: code, changedOptionSet: options, expected: """ + + class C { - { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers, false) }, - }; - await AssertFormatAsync( - @" -class A -{ - void br() - { - var msg = 1 switch { - _ => null - }; + void M() + { + _ = this is + [ 1 , 2 , >= 3 + ]; + } + } + """); } -}", - @" -class A -{ - void br() + + [Fact] + public async Task FormatSlicePattern() { - var msg = 1 switch - { - _ => null - }; + var code = """ + class C + { + void M() { + _ = this is[ 0,.. var rest ]; + } + } + """; + var expectedCode = """ + class C + { + void M() + { + _ = this is [0, .. var rest]; + } + } + """; + await AssertFormatAsync(expectedCode, code); } -}", changedOptionSet: changingOptions); - } - [Fact, WorkItem("https://github.com/dotnet/roslyn/discussions/49725")] - public async Task NewLinesForBraces_RecordWithInitializer_Default() - { - await AssertFormatAsync( - @" -record R(int X); -class C -{ - void Goo(R r) + [Fact] + public async Task FormatSlicePattern_NoSpace() { - var r2 = r with - { - X = 0 - }; + var code = """ + class C + { + void M() { + _ = this is[ 0,..var rest ]; + } + } + """; + var expectedCode = """ + class C + { + void M() + { + _ = this is [0, .. var rest]; + } + } + """; + await AssertFormatAsync(expectedCode, code); } -}", - @" -record R(int X); -class C -{ - void Goo(R r) + + [Fact] + public async Task FormatSlicePatternWithAnd() { - var r2 = r with { - X = 0 - }; + var code = """ + class C + { + void M() { + _ = this is[ 0,.. {Count: >0} and var rest ]; + } + } + """; + var expectedCode = """ + class C + { + void M() + { + _ = this is [0, .. { Count: > 0 } and var rest]; + } + } + """; + await AssertFormatAsync(expectedCode, code); } -}"); - } - [Fact, WorkItem("https://github.com/dotnet/roslyn/discussions/49725")] - public async Task NewLinesForBraces_RecordWithInitializer_NonDefault() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) - { - { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers, false) }, - }; - await AssertFormatAsync( - @" -record R(int X); -class C -{ - void Goo(R r) + [Fact] + public async Task FormatLengthAndListPattern() { - var r2 = r with { - X = 0 - }; + var code = """ + class C + { + void M() { + _ = this is{Count:>0 and var x}and[ 1,2,3 ]; + } + } + """; + var expectedCode = """ + class C + { + void M() + { + _ = this is { Count: > 0 and var x } and [1, 2, 3]; + } + } + """; + await AssertFormatAsync(expectedCode, code); } -}", - @" -record R(int X); -class C -{ - void Goo(R r) + + [Fact] + public async Task LambdaReturnType_01() { - var r2 = r with - { - X = 0 - }; + await AssertFormatAsync( + """ + class Program + { + Delegate D = void () => { }; + } + """, + """ + class Program + { + Delegate D = void () => { }; + } + """); } -}", changedOptionSet: changingOptions); - } - [Fact] - public async Task NoSpacesInPropertyPatterns() - { - var code = @"class C -{ - int IntProperty { get; set; } - void M() + [Fact] + public async Task LambdaReturnType_02() { - _ = this is { IntProperty : 2 }; + await AssertFormatAsync( + """ + class Program + { + Delegate D = A.B () => { }; + } + """, + """ + class Program + { + Delegate D = A.B()=>{ }; + } + """); } -}"; - var expectedCode = @"class C -{ - int IntProperty { get; set; } - void M() + + [Fact] + public async Task LambdaReturnType_03() { - _ = this is { IntProperty: 2 }; + await AssertFormatAsync( + """ + class Program + { + Delegate D = A (x) => x; + } + """, + """ + class Program + { + Delegate D = A < B > ( x ) => x; + } + """); } -}"; - await AssertFormatAsync(expectedCode, code); - } - [Fact] - public async Task NoSpacesInExtendedPropertyPatterns() - { - var code = @"class C -{ - C CProperty { get; set; } - int IntProperty { get; set; } - void M() + [Fact] + public async Task LambdaReturnType_04() { - _ = this is { CProperty . IntProperty : 2 }; + await AssertFormatAsync( + """ + class Program + { + object F = Func((A, B) ((A, B) t) => t); + } + """, + """ + class Program + { + object F = Func((A,B)((A,B)t)=>t); + } + """); } -}"; - var expectedCode = @"class C -{ - C CProperty { get; set; } - int IntProperty { get; set; } - void M() + + [Fact] + public async Task LineSpanDirective() { - _ = this is { CProperty.IntProperty: 2 }; + var optionSet = new OptionsCollection(LanguageNames.CSharp) { { FormattingOptions2.UseTabs, true } }; + await AssertFormatAsync( + """ + class Program + { + static void Main() + { + #line (1, 1) - (1, 100) 5 "a.razor" + } + } + """, + """ + class Program + { + static void Main() + { + #line (1,1)-(1,100) 5 "a.razor" + } + } + """, changedOptionSet: optionSet); } -}"; - await AssertFormatAsync(expectedCode, code); - } - - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/52413")] - public async Task NewLinesForBraces_PropertyPatternClauses_Default() - { - await AssertFormatAsync( - @" -class A -{ - public string Name { get; } - public bool IsFoo(A a) + [Fact] + public async Task FileScopedNamespace() { - return a is - { - Name: ""foo"", - }; + await AssertFormatAsync( + expected: """ + + namespace NS; + + class C { } + + """, + code: """ + + namespace NS; + + class C { } + + """); } -}", - @" -class A -{ - public string Name { get; } - public bool IsFoo(A a) + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56498")] + public async Task NewInImplicitObjectCreation() { - return a is { - Name: ""foo"", - }; - } -}"); - } + await AssertFormatAsync( + expected: """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/52413")] - public async Task NewLinesForBraces_PropertyPatternClauses_NonDefault() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) + class C { - { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers, false) }, - }; - await AssertFormatAsync( - @" -class A -{ - public string Name { get; } + void M() + { + string v = new(); + } + } - public bool IsFoo(A a) - { - return a is { - Name: ""foo"", - }; + """, + code: """ + + class C + { + void M() { + string v = new (); + } + } + + """); } -}", - @" -class A -{ - public string Name { get; } - public bool IsFoo(A a) + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56498")] + public async Task NewInTupleArrayCreation() { - return a is - { - Name: ""foo"", - }; - } -}", changedOptionSet: changingOptions); - } + await AssertFormatAsync( + expected: """ - [Fact, Trait(Traits.Feature, Traits.Features.Formatting)] - [WorkItem(57854, "https://github.com/dotnet/roslyn/issues/57854")] - public async Task NewLinesForBraces_PropertyPatternClauses_NonDefaultInSwitchExpression() - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) + class C { - { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers, false) }, - }; - await AssertFormatAsync( - @" -class A -{ - public string Name { get; } + void M() + { + var v = new (int, int)[]; + } + } - public bool IsFoo(A a) - { - return a switch { - { Name: ""foo"" } => true, - _ => false, - }; + """, + code: """ + + class C + { + void M() { + var v = new (int, int) [ ]; + } + } + + """); } -}", - @" -class A -{ - public string Name { get; } - public bool IsFoo(A a) + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56498")] + public async Task NewInArrayCreation() { - return a switch - { - { Name: ""foo"" } => true, - _ => false, - }; - } -}", changedOptionSet: changingOptions); - } + await AssertFormatAsync( + expected: """ - [Theory, CombinatorialData] - [WorkItem("https://github.com/dotnet/roslyn/issues/52413")] - public async Task NewLinesForBraces_PropertyPatternClauses_SingleLine(bool option) - { - var changingOptions = new OptionsCollection(LanguageNames.CSharp) + class C { - { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers, option) }, - }; - var code = @" -class A -{ - public string Name { get; } + void M() + { + var v = new int[1]; + } + } - public bool IsFoo(A a) - { - return a is { Name: ""foo"" }; + """, + code: """ + + class C + { + void M() { + var v = new int [ 1 ]; + } + } + + """); } -}"; - await AssertFormatAsync(code, code, changedOptionSet: changingOptions); - } - [Fact] - public async Task RecordClass() - { - await AssertFormatAsync( - @" -record class R(int X); -", - @" -record class R(int X); -"); - } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56498")] + public async Task NewInImplicitArrayCreation() + { + await AssertFormatAsync( + expected: """ - [Fact] - public async Task Class() - { - await AssertFormatAsync( - @" -class R(int X); -", - @" -class R(int X) ; -"); - } + class C + { + void M() + { + var v = new[] { 1, 2, 3 }; + } + } - [Fact] - public async Task Interface() - { - await AssertFormatAsync( - @" -interface R(int X); -", - @" -interface R(int X) ; -"); - } + """, + code: """ - [Fact] - public async Task RecordStruct() - { - await AssertFormatAsync( - @" -record struct R(int X); -", - @" -record struct R(int X); -"); - } + class C + { + void M() { + var v = new [ ] { 1, 2, 3 }; + } + } - [Fact] - public async Task Struct() - { - await AssertFormatAsync( - @" -struct R(int X); -", - @" -struct R(int X) ; -"); - } + """); + } - [Fact] - public async Task FormatListPattern() - { - var code = @" -class C -{ - void M() { -_ = this is[1,2,>=3]; -} -}"; - await AssertFormatAsync(code: code, expected: @" -class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56498")] + public async Task NewInConstructorConstraint() { - _ = this is [1, 2, >= 3]; - } -}"); + await AssertFormatAsync( + expected: """ - var options = new OptionsCollection(LanguageNames.CSharp) + class C { - { SpaceBetweenEmptySquareBrackets, false }, - { SpaceWithinSquareBrackets, false }, - { SpaceBeforeComma, false }, - { SpaceAfterComma, false }, - }; + void M() where T : new() + { + } + } - await AssertFormatAsync(code: code, changedOptionSet: options, expected: @" -class C -{ - void M() - { - _ = this is [1,2,>= 3]; - } -}"); + """, + code: """ - options = new OptionsCollection(LanguageNames.CSharp) + class C { - { SpaceBeforeOpenSquareBracket, false }, // ignored - { SpaceBetweenEmptySquareBrackets, true }, - { SpaceWithinSquareBrackets, true }, - { SpaceBeforeComma, true }, - { SpaceAfterComma, true }, - }; + void M() where T : new ( ) { + } + } - await AssertFormatAsync(code: code, changedOptionSet: options, expected: @" -class C -{ - void M() - { - _ = this is [ 1 , 2 , >= 3 ]; + """); } -}"); - } - [Fact] - public async Task FormatListPattern_Parentheses() - { - var code = @" -class C -{ - void M((int[], int[]) a) { -_ = a is([1,2,>=3],[1,2]); -} -}"; - await AssertFormatAsync(code: code, expected: @" -class C -{ - void M((int[], int[]) a) + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56498")] + public async Task NewMethodOverloadWithTupleReturnType() { - _ = a is ([1, 2, >= 3], [1, 2]); - } -}"); + await AssertFormatAsync( + expected: """ - var options = new OptionsCollection(LanguageNames.CSharp) + class C { - { SpaceBetweenEmptySquareBrackets, false }, - { SpaceWithinSquareBrackets, false }, - { SpaceBeforeComma, false }, - { SpaceAfterComma, false }, - }; + new (int, int) M() { } + } - await AssertFormatAsync(code: code, changedOptionSet: options, expected: @" -class C -{ - void M((int[], int[]) a) - { - _ = a is ([1,2,>= 3],[1,2]); - } -}"); + """, + code: """ - options = new OptionsCollection(LanguageNames.CSharp) + class C { - { SpaceBeforeOpenSquareBracket, false }, // ignored - { SpaceBetweenEmptySquareBrackets, true }, - { SpaceWithinSquareBrackets, true }, - { SpaceBeforeComma, true }, - { SpaceAfterComma, true }, - }; + new (int, int) M() { } + } - await AssertFormatAsync(code: code, changedOptionSet: options, expected: @" -class C -{ - void M((int[ ], int[ ]) a) - { - _ = a is ([ 1 , 2 , >= 3 ], [ 1 , 2 ]); + """); } -}"); - } - [Fact] - public async Task FormatListPattern_TrailingComma() - { - var code = @" -class C -{ - void M() { -_ = this is[1,2,>=3,]; -} -}"; - await AssertFormatAsync(code: code, expected: @" -class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56498")] + public async Task NewPropertyWithTupleReturnType() { - _ = this is [1, 2, >= 3,]; - } -}"); + await AssertFormatAsync( + expected: """ - var options = new OptionsCollection(LanguageNames.CSharp) + class C { - { SpaceBetweenEmptySquareBrackets, false }, - { SpaceWithinSquareBrackets, false }, - { SpaceBeforeComma, false }, - { SpaceAfterComma, false }, - }; + new (int, int) Property { get; set; } + } - await AssertFormatAsync(code: code, changedOptionSet: options, expected: @" -class C -{ - void M() - { - _ = this is [1,2,>= 3,]; - } -}"); + """, + code: """ - options = new OptionsCollection(LanguageNames.CSharp) + class C { - { SpaceBeforeOpenSquareBracket, false }, // ignored - { SpaceBetweenEmptySquareBrackets, true }, - { SpaceWithinSquareBrackets, true }, - { SpaceBeforeComma, true }, - { SpaceAfterComma, true }, - }; + new (int, int) Property { get; set; } + } - await AssertFormatAsync(code: code, changedOptionSet: options, expected: @" -class C -{ - void M() - { - _ = this is [ 1 , 2 , >= 3 , ]; + """); } -}"); - } - [Fact] - public async Task FormatListPattern_WithNewline() - { - var code = @" -class C -{ - void M() { -_ = this is -[1,2,>=3 -]; -} -}"; - await AssertFormatAsync(code: code, expected: @" -class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56498")] + public async Task NewIndexerWithTupleReturnType() { - _ = this is - [1, 2, >= 3 - ]; - } -}"); + await AssertFormatAsync( + expected: """ - var options = new OptionsCollection(LanguageNames.CSharp) + class C { - { SpaceBetweenEmptySquareBrackets, false }, - { SpaceWithinSquareBrackets, false }, - { SpaceBeforeComma, false }, - { SpaceAfterComma, false }, - }; + new (int, int) this[int i] { get => throw null; } + } - await AssertFormatAsync(code: code, changedOptionSet: options, expected: @" -class C -{ - void M() - { - _ = this is - [1,2,>= 3 - ]; - } -}"); + """, + code: """ - options = new OptionsCollection(LanguageNames.CSharp) + class C { - { SpaceBeforeOpenSquareBracket, false }, // ignored - { SpaceBetweenEmptySquareBrackets, true }, - { SpaceWithinSquareBrackets, true }, - { SpaceBeforeComma, true }, - { SpaceAfterComma, true }, - }; + new (int, int) this[int i] { get => throw null; } + } - await AssertFormatAsync(code: code, changedOptionSet: options, expected: @" -class C -{ - void M() - { - _ = this is - [ 1 , 2 , >= 3 - ]; + """); } -}"); - } - [Fact] - public async Task FormatSlicePattern() - { - var code = @"class C -{ - void M() { -_ = this is[ 0,.. var rest ]; -} -}"; - var expectedCode = @"class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56543")] + public async Task FormatAttributeOnLambda() { - _ = this is [0, .. var rest]; + await AssertFormatAsync( + expected: """ + + var f = [Attribute] () => { }; + + """, + code: """ + + var f = [Attribute] () => { }; + + """); } -}"; - await AssertFormatAsync(expectedCode, code); - } - [Fact] - public async Task FormatSlicePattern_NoSpace() - { - var code = @"class C -{ - void M() { -_ = this is[ 0,..var rest ]; -} -}"; - var expectedCode = @"class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56543")] + public async Task FormatAttributeOnLambda_TwoAttributes() { - _ = this is [0, .. var rest]; + await AssertFormatAsync( + expected: """ + + var f = [Attribute][Attribute2] () => { }; + + """, + code: """ + + var f = [Attribute] [Attribute2] () => { }; + + """); } -}"; - await AssertFormatAsync(expectedCode, code); - } - [Fact] - public async Task FormatSlicePatternWithAnd() - { - var code = @"class C -{ - void M() { -_ = this is[ 0,.. {Count: >0} and var rest ]; -} -}"; - var expectedCode = @"class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56543")] + public async Task FormatAttributeOnMethod_TwoAttributes() { - _ = this is [0, .. { Count: > 0 } and var rest]; + await AssertFormatAsync( + expected: """ + + [Attribute][Attribute2] + void M() + { } + + """, + code: """ + + [Attribute] [Attribute2] + void M() + { } + + """); } -}"; - await AssertFormatAsync(expectedCode, code); - } - [Fact] - public async Task FormatLengthAndListPattern() - { - var code = @"class C -{ - void M() { -_ = this is{Count:>0 and var x}and[ 1,2,3 ]; -} -}"; - var expectedCode = @"class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56543")] + public async Task FormatAttributeOnTypeParameter_TwoAttributes() { - _ = this is { Count: > 0 and var x } and [1, 2, 3]; - } -}"; - await AssertFormatAsync(expectedCode, code); - } + await AssertFormatAsync( + expected: """ - [Fact] - public async Task LambdaReturnType_01() - { - await AssertFormatAsync( -@"class Program -{ - Delegate D = void () => { }; -}", -@"class Program -{ - Delegate D = void () => { }; -}"); - } + class C<[Attribute][Attribute2] T> { } - [Fact] - public async Task LambdaReturnType_02() - { - await AssertFormatAsync( -@"class Program -{ - Delegate D = A.B () => { }; -}", -@"class Program -{ - Delegate D = A.B()=>{ }; -}"); - } + """, + code: """ - [Fact] - public async Task LambdaReturnType_03() - { - await AssertFormatAsync( -@"class Program -{ - Delegate D = A (x) => x; -}", -@"class Program -{ - Delegate D = A < B > ( x ) => x; -}"); - } + class C< [Attribute] [Attribute2] T > { } - [Fact] - public async Task LambdaReturnType_04() - { - await AssertFormatAsync( -@"class Program -{ - object F = Func((A, B) ((A, B) t) => t); -}", -@"class Program -{ - object F = Func((A,B)((A,B)t)=>t); -}"); - } + """); + } - [Fact] - public async Task LineSpanDirective() - { - var optionSet = new OptionsCollection(LanguageNames.CSharp) { { FormattingOptions2.UseTabs, true } }; - await AssertFormatAsync( -@"class Program -{ - static void Main() - { -#line (1, 1) - (1, 100) 5 ""a.razor"" - } -}", -@"class Program -{ - static void Main() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56543")] + public async Task FormatAttributeOnTypeParameter_TwoAttributes_Method() { -#line (1,1)-(1,100) 5 ""a.razor"" - } -}", changedOptionSet: optionSet); - } + await AssertFormatAsync( + expected: """ - [Fact] - public async Task FileScopedNamespace() - { - await AssertFormatAsync( - expected: @" -namespace NS; + class C + { + void M<[Attribute][Attribute2] T>() { } + } -class C { } -", - code: @" -namespace NS; + """, + code: """ - class C { } -"); - } + class C + { + void M< [Attribute] [Attribute2] T > ( ) { } + } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56498")] - public async Task NewInImplicitObjectCreation() - { - await AssertFormatAsync( - expected: @" -class C -{ - void M() - { - string v = new(); - } -} -", - code: @" -class C -{ - void M() { - string v = new (); + """); } -} -"); - } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56498")] - public async Task NewInTupleArrayCreation() - { - await AssertFormatAsync( - expected: @" -class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56543")] + public async Task FormatAttributeOnParameter_TwoAttributes() { - var v = new (int, int)[]; - } -} -", - code: @" -class C -{ - void M() { - var v = new (int, int) [ ]; + await AssertFormatAsync( + expected: """ + + class C + { + void M([Attribute][Attribute2] T t) { } + } + + """, + code: """ + + class C + { + void M( [Attribute] [Attribute2] T t ) { } + } + + """); } -} -"); - } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56498")] - public async Task NewInArrayCreation() - { - await AssertFormatAsync( - expected: @" -class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56543")] + public async Task FormatAttributeOnLambdaWithExplicitType() { - var v = new int[1]; - } -} -", - code: @" -class C -{ - void M() { - var v = new int [ 1 ]; + await AssertFormatAsync( + expected: """ + + var f = [Attribute] int () => 1; + + """, + code: """ + + var f = [Attribute] int () => 1; + + """); } -} -"); - } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56498")] - public async Task NewInImplicitArrayCreation() - { - await AssertFormatAsync( - expected: @" -class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56543")] + public async Task FormatAttributeOnLambdaInInvocation() { - var v = new[] { 1, 2, 3 }; - } -} -", - code: @" -class C -{ - void M() { - var v = new [ ] { 1, 2, 3 }; + await AssertFormatAsync( + expected: """ + + f([Attribute] () => { }); + + """, + code: """ + + f( [Attribute] () => { }); + + """); } -} -"); - } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56498")] - public async Task NewInConstructorConstraint() - { - await AssertFormatAsync( - expected: @" -class C -{ - void M() where T : new() + [Fact] + public async Task FormatAttributeOnLambdaParameter() { + await AssertFormatAsync(expected: """ + var f = ([Attribute] int x = 1) => x; + """, code: """ + var f = ( [ Attribute ]int x=1)=>x; + """); } -} -", - code: @" -class C -{ - void M() where T : new ( ) { - } -} -"); - } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56498")] - public async Task NewMethodOverloadWithTupleReturnType() - { - await AssertFormatAsync( - expected: @" -class C -{ - new (int, int) M() { } -} -", - code: @" -class C -{ - new (int, int) M() { } -} -"); - } + [Fact] + public async Task FormatRawStringInterpolation() + { + await AssertFormatAsync( + expected: """" - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56498")] - public async Task NewPropertyWithTupleReturnType() - { - await AssertFormatAsync( - expected: @" -class C -{ - new (int, int) Property { get; set; } -} -", - code: @" -class C -{ - new (int, int) Property { get; set; } -} -"); - } + var s = $"""{s}""" - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56498")] - public async Task NewIndexerWithTupleReturnType() - { - await AssertFormatAsync( - expected: @" -class C -{ - new (int, int) this[int i] { get => throw null; } -} -", - code: @" -class C -{ - new (int, int) this[int i] { get => throw null; } -} -"); - } + """", + code: """" - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56543")] - public async Task FormatAttributeOnLambda() - { - await AssertFormatAsync( - expected: @" -var f = [Attribute] () => { }; -", - code: @" -var f = [Attribute] () => { }; -"); - } + var s = $"""{s}""" - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56543")] - public async Task FormatAttributeOnLambda_TwoAttributes() - { - await AssertFormatAsync( - expected: @" -var f = [Attribute][Attribute2] () => { }; -", - code: @" -var f = [Attribute] [Attribute2] () => { }; -"); - } + """"); + } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56543")] - public async Task FormatAttributeOnMethod_TwoAttributes() - { - await AssertFormatAsync( - expected: @" -[Attribute][Attribute2] -void M() -{ } -", - code: @" - [Attribute] [Attribute2] -void M() -{ } -"); - } + [Fact] + public async Task FormatRawStringInterpolation2() + { + await AssertFormatAsync( + expected: """" - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56543")] - public async Task FormatAttributeOnTypeParameter_TwoAttributes() - { - await AssertFormatAsync( - expected: @" -class C<[Attribute][Attribute2] T> { } -", - code: @" -class C< [Attribute] [Attribute2] T > { } -"); - } + var s = $"""{s,0: x }""" - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56543")] - public async Task FormatAttributeOnTypeParameter_TwoAttributes_Method() - { - await AssertFormatAsync( - expected: @" -class C -{ - void M<[Attribute][Attribute2] T>() { } -} -", - code: @" -class C -{ - void M< [Attribute] [Attribute2] T > ( ) { } -} -"); - } + """", + code: """" - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56543")] - public async Task FormatAttributeOnParameter_TwoAttributes() - { - await AssertFormatAsync( - expected: @" -class C -{ - void M([Attribute][Attribute2] T t) { } -} -", - code: @" -class C -{ - void M( [Attribute] [Attribute2] T t ) { } -} -"); - } + var s = $"""{s, 0 : x }""" - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56543")] - public async Task FormatAttributeOnLambdaWithExplicitType() - { - await AssertFormatAsync( - expected: @" -var f = [Attribute] int () => 1; -", - code: @" -var f = [Attribute] int () => 1; -"); - } + """"); + } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56543")] - public async Task FormatAttributeOnLambdaInInvocation() - { - await AssertFormatAsync( - expected: @" -f([Attribute] () => { }); -", - code: @" -f( [Attribute] () => { }); -"); - } + [Fact] + public async Task FormatUsingAliasToType1() + { + await AssertFormatAsync( + expected: """ - [Fact] - public async Task FormatAttributeOnLambdaParameter() - { - await AssertFormatAsync(expected: """ - var f = ([Attribute] int x = 1) => x; - """, code: """ - var f = ( [ Attribute ]int x=1)=>x; - """); - } + f([Attribute] () => { }); - [Fact] - public async Task FormatRawStringInterpolation() - { - await AssertFormatAsync( - expected: @" -var s = $""""""{s}"""""" -", - code: @" -var s = $""""""{s}"""""" -"); - } + """, + code: """ - [Fact] - public async Task FormatRawStringInterpolation2() - { - await AssertFormatAsync( - expected: @" -var s = $""""""{s,0: x }"""""" -", - code: @" -var s = $""""""{s, 0 : x }"""""" -"); - } + f( [Attribute] () => { }); - [Fact] - public async Task FormatUsingAliasToType1() - { - await AssertFormatAsync( - expected: @" -f([Attribute] () => { }); -", - code: @" -f( [Attribute] () => { }); -"); - } + """); + } - [Theory] - [InlineData("using X=int ;", "using X = int;")] - [InlineData("global using X=int ;", "global using X = int;")] - [InlineData("using X=nint;", "using X = nint;")] - [InlineData("using X=dynamic;", "using X = dynamic;")] - [InlineData("using X=int [] ;", "using X = int[];")] - [InlineData("using X=(int,int) ;", "using X = (int, int);")] - [InlineData("using unsafe X=int * ;", "using unsafe X = int*;")] - [InlineData("global using unsafe X=int * ;", "global using unsafe X = int*;")] - [InlineData("using X=int ?;", "using X = int?;")] - [InlineData("using X=delegate * ;", "using X = delegate*;")] - public async Task TestNormalizeUsingAlias(string text, string expected) - { - await AssertFormatAsync(expected, text); - } + [Theory] + [InlineData("using X=int ;", "using X = int;")] + [InlineData("global using X=int ;", "global using X = int;")] + [InlineData("using X=nint;", "using X = nint;")] + [InlineData("using X=dynamic;", "using X = dynamic;")] + [InlineData("using X=int [] ;", "using X = int[];")] + [InlineData("using X=(int,int) ;", "using X = (int, int);")] + [InlineData("using unsafe X=int * ;", "using unsafe X = int*;")] + [InlineData("global using unsafe X=int * ;", "global using unsafe X = int*;")] + [InlineData("using X=int ?;", "using X = int?;")] + [InlineData("using X=delegate * ;", "using X = delegate*;")] + public async Task TestNormalizeUsingAlias(string text, string expected) + { + await AssertFormatAsync(expected, text); + } + + [Fact] + public async Task TestExtension1() + { + await AssertFormatAsync( + """ + static class C + { + extension(string s) + { + public void M() + { + } + } + } + """, + """ + static class C + { + extension ( string s ) + { + public void M ( ) + { + } + } + } + """, + parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersionExtensions.CSharpNext)); } } diff --git a/src/Workspaces/CSharpTest/Formatting/FormattingTests_Patterns.cs b/src/Workspaces/CSharpTest/Formatting/FormattingTests_Patterns.cs index 4caeafdd8856c..5ca7c0fa62a2c 100644 --- a/src/Workspaces/CSharpTest/Formatting/FormattingTests_Patterns.cs +++ b/src/Workspaces/CSharpTest/Formatting/FormattingTests_Patterns.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; -using Roslyn.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Formatting diff --git a/src/Workspaces/CSharpTest/Microsoft.CodeAnalysis.CSharp.Workspaces.UnitTests.csproj b/src/Workspaces/CSharpTest/Microsoft.CodeAnalysis.CSharp.Workspaces.UnitTests.csproj index 65dae6561ce44..065c2a4dd7aed 100644 --- a/src/Workspaces/CSharpTest/Microsoft.CodeAnalysis.CSharp.Workspaces.UnitTests.csproj +++ b/src/Workspaces/CSharpTest/Microsoft.CodeAnalysis.CSharp.Workspaces.UnitTests.csproj @@ -7,6 +7,9 @@ $(NetVSShared);net472 + + + diff --git a/src/Workspaces/CSharpTest/OrganizeImports/OrganizeUsingsTests.cs b/src/Workspaces/CSharpTest/OrganizeImports/OrganizeUsingsTests.cs index 7e6d2ca93dcd6..77bbcba1784b8 100644 --- a/src/Workspaces/CSharpTest/OrganizeImports/OrganizeUsingsTests.cs +++ b/src/Workspaces/CSharpTest/OrganizeImports/OrganizeUsingsTests.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.OrganizeImports; diff --git a/src/Workspaces/Core/Desktop/TypeForwarders.cs b/src/Workspaces/Core/Desktop/TypeForwarders.cs index bd00d5063caa4..914343bc8d8b4 100644 --- a/src/Workspaces/Core/Desktop/TypeForwarders.cs +++ b/src/Workspaces/Core/Desktop/TypeForwarders.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.Runtime.CompilerServices; // Microsoft.CodeAnalysis.FileTextLoader has been moved to Microsoft.CodeAnalysis.Workspaces.dll. diff --git a/src/Workspaces/Core/Desktop/Workspace/Host/Mef/MefV1HostServices.cs b/src/Workspaces/Core/Desktop/Workspace/Host/Mef/MefV1HostServices.cs index 6ec35bcccc9f6..eb940aae6922f 100644 --- a/src/Workspaces/Core/Desktop/Workspace/Host/Mef/MefV1HostServices.cs +++ b/src/Workspaces/Core/Desktop/Workspace/Host/Mef/MefV1HostServices.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; using System.Collections.Generic; @@ -26,7 +24,7 @@ public class MefV1HostServices : HostServices, IMefHostExportProvider /// This delegate allows test code to override the behavior of . /// /// - private static CreationHook s_CreationHook; + private static CreationHook? s_CreationHook; // the export provider for the MEF composition private readonly ExportProvider _exportProvider; @@ -80,7 +78,7 @@ protected internal override HostWorkspaceServices CreateWorkspaceServices(Worksp /// public IEnumerable> GetExports() { - var key = new ExportKey(typeof(TExtension).AssemblyQualifiedName, typeof(TMetadata).AssemblyQualifiedName); + var key = new ExportKey(typeof(TExtension).AssemblyQualifiedName!, typeof(TMetadata).AssemblyQualifiedName!); if (!_exportsMap.TryGetValue(key, out var exports)) { exports = ImmutableInterlocked.GetOrAdd(ref _exportsMap, key, _ => @@ -97,7 +95,7 @@ public IEnumerable> GetExports public IEnumerable> GetExports() { - var key = new ExportKey(typeof(TExtension).AssemblyQualifiedName, ""); + var key = new ExportKey(typeof(TExtension).AssemblyQualifiedName!, ""); if (!_exportsMap.TryGetValue(key, out var exports)) { exports = ImmutableInterlocked.GetOrAdd(ref _exportsMap, key, _ => @@ -128,7 +126,7 @@ public bool Equals(ExportKey other) && string.Compare(this.MetadataTypeName, other.MetadataTypeName, StringComparison.OrdinalIgnoreCase) == 0; } - public override bool Equals(object obj) + public override bool Equals(object? obj) => obj is ExportKey exportKey && this.Equals(exportKey); public override int GetHashCode() diff --git a/src/Workspaces/Core/Portable/ChangeNamespace/IChangeNamespaceService.cs b/src/Workspaces/Core/Portable/ChangeNamespace/IChangeNamespaceService.cs index c02cef62400ab..971b57a606e9a 100644 --- a/src/Workspaces/Core/Portable/ChangeNamespace/IChangeNamespaceService.cs +++ b/src/Workspaces/Core/Portable/ChangeNamespace/IChangeNamespaceService.cs @@ -4,7 +4,6 @@ using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.ChangeNamespace; diff --git a/src/Workspaces/Core/Portable/Classification/AbstractClassificationService.cs b/src/Workspaces/Core/Portable/Classification/AbstractClassificationService.cs index dd1a9232a399e..d8abbec45dc48 100644 --- a/src/Workspaces/Core/Portable/Classification/AbstractClassificationService.cs +++ b/src/Workspaces/Core/Portable/Classification/AbstractClassificationService.cs @@ -17,7 +17,6 @@ using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Classification; diff --git a/src/Workspaces/Core/Portable/Classification/SyntaxClassification/AbstractSyntaxClassificationService.cs b/src/Workspaces/Core/Portable/Classification/SyntaxClassification/AbstractSyntaxClassificationService.cs index 2a0f06553b0dd..9c607c239da06 100644 --- a/src/Workspaces/Core/Portable/Classification/SyntaxClassification/AbstractSyntaxClassificationService.cs +++ b/src/Workspaces/Core/Portable/Classification/SyntaxClassification/AbstractSyntaxClassificationService.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Classification; diff --git a/src/Workspaces/Core/Portable/CodeActions/CodeAction.cs b/src/Workspaces/Core/Portable/CodeActions/CodeAction.cs index c11b685452841..dbd9f775ca9d0 100644 --- a/src/Workspaces/Core/Portable/CodeActions/CodeAction.cs +++ b/src/Workspaces/Core/Portable/CodeActions/CodeAction.cs @@ -16,7 +16,6 @@ using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; @@ -658,16 +657,19 @@ protected CodeActionWithNestedActions( internal class DocumentChangeAction : SimpleCodeAction { private readonly Func, CancellationToken, Task> _createChangedDocument; + private readonly Func, CancellationToken, Task>? _createChangedDocumentPreview; private DocumentChangeAction( string title, Func, CancellationToken, Task> createChangedDocument, + Func, CancellationToken, Task>? createChangedDocumentPreview, string? equivalenceKey, CodeActionPriority priority, bool createdFromFactoryMethod) : base(title, equivalenceKey, priority, createdFromFactoryMethod) { _createChangedDocument = createChangedDocument; + _createChangedDocumentPreview = createChangedDocumentPreview; } protected DocumentChangeAction( @@ -675,7 +677,7 @@ protected DocumentChangeAction( Func, CancellationToken, Task> createChangedDocument, string? equivalenceKey, CodeActionPriority priority = CodeActionPriority.Default) - : this(title, createChangedDocument, equivalenceKey, priority, createdFromFactoryMethod: false) + : this(title, createChangedDocument, createChangedDocumentPreview: null, equivalenceKey, priority, createdFromFactoryMethod: false) { } @@ -684,7 +686,16 @@ public static DocumentChangeAction New( Func, CancellationToken, Task> createChangedDocument, string? equivalenceKey, CodeActionPriority priority = CodeActionPriority.Default) - => new(title, createChangedDocument, equivalenceKey, priority, createdFromFactoryMethod: true); + => new(title, createChangedDocument, createChangedDocumentPreview: null, equivalenceKey, priority, createdFromFactoryMethod: true); + + protected override async Task> ComputePreviewOperationsAsync(CancellationToken cancellationToken) + { + if (_createChangedDocumentPreview is null) + return await base.ComputePreviewOperationsAsync(cancellationToken).ConfigureAwait(false); + + var newDocument = await _createChangedDocumentPreview(CodeAnalysisProgress.None, cancellationToken).ConfigureAwait(false); + return [new ApplyChangesOperation(newDocument.Project.Solution)]; + } protected sealed override Task GetChangedDocumentAsync(IProgress progress, CancellationToken cancellationToken) => _createChangedDocument(progress, cancellationToken); diff --git a/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllContext.cs b/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllContext.cs index 942392fbbbd43..56de731c8bfb4 100644 --- a/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllContext.cs +++ b/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllContext.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixesAndRefactorings; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeFixes; diff --git a/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllState.cs b/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllState.cs index dd4b91da6f91e..1e7ee4eddde7e 100644 --- a/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllState.cs +++ b/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllState.cs @@ -6,7 +6,6 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Linq; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixesAndRefactorings; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; diff --git a/src/Workspaces/Core/Portable/CodeFixesAndRefactorings/CommonFixAllState.cs b/src/Workspaces/Core/Portable/CodeFixesAndRefactorings/CommonFixAllState.cs index 7681dc9c307e9..8bc5930ccccae 100644 --- a/src/Workspaces/Core/Portable/CodeFixesAndRefactorings/CommonFixAllState.cs +++ b/src/Workspaces/Core/Portable/CodeFixesAndRefactorings/CommonFixAllState.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Internal.Log; using FixAllScope = Microsoft.CodeAnalysis.CodeFixes.FixAllScope; diff --git a/src/Workspaces/Core/Portable/CodeFixesAndRefactorings/FixAllLogger.cs b/src/Workspaces/Core/Portable/CodeFixesAndRefactorings/FixAllLogger.cs index efd024c4721ba..a88e2f3b6807d 100644 --- a/src/Workspaces/Core/Portable/CodeFixesAndRefactorings/FixAllLogger.cs +++ b/src/Workspaces/Core/Portable/CodeFixesAndRefactorings/FixAllLogger.cs @@ -5,7 +5,6 @@ using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis.Internal.Log; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeFixesAndRefactorings; diff --git a/src/Workspaces/Core/Portable/CodeFixesAndRefactorings/IFixAllState.cs b/src/Workspaces/Core/Portable/CodeFixesAndRefactorings/IFixAllState.cs index 66083f1d4ac32..e714ebe17dcd2 100644 --- a/src/Workspaces/Core/Portable/CodeFixesAndRefactorings/IFixAllState.cs +++ b/src/Workspaces/Core/Portable/CodeFixesAndRefactorings/IFixAllState.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 Microsoft.CodeAnalysis.CodeActions; using FixAllScope = Microsoft.CodeAnalysis.CodeFixes.FixAllScope; namespace Microsoft.CodeAnalysis.CodeFixesAndRefactorings; diff --git a/src/Workspaces/Core/Portable/CodeRefactorings/SyntaxEditorBasedCodeRefactoringProvider.cs b/src/Workspaces/Core/Portable/CodeRefactorings/SyntaxEditorBasedCodeRefactoringProvider.cs index 3064aa9009685..6c97f2080b6e3 100644 --- a/src/Workspaces/Core/Portable/CodeRefactorings/SyntaxEditorBasedCodeRefactoringProvider.cs +++ b/src/Workspaces/Core/Portable/CodeRefactorings/SyntaxEditorBasedCodeRefactoringProvider.cs @@ -6,7 +6,6 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -28,9 +27,7 @@ internal abstract partial class SyntaxEditorBasedCodeRefactoringProvider : CodeR return FixAllProvider.Create( async (fixAllContext, document, fixAllSpans) => - { - return await this.FixAllAsync(document, fixAllSpans, fixAllContext.CodeActionEquivalenceKey, fixAllContext.CancellationToken).ConfigureAwait(false); - }, + await this.FixAllAsync(document, fixAllSpans, fixAllContext.CodeActionEquivalenceKey, fixAllContext.CancellationToken).ConfigureAwait(false), SupportedFixAllScopes); } diff --git a/src/Workspaces/Core/Portable/CodeStyle/NotificationOption.cs b/src/Workspaces/Core/Portable/CodeStyle/NotificationOption.cs index 23655f80671ac..ff17b495a58ab 100644 --- a/src/Workspaces/Core/Portable/CodeStyle/NotificationOption.cs +++ b/src/Workspaces/Core/Portable/CodeStyle/NotificationOption.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.Diagnostics; diff --git a/src/Workspaces/Core/Portable/CodeStyle/NotificationOption2_operators.cs b/src/Workspaces/Core/Portable/CodeStyle/NotificationOption2_operators.cs index b72a6cfb83c81..a4acc94541aaa 100644 --- a/src/Workspaces/Core/Portable/CodeStyle/NotificationOption2_operators.cs +++ b/src/Workspaces/Core/Portable/CodeStyle/NotificationOption2_operators.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Roslyn.Utilities; - namespace Microsoft.CodeAnalysis.CodeStyle; internal readonly partial record struct NotificationOption2 diff --git a/src/Workspaces/Core/Portable/Diagnostics/CodeAnalysisEventSource.Workspaces.cs b/src/Workspaces/Core/Portable/Diagnostics/CodeAnalysisEventSource.Workspaces.cs index 40eaeb56ca70b..29712ea2a2b54 100644 --- a/src/Workspaces/Core/Portable/Diagnostics/CodeAnalysisEventSource.Workspaces.cs +++ b/src/Workspaces/Core/Portable/Diagnostics/CodeAnalysisEventSource.Workspaces.cs @@ -1,8 +1,7 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Diagnostics.Tracing; namespace Microsoft.CodeAnalysis diff --git a/src/Workspaces/Core/Portable/Diagnostics/CompilationWithAnalyzersPair.cs b/src/Workspaces/Core/Portable/Diagnostics/CompilationWithAnalyzersPair.cs index e9b7f7f73746e..5e308ed7521be 100644 --- a/src/Workspaces/Core/Portable/Diagnostics/CompilationWithAnalyzersPair.cs +++ b/src/Workspaces/Core/Portable/Diagnostics/CompilationWithAnalyzersPair.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. -using System; using System.Collections.Immutable; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using System.Threading.Tasks; diff --git a/src/Workspaces/Core/Portable/Diagnostics/DiagnosticAnalysisResult.cs b/src/Workspaces/Core/Portable/Diagnostics/DiagnosticAnalysisResult.cs index 9cd424ee9c284..8161311508bbf 100644 --- a/src/Workspaces/Core/Portable/Diagnostics/DiagnosticAnalysisResult.cs +++ b/src/Workspaces/Core/Portable/Diagnostics/DiagnosticAnalysisResult.cs @@ -8,7 +8,7 @@ using System.Linq; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; @@ -20,59 +20,40 @@ namespace Microsoft.CodeAnalysis.Workspaces.Diagnostics; /// internal readonly struct DiagnosticAnalysisResult { - public readonly bool FromBuild; public readonly ProjectId ProjectId; - public readonly VersionStamp Version; /// /// The set of documents that has any kind of diagnostics on it. /// public readonly ImmutableHashSet? DocumentIds; - public readonly bool IsEmpty; /// /// Syntax diagnostics from this file. /// - private readonly ImmutableDictionary>? _syntaxLocals; + private readonly ImmutableDictionary> _syntaxLocals; /// /// Semantic diagnostics from this file. /// - private readonly ImmutableDictionary>? _semanticLocals; + private readonly ImmutableDictionary> _semanticLocals; /// /// Diagnostics that were produced for these documents, but came from the analysis of other files. /// - private readonly ImmutableDictionary>? _nonLocals; + private readonly ImmutableDictionary> _nonLocals; /// /// Diagnostics that don't have locations. /// private readonly ImmutableArray _others; - private DiagnosticAnalysisResult(ProjectId projectId, VersionStamp version, ImmutableHashSet? documentIds, bool isEmpty, bool fromBuild) - { - ProjectId = projectId; - Version = version; - DocumentIds = documentIds; - IsEmpty = isEmpty; - FromBuild = fromBuild; - - _syntaxLocals = null; - _semanticLocals = null; - _nonLocals = null; - _others = default; - } - private DiagnosticAnalysisResult( ProjectId projectId, - VersionStamp version, ImmutableDictionary> syntaxLocals, ImmutableDictionary> semanticLocals, ImmutableDictionary> nonLocals, ImmutableArray others, - ImmutableHashSet? documentIds, - bool fromBuild) + ImmutableHashSet? documentIds) { Debug.Assert(!others.IsDefault); Debug.Assert(!syntaxLocals.Values.Any(item => item.IsDefault)); @@ -80,8 +61,6 @@ private DiagnosticAnalysisResult( Debug.Assert(!nonLocals.Values.Any(item => item.IsDefault)); ProjectId = projectId; - Version = version; - FromBuild = fromBuild; _syntaxLocals = syntaxLocals; _semanticLocals = semanticLocals; @@ -89,74 +68,21 @@ private DiagnosticAnalysisResult( _others = others; DocumentIds = documentIds ?? GetDocumentIds(syntaxLocals, semanticLocals, nonLocals); - IsEmpty = DocumentIds.IsEmpty && _others.IsEmpty; } - public static DiagnosticAnalysisResult CreateEmpty(ProjectId projectId, VersionStamp version) + public static DiagnosticAnalysisResult CreateEmpty(ProjectId projectId) { return new DiagnosticAnalysisResult( projectId, - version, documentIds: [], syntaxLocals: ImmutableDictionary>.Empty, semanticLocals: ImmutableDictionary>.Empty, nonLocals: ImmutableDictionary>.Empty, - others: [], - fromBuild: false); - } - - public static DiagnosticAnalysisResult CreateInitialResult(ProjectId projectId) - { - return new DiagnosticAnalysisResult( - projectId, - version: VersionStamp.Default, - documentIds: null, - isEmpty: true, - fromBuild: false); - } - - public static DiagnosticAnalysisResult CreateFromBuild(Project project, ImmutableArray diagnostics, IEnumerable initialDocuments) - { - // we can't distinguish locals and non locals from build diagnostics nor determine right snapshot version for the build. - // so we put everything in as semantic local with default version. this lets us to replace those to live diagnostics when needed easily. - var version = VersionStamp.Default; - - var documentIds = ImmutableHashSet.CreateBuilder(); - documentIds.AddRange(initialDocuments); - - var diagnosticsWithDocumentId = PooledDictionary>.GetInstance(); - var diagnosticsWithoutDocumentId = ArrayBuilder.GetInstance(); - - foreach (var data in diagnostics) - { - var documentId = data.DocumentId; - if (documentId != null) - { - documentIds.Add(documentId); - diagnosticsWithDocumentId.MultiAdd(documentId, data); - } - else - { - diagnosticsWithoutDocumentId.Add(data); - } - } - - var result = new DiagnosticAnalysisResult( - project.Id, - version, - documentIds: documentIds.ToImmutable(), - syntaxLocals: ImmutableDictionary>.Empty, - semanticLocals: diagnosticsWithDocumentId.ToImmutableMultiDictionaryAndFree(), - nonLocals: ImmutableDictionary>.Empty, - others: diagnosticsWithoutDocumentId.ToImmutableAndFree(), - fromBuild: true); - - return result; + others: []); } public static DiagnosticAnalysisResult Create( Project project, - VersionStamp version, ImmutableDictionary> syntaxLocalMap, ImmutableDictionary> semanticLocalMap, ImmutableDictionary> nonLocalMap, @@ -169,20 +95,17 @@ public static DiagnosticAnalysisResult Create( return new DiagnosticAnalysisResult( project.Id, - version, syntaxLocalMap, semanticLocalMap, nonLocalMap, others, - documentIds, - fromBuild: false); + documentIds); } public static DiagnosticAnalysisResult CreateFromBuilder(DiagnosticAnalysisResultBuilder builder) { return Create( builder.Project, - builder.Version, builder.SyntaxLocals, builder.SemanticLocals, builder.NonLocals, @@ -190,15 +113,6 @@ public static DiagnosticAnalysisResult CreateFromBuilder(DiagnosticAnalysisResul builder.DocumentIds); } - // aggregated form means it has aggregated information but no actual data. - public bool IsAggregatedForm => _syntaxLocals == null; - - // default analysis result - public bool IsDefault => DocumentIds == null; - - // make sure we don't return null - public ImmutableHashSet DocumentIdsOrEmpty => DocumentIds ?? []; - private ImmutableDictionary>? GetMap(AnalysisKind kind) => kind switch { @@ -210,41 +124,24 @@ public static DiagnosticAnalysisResult CreateFromBuilder(DiagnosticAnalysisResul public ImmutableArray GetAllDiagnostics() { - // PERF: don't allocation anything if not needed - if (IsAggregatedForm || IsEmpty) - { - return []; - } + using var result = TemporaryArray.Empty; - Contract.ThrowIfNull(_syntaxLocals); - Contract.ThrowIfNull(_semanticLocals); - Contract.ThrowIfNull(_nonLocals); - Contract.ThrowIfTrue(_others.IsDefault); + foreach (var (_, data) in _syntaxLocals) + result.AddRange(data); - using var _ = ArrayBuilder.GetInstance(out var builder); + foreach (var (_, data) in _semanticLocals) + result.AddRange(data); - foreach (var data in _syntaxLocals.Values) - builder.AddRange(data); + foreach (var (_, data) in _nonLocals) + result.AddRange(data); - foreach (var data in _semanticLocals.Values) - builder.AddRange(data); + result.AddRange(_others); - foreach (var data in _nonLocals.Values) - builder.AddRange(data); - - foreach (var data in _others) - builder.AddRange(data); - - return builder.ToImmutableAndClear(); + return result.ToImmutableAndClear(); } public ImmutableArray GetDocumentDiagnostics(DocumentId documentId, AnalysisKind kind) { - if (IsAggregatedForm || IsEmpty) - { - return []; - } - var map = GetMap(kind); Contract.ThrowIfNull(map); @@ -258,35 +155,24 @@ public ImmutableArray GetDocumentDiagnostics(DocumentId document } public ImmutableArray GetOtherDiagnostics() - => (IsAggregatedForm || IsEmpty) ? [] : _others; - - public DiagnosticAnalysisResult ToAggregatedForm() - => new(ProjectId, Version, DocumentIds, IsEmpty, FromBuild); - - public DiagnosticAnalysisResult UpdateAggregatedResult(VersionStamp version, DocumentId documentId, bool fromBuild) - => new(ProjectId, version, DocumentIdsOrEmpty.Add(documentId), isEmpty: false, fromBuild: fromBuild); - - public DiagnosticAnalysisResult Reset() - => new(ProjectId, VersionStamp.Default, DocumentIds, IsEmpty, FromBuild); + => _others; public DiagnosticAnalysisResult DropExceptSyntax() { // quick bail out if (_syntaxLocals == null || _syntaxLocals.Count == 0) { - return CreateEmpty(ProjectId, Version); + return CreateEmpty(ProjectId); } // keep only syntax errors return new DiagnosticAnalysisResult( ProjectId, - Version, _syntaxLocals, semanticLocals: ImmutableDictionary>.Empty, nonLocals: ImmutableDictionary>.Empty, others: [], - documentIds: null, - fromBuild: false); + documentIds: null); } private static ImmutableHashSet GetDocumentIds( diff --git a/src/Workspaces/Core/Portable/Diagnostics/DiagnosticAnalysisResultBuilder.cs b/src/Workspaces/Core/Portable/Diagnostics/DiagnosticAnalysisResultBuilder.cs index c2ec484358ccb..f4b4f6ec2b9bf 100644 --- a/src/Workspaces/Core/Portable/Diagnostics/DiagnosticAnalysisResultBuilder.cs +++ b/src/Workspaces/Core/Portable/Diagnostics/DiagnosticAnalysisResultBuilder.cs @@ -16,10 +16,9 @@ namespace Microsoft.CodeAnalysis.Workspaces.Diagnostics; /// We have this builder to avoid creating collections unnecessarily. /// Expectation is that, most of time, most of analyzers doesn't have any diagnostics. so no need to actually create any objects. /// -internal struct DiagnosticAnalysisResultBuilder(Project project, VersionStamp version) +internal struct DiagnosticAnalysisResultBuilder(Project project) { public readonly Project Project = project; - public readonly VersionStamp Version = version; private HashSet? _lazyDocumentsWithDiagnostics = null; diff --git a/src/Workspaces/Core/Portable/Diagnostics/DiagnosticAnalyzerExtensions.cs b/src/Workspaces/Core/Portable/Diagnostics/DiagnosticAnalyzerExtensions.cs index f76d51c050d14..10573a19b5833 100644 --- a/src/Workspaces/Core/Portable/Diagnostics/DiagnosticAnalyzerExtensions.cs +++ b/src/Workspaces/Core/Portable/Diagnostics/DiagnosticAnalyzerExtensions.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Roslyn.Utilities; - namespace Microsoft.CodeAnalysis.Diagnostics; internal static partial class DiagnosticAnalyzerExtensions diff --git a/src/Workspaces/Core/Portable/Diagnostics/DiagnosticData.cs b/src/Workspaces/Core/Portable/Diagnostics/DiagnosticData.cs index cb6d63dd32c32..9342db0363854 100644 --- a/src/Workspaces/Core/Portable/Diagnostics/DiagnosticData.cs +++ b/src/Workspaces/Core/Portable/Diagnostics/DiagnosticData.cs @@ -248,7 +248,7 @@ private static DiagnosticData Create( private static ImmutableDictionary? GetAdditionalProperties(TextDocument document, Diagnostic diagnostic) { var service = document.Project.GetLanguageService(); - return service?.GetAdditionalProperties(diagnostic); + return service?.GetAdditionalProperties(diagnostic)!; } private static ImmutableArray GetAdditionalLocations(TextDocument document, Diagnostic diagnostic) diff --git a/src/Workspaces/Core/Portable/Diagnostics/DocumentDiagnosticAnalyzer.cs b/src/Workspaces/Core/Portable/Diagnostics/DocumentDiagnosticAnalyzer.cs index b33a58f6cbc59..5a3d481aab3dd 100644 --- a/src/Workspaces/Core/Portable/Diagnostics/DocumentDiagnosticAnalyzer.cs +++ b/src/Workspaces/Core/Portable/Diagnostics/DocumentDiagnosticAnalyzer.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; diff --git a/src/Workspaces/Core/Portable/Diagnostics/Extensions.cs b/src/Workspaces/Core/Portable/Diagnostics/Extensions.cs index ae879b375a924..eb30cc820c762 100644 --- a/src/Workspaces/Core/Portable/Diagnostics/Extensions.cs +++ b/src/Workspaces/Core/Portable/Diagnostics/Extensions.cs @@ -7,6 +7,7 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Linq; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Collections; @@ -21,6 +22,8 @@ namespace Microsoft.CodeAnalysis.Diagnostics; internal static partial class Extensions { + private static readonly ConditionalWeakTable> s_projectToDiagnosticChecksum = new(); + public static async Task> ToDiagnosticsAsync(this IEnumerable diagnostics, Project project, CancellationToken cancellationToken) { var result = ArrayBuilder.GetInstance(); @@ -103,7 +106,6 @@ public static async Task additionalPragmaSuppressionDiagnostics, DocumentAnalysisScope? documentAnalysisScope, Project project, - VersionStamp version, ImmutableArray projectAnalyzers, ImmutableArray hostAnalyzers, SkippedHostAnalyzersInfo skippedAnalyzersInfo, @@ -133,7 +135,7 @@ public static async Task + /// Calculates a checksum that contains a project's checksum along with a checksum for each of the project's + /// transitive dependencies. + /// + /// + /// This checksum calculation can be used for cases where a feature needs to know if the semantics in this project + /// changed. For example, for diagnostics or caching computed semantic data. The goal is to ensure that changes to + /// + /// Files inside the current project + /// Project properties of the current project + /// Visible files in referenced projects + /// Project properties in referenced projects + /// + /// are reflected in the metadata we keep so that comparing solutions accurately tells us when we need to recompute + /// semantic work. + /// + /// This method of checking for changes has a few important properties that differentiate it from other methods of determining project version. + /// + /// Changes to methods inside the current project will be reflected to compute updated diagnostics. + /// does not change as it only returns top level changes. + /// Reloading a project without making any changes will re-use cached diagnostics. + /// changes as the project is removed, then added resulting in a version change. + /// + /// + /// This checksum is also affected by the for this project. + /// As such, it is not usable across different sessions of a particular host. + /// + public static Task GetDiagnosticChecksumAsync(this Project? project, CancellationToken cancellationToken) + { + if (project is null) + return SpecializedTasks.Default(); + + var lazyChecksum = s_projectToDiagnosticChecksum.GetValue( + project, + static project => AsyncLazy.Create( + static (project, cancellationToken) => ComputeDiagnosticChecksumAsync(project, cancellationToken), + project)); + + return lazyChecksum.GetValueAsync(cancellationToken); + + static async Task ComputeDiagnosticChecksumAsync(Project project, CancellationToken cancellationToken) + { + var solution = project.Solution; + + using var _ = ArrayBuilder.GetInstance(out var tempChecksumArray); + + // Mix in the SG information for this project. That way if it changes, we will have a different + // checksum (since semantics could have changed because of this). + if (solution.CompilationState.SourceGeneratorExecutionVersionMap.Map.TryGetValue(project.Id, out var executionVersion)) + tempChecksumArray.Add(executionVersion.Checksum); + + // Get the checksum for the project itself. Note: this will normally be cached. As such, even if we + // have a different Project instance (due to a change in an unrelated project), this will be fast to + // compute and return. + var projectChecksum = await project.State.GetChecksumAsync(cancellationToken).ConfigureAwait(false); + tempChecksumArray.Add(projectChecksum); + + // Calculate a checksum this project and for each dependent project that could affect semantics for this + // project. We order the projects guid so that we are resilient to the underlying in-memory graph structure + // changing this arbitrarily. + foreach (var projectRef in project.ProjectReferences.OrderBy(r => r.ProjectId.Id)) + { + // Note that these checksums should only actually be calculated once, if the project is unchanged + // the same checksum will be returned. + tempChecksumArray.Add(await GetDiagnosticChecksumAsync( + solution.GetProject(projectRef.ProjectId), cancellationToken).ConfigureAwait(false)); + } + + return Checksum.Create(tempChecksumArray); + } + } } diff --git a/src/Workspaces/Core/Portable/Diagnostics/FileContentLoadAnalyzer.cs b/src/Workspaces/Core/Portable/Diagnostics/FileContentLoadAnalyzer.cs index 5cc83d3c3f6e3..54c0ebe8b2305 100644 --- a/src/Workspaces/Core/Portable/Diagnostics/FileContentLoadAnalyzer.cs +++ b/src/Workspaces/Core/Portable/Diagnostics/FileContentLoadAnalyzer.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; namespace Microsoft.CodeAnalysis.Diagnostics; diff --git a/src/Workspaces/Core/Portable/Diagnostics/HostDiagnosticAnalyzers.cs b/src/Workspaces/Core/Portable/Diagnostics/HostDiagnosticAnalyzers.cs index e63221b427381..fb72eccc2dc01 100644 --- a/src/Workspaces/Core/Portable/Diagnostics/HostDiagnosticAnalyzers.cs +++ b/src/Workspaces/Core/Portable/Diagnostics/HostDiagnosticAnalyzers.cs @@ -133,7 +133,7 @@ public ImmutableDictionary> CreateDia /// Create identity and s map for given that /// has only project analyzers /// - public ImmutableDictionary> CreateProjectDiagnosticAnalyzersPerReference(Project project) + public ImmutableDictionary> CreateProjectDiagnosticAnalyzersPerReference(ProjectState project) => CreateProjectDiagnosticAnalyzersPerReference(project.AnalyzerReferences, project.Language); public ImmutableDictionary> CreateProjectDiagnosticAnalyzersPerReference(IReadOnlyList projectAnalyzerReferences, string language) @@ -296,7 +296,7 @@ private static ImmutableDictionary> M return current; } - public SkippedHostAnalyzersInfo GetSkippedAnalyzersInfo(Project project, DiagnosticAnalyzerInfoCache infoCache) + public SkippedHostAnalyzersInfo GetSkippedAnalyzersInfo(ProjectState project, DiagnosticAnalyzerInfoCache infoCache) { var box = _skippedHostAnalyzers.GetOrCreateValue(project.AnalyzerReferences); diff --git a/src/Workspaces/Core/Portable/Diagnostics/IDiagnosticPropertiesService.cs b/src/Workspaces/Core/Portable/Diagnostics/IDiagnosticPropertiesService.cs index af25c1b92bb95..caed6f4291d16 100644 --- a/src/Workspaces/Core/Portable/Diagnostics/IDiagnosticPropertiesService.cs +++ b/src/Workspaces/Core/Portable/Diagnostics/IDiagnosticPropertiesService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using Microsoft.CodeAnalysis.Host; diff --git a/src/Workspaces/Core/Portable/Diagnostics/IWorkspaceVenusSpanMappingService.cs b/src/Workspaces/Core/Portable/Diagnostics/IWorkspaceVenusSpanMappingService.cs index 95fd270f13239..a1b3a0a71b272 100644 --- a/src/Workspaces/Core/Portable/Diagnostics/IWorkspaceVenusSpanMappingService.cs +++ b/src/Workspaces/Core/Portable/Diagnostics/IWorkspaceVenusSpanMappingService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Text; diff --git a/src/Workspaces/Core/Portable/Diagnostics/ProjectDiagnosticAnalyzer.cs b/src/Workspaces/Core/Portable/Diagnostics/ProjectDiagnosticAnalyzer.cs index 735ada738c2d0..771c9cb3288ba 100644 --- a/src/Workspaces/Core/Portable/Diagnostics/ProjectDiagnosticAnalyzer.cs +++ b/src/Workspaces/Core/Portable/Diagnostics/ProjectDiagnosticAnalyzer.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; diff --git a/src/Workspaces/Core/Portable/Diagnostics/WellKnownDiagnosticPropertyNames.cs b/src/Workspaces/Core/Portable/Diagnostics/WellKnownDiagnosticPropertyNames.cs index 1530c81b312b6..d5dab9d6df631 100644 --- a/src/Workspaces/Core/Portable/Diagnostics/WellKnownDiagnosticPropertyNames.cs +++ b/src/Workspaces/Core/Portable/Diagnostics/WellKnownDiagnosticPropertyNames.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.Diagnostics; internal static class WellKnownDiagnosticPropertyNames diff --git a/src/Workspaces/Core/Portable/Differencing/LongestCommonImmutableArraySubsequence.cs b/src/Workspaces/Core/Portable/Differencing/LongestCommonImmutableArraySubsequence.cs index f550bc3d69b26..211d9f212f7bb 100644 --- a/src/Workspaces/Core/Portable/Differencing/LongestCommonImmutableArraySubsequence.cs +++ b/src/Workspaces/Core/Portable/Differencing/LongestCommonImmutableArraySubsequence.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; diff --git a/src/Workspaces/Core/Portable/Differencing/LongestCommonSubstring.cs b/src/Workspaces/Core/Portable/Differencing/LongestCommonSubstring.cs index 5561efb597b5b..f2cf5fde07776 100644 --- a/src/Workspaces/Core/Portable/Differencing/LongestCommonSubstring.cs +++ b/src/Workspaces/Core/Portable/Differencing/LongestCommonSubstring.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; namespace Microsoft.CodeAnalysis.Differencing; diff --git a/src/Workspaces/Core/Portable/Editing/DeclarationModifiers.cs b/src/Workspaces/Core/Portable/Editing/DeclarationModifiers.cs index 553aa1718382f..bab3554fe55e2 100644 --- a/src/Workspaces/Core/Portable/Editing/DeclarationModifiers.cs +++ b/src/Workspaces/Core/Portable/Editing/DeclarationModifiers.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.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Workspaces/Core/Portable/Editing/ImportAdder.cs b/src/Workspaces/Core/Portable/Editing/ImportAdder.cs index 4f8fb106f5a6c..b49641ad3fc64 100644 --- a/src/Workspaces/Core/Portable/Editing/ImportAdder.cs +++ b/src/Workspaces/Core/Portable/Editing/ImportAdder.cs @@ -7,7 +7,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.AddImport; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/Workspaces/Core/Portable/Editing/SyntaxEditor.cs b/src/Workspaces/Core/Portable/Editing/SyntaxEditor.cs index e18ee200d37fa..43e119533866e 100644 --- a/src/Workspaces/Core/Portable/Editing/SyntaxEditor.cs +++ b/src/Workspaces/Core/Portable/Editing/SyntaxEditor.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis.Host; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editing; diff --git a/src/Workspaces/Core/Portable/Editing/SyntaxEditorExtensions.cs b/src/Workspaces/Core/Portable/Editing/SyntaxEditorExtensions.cs index c7111748afc1f..5d3a60e4ead27 100644 --- a/src/Workspaces/Core/Portable/Editing/SyntaxEditorExtensions.cs +++ b/src/Workspaces/Core/Portable/Editing/SyntaxEditorExtensions.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; namespace Microsoft.CodeAnalysis.Editing; diff --git a/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs b/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs index 7f1f3d09ca93d..ad653c85131ec 100644 --- a/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs +++ b/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs @@ -1228,7 +1228,11 @@ public SyntaxNode AddMembers(SyntaxNode declaration, params SyntaxNode[] members /// /// Changes the for the declaration. /// - public abstract SyntaxNode WithModifiers(SyntaxNode declaration, DeclarationModifiers modifiers); + public SyntaxNode WithModifiers(SyntaxNode declaration, DeclarationModifiers modifiers) + => WithModifiers(declaration, modifiers); + + internal abstract TSyntaxNode WithModifiers(TSyntaxNode declaration, DeclarationModifiers modifiers) + where TSyntaxNode : SyntaxNode; /// /// Gets the for the declaration. diff --git a/src/Workspaces/Core/Portable/Editing/TypeConstraintKind.cs b/src/Workspaces/Core/Portable/Editing/TypeConstraintKind.cs index b0e6ce0af06f5..ae9d8052b6fd5 100644 --- a/src/Workspaces/Core/Portable/Editing/TypeConstraintKind.cs +++ b/src/Workspaces/Core/Portable/Editing/TypeConstraintKind.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; namespace Microsoft.CodeAnalysis.Editing; diff --git a/src/Workspaces/Core/Portable/ErrorReporting/InfoBarUI.cs b/src/Workspaces/Core/Portable/ErrorReporting/InfoBarUI.cs index 4e5761e954958..280a5a0f106cd 100644 --- a/src/Workspaces/Core/Portable/ErrorReporting/InfoBarUI.cs +++ b/src/Workspaces/Core/Portable/ErrorReporting/InfoBarUI.cs @@ -4,7 +4,6 @@ using System; using System.Diagnostics.CodeAnalysis; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ErrorReporting; diff --git a/src/Workspaces/Core/Portable/ExternalAccess/Pythia/Api/PythiaObjectPool.cs b/src/Workspaces/Core/Portable/ExternalAccess/Pythia/Api/PythiaObjectPool.cs index 548cc97efa0e4..25e40508b6523 100644 --- a/src/Workspaces/Core/Portable/ExternalAccess/Pythia/Api/PythiaObjectPool.cs +++ b/src/Workspaces/Core/Portable/ExternalAccess/Pythia/Api/PythiaObjectPool.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using Microsoft.CodeAnalysis.PooledObjects; diff --git a/src/Workspaces/Core/Portable/ExternalAccess/Pythia/Api/PythiaSyntaxFactsServiceWrapper.cs b/src/Workspaces/Core/Portable/ExternalAccess/Pythia/Api/PythiaSyntaxFactsServiceWrapper.cs index ce7f9820598d6..fbbb622fdce39 100644 --- a/src/Workspaces/Core/Portable/ExternalAccess/Pythia/Api/PythiaSyntaxFactsServiceWrapper.cs +++ b/src/Workspaces/Core/Portable/ExternalAccess/Pythia/Api/PythiaSyntaxFactsServiceWrapper.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Workspaces/Core/Portable/ExternalAccess/UnitTesting/Api/UnitTestingFatalErrorAccessor.cs b/src/Workspaces/Core/Portable/ExternalAccess/UnitTesting/Api/UnitTestingFatalErrorAccessor.cs index ab84ab37acbf9..c49ee8aa59eba 100644 --- a/src/Workspaces/Core/Portable/ExternalAccess/UnitTesting/Api/UnitTestingFatalErrorAccessor.cs +++ b/src/Workspaces/Core/Portable/ExternalAccess/UnitTesting/Api/UnitTestingFatalErrorAccessor.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.ErrorReporting; diff --git a/src/Workspaces/Core/Portable/ExternalAccess/VSTypeScript/Api/TaskExtensions.cs b/src/Workspaces/Core/Portable/ExternalAccess/VSTypeScript/Api/TaskExtensions.cs new file mode 100644 index 0000000000000..c1cb797b3f77e --- /dev/null +++ b/src/Workspaces/Core/Portable/ExternalAccess/VSTypeScript/Api/TaskExtensions.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Shared.TestHooks; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api; + +internal static class TaskExtensions +{ +#pragma warning disable VSTHRD200 // Use "Async" suffix for async methods + public static Task CompletesAsyncOperation(this Task task, VSTypeScriptAsyncToken asyncToken) +#pragma warning restore VSTHRD200 + => task.CompletesAsyncOperation(asyncToken.UnderlyingObject); +} diff --git a/src/Workspaces/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptAsyncToken.cs b/src/Workspaces/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptAsyncToken.cs new file mode 100644 index 0000000000000..68cc0882a1bae --- /dev/null +++ b/src/Workspaces/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptAsyncToken.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 Microsoft.CodeAnalysis.Shared.TestHooks; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api; + +internal sealed class VSTypeScriptAsyncToken(IAsyncToken underlyingObject) : IDisposable +{ + internal IAsyncToken UnderlyingObject + => underlyingObject; + + public void Dispose() + => UnderlyingObject.Dispose(); +} diff --git a/src/Workspaces/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptAsynchronousOperationListener.cs b/src/Workspaces/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptAsynchronousOperationListener.cs new file mode 100644 index 0000000000000..f562e164a606a --- /dev/null +++ b/src/Workspaces/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptAsynchronousOperationListener.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.CompilerServices; +using Microsoft.CodeAnalysis.Shared.TestHooks; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api; + +internal readonly struct VSTypeScriptAsynchronousOperationListener(IAsynchronousOperationListener underlyingObject) +{ + public VSTypeScriptAsyncToken BeginAsyncOperation(string name, object? tag = null, [CallerFilePath] string filePath = "", [CallerLineNumber] int lineNumber = 0) + => new(underlyingObject.BeginAsyncOperation(name, tag, filePath, lineNumber)); +} diff --git a/src/Workspaces/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptAsynchronousOperationListenerProvider.cs b/src/Workspaces/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptAsynchronousOperationListenerProvider.cs new file mode 100644 index 0000000000000..523716898c691 --- /dev/null +++ b/src/Workspaces/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptAsynchronousOperationListenerProvider.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Shared.TestHooks; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api; + +[Shared] +[Export(typeof(VSTypeScriptAsynchronousOperationListenerProvider))] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class VSTypeScriptAsynchronousOperationListenerProvider( + IAsynchronousOperationListenerProvider provider) +{ + public VSTypeScriptAsynchronousOperationListener GetListener(string featureName) + => new(provider.GetListener(featureName)); +} diff --git a/src/Workspaces/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptFeatureAttribute.cs b/src/Workspaces/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptFeatureAttribute.cs new file mode 100644 index 0000000000000..8c2ee1e25ba90 --- /dev/null +++ b/src/Workspaces/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptFeatureAttribute.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Shared.TestHooks; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api; + +internal static class VSTypeScriptFeatureAttribute +{ + public const string RenameTracking = FeatureAttribute.RenameTracking; + public const string Snippets = FeatureAttribute.Snippets; + public const string Workspace = FeatureAttribute.Workspace; + public const string SolutionCrawlerLegacy = FeatureAttribute.SolutionCrawlerLegacy; +} diff --git a/src/Workspaces/Core/Portable/ExtractMethod/ExtractMethodOptions.cs b/src/Workspaces/Core/Portable/ExtractMethod/ExtractMethodOptions.cs index 2d715264d7ef6..def790ba9bc76 100644 --- a/src/Workspaces/Core/Portable/ExtractMethod/ExtractMethodOptions.cs +++ b/src/Workspaces/Core/Portable/ExtractMethod/ExtractMethodOptions.cs @@ -6,7 +6,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.AddImport; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Formatting; diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_ProjectIndex.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_ProjectIndex.cs index 083c3d0937a87..8d6fec248ec0e 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_ProjectIndex.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_ProjectIndex.cs @@ -6,6 +6,7 @@ using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Storage; using Roslyn.Utilities; @@ -21,7 +22,16 @@ private sealed class ProjectIndex( MultiDictionary delegates, MultiDictionary namedTypes) { - private static readonly ConditionalWeakTable> s_projectToIndex = new(); + /// + /// We cache the project instance per . This allows us to reuse it over a wide set of + /// changes (for example, changing completely unrelated projects that a particular project doesn't depend on). + /// However, doesn't change even when certain things change that will create a + /// substantively different . For example, if the for the project changes, we'll still have the same project state. + /// As such, we store the of the project as well, ensuring that if anything in it or its + /// dependencies changes, we recompute the index. + /// + private static readonly ConditionalWeakTable lazyProjectIndex)>> s_projectToIndex = new(); public readonly MultiDictionary ClassesAndRecordsThatMayDeriveFromSystemObject = classesAndRecordsThatMayDeriveFromSystemObject; public readonly MultiDictionary ValueTypes = valueTypes; @@ -29,18 +39,29 @@ private sealed class ProjectIndex( public readonly MultiDictionary Delegates = delegates; public readonly MultiDictionary NamedTypes = namedTypes; - public static Task GetIndexAsync( + public static async Task GetIndexAsync( Project project, CancellationToken cancellationToken) { - if (!s_projectToIndex.TryGetValue(project.State, out var lazyIndex)) + // Use the checksum of the project. That way if its state *or* SG info changes, we compute a new index with + // accurate information in it. + var checksum = await project.GetDiagnosticChecksumAsync(cancellationToken).ConfigureAwait(false); + if (!s_projectToIndex.TryGetValue(project.State, out var tuple) || + tuple.Value.checksum != checksum) { - lazyIndex = s_projectToIndex.GetValue( - project.State, p => AsyncLazy.Create( - static (project, c) => CreateIndexAsync(project, c), - project)); + tuple = new((checksum, AsyncLazy.Create(CreateIndexAsync, project))); + +#if NET + s_projectToIndex.AddOrUpdate(project.State, tuple); +#else + // Best effort try to update the map with the new data. + s_projectToIndex.Remove(project.State); + // Note: intentionally ignore the return value here. We want to use the value we've computed even if + // another thread beats us to adding things here. + _ = s_projectToIndex.GetValue(project.State, _ => tuple); +#endif } - return lazyIndex.GetValueAsync(cancellationToken); + return await tuple.Value.lazyProjectIndex.GetValueAsync(cancellationToken).ConfigureAwait(false); } private static async Task CreateIndexAsync(Project project, CancellationToken cancellationToken) diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.SymbolSet.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.SymbolSet.cs index 76c2b5f4e9090..d5458c1696ae9 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.SymbolSet.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.SymbolSet.cs @@ -8,7 +8,6 @@ using Microsoft.CodeAnalysis.FindSymbols.Finders; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.FindSymbols; diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.cs index ee82ecb3d4526..1652e97e44258 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractMethodOrPropertyOrEventSymbolReferenceFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractMethodOrPropertyOrEventSymbolReferenceFinder.cs index e9944e7ff30c0..d6be466eec277 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractMethodOrPropertyOrEventSymbolReferenceFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractMethodOrPropertyOrEventSymbolReferenceFinder.cs @@ -24,7 +24,7 @@ protected static ImmutableArray GetReferencedAccessorSymbols( // the only accessor method referenced in a foreach-statement is the .Current's // get-accessor - return symbols.CurrentProperty.GetMethod == null + return symbols.CurrentProperty?.GetMethod == null ? [] : [symbols.CurrentProperty.GetMethod]; } diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractTypeParameterSymbolReferenceFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractTypeParameterSymbolReferenceFinder.cs index b4f6514a4c740..7ce8df55a4d76 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractTypeParameterSymbolReferenceFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractTypeParameterSymbolReferenceFinder.cs @@ -7,7 +7,6 @@ using System.Threading; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.FindSymbols.Finders; diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ConstructorInitializerSymbolReferenceFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ConstructorInitializerSymbolReferenceFinder.cs index 1fcfdd74b8f02..85aef6b00770c 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ConstructorInitializerSymbolReferenceFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ConstructorInitializerSymbolReferenceFinder.cs @@ -5,11 +5,9 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.FindSymbols.Finders; @@ -31,8 +29,20 @@ protected override Task DetermineDocumentsToSearchAsync( return FindDocumentsAsync(project, documents, static async (document, name, cancellationToken) => { var index = await SyntaxTreeIndex.GetRequiredIndexAsync(document, cancellationToken).ConfigureAwait(false); + if (index.ContainsBaseConstructorInitializer) - return true; + { + // if we have `partial class C { ... : base(...) }` we have to assume it might be a match, as the base + // type reference might be in a another part of the partial in another file. + if (index.ContainsPartialClass) + return true; + + // Otherwise, if it doesn't have any partial types, ensure that the base type name is referenced in the + // same file. e.g. `partial class C : B { ... base(...) }`. This allows us to greatly filter down the + // number of matches, presuming that most inheriting types in a project are not themselves partial. + if (index.ProbablyContainsIdentifier(name)) + return true; + } if (index.ProbablyContainsIdentifier(name)) { diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ConstructorSymbolReferenceFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ConstructorSymbolReferenceFinder.cs index e7b4f0c98ed32..01ea7e24cdb94 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ConstructorSymbolReferenceFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ConstructorSymbolReferenceFinder.cs @@ -24,6 +24,27 @@ private ConstructorSymbolReferenceFinder() protected override bool CanFind(IMethodSymbol symbol) => symbol.MethodKind is MethodKind.Constructor or MethodKind.StaticConstructor; + protected override ValueTask> DetermineCascadedSymbolsAsync(IMethodSymbol symbol, Solution solution, FindReferencesSearchOptions options, CancellationToken cancellationToken) + { + if (symbol.MethodKind is MethodKind.Constructor) + { + return new(GetOtherPartsOfPartial(symbol)); + } + + return new([]); + } + + private static ImmutableArray GetOtherPartsOfPartial(IMethodSymbol symbol) + { + if (symbol.PartialDefinitionPart != null) + return [symbol.PartialDefinitionPart]; + + if (symbol.PartialImplementationPart != null) + return [symbol.PartialImplementationPart]; + + return []; + } + protected override Task> DetermineGlobalAliasesAsync(IMethodSymbol symbol, Project project, CancellationToken cancellationToken) { var containingType = symbol.ContainingType; diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/EventSymbolReferenceFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/EventSymbolReferenceFinder.cs index d0347dca087c1..e961f81af4f5c 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/EventSymbolReferenceFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/EventSymbolReferenceFinder.cs @@ -32,7 +32,18 @@ protected sealed override ValueTask> DetermineCascadedSy .WhereAsArray(n => symbol.Equals(n.AssociatedSymbol)) .CastArray(); - return new(backingFields.Concat(associatedNamedTypes)); + return new(GetOtherPartsOfPartial(symbol).Concat(backingFields).Concat(associatedNamedTypes)); + } + + private static ImmutableArray GetOtherPartsOfPartial(IEventSymbol symbol) + { + if (symbol.PartialDefinitionPart != null) + return [symbol.PartialDefinitionPart]; + + if (symbol.PartialImplementationPart != null) + return [symbol.PartialImplementationPart]; + + return []; } protected sealed override async Task DetermineDocumentsToSearchAsync( diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ExplicitConversionSymbolReferenceFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ExplicitConversionSymbolReferenceFinder.cs index 647a4cb6565e2..379f2f543d2bd 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ExplicitConversionSymbolReferenceFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ExplicitConversionSymbolReferenceFinder.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.FindSymbols.Finders; diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/MethodTypeParameterSymbolReferenceFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/MethodTypeParameterSymbolReferenceFinder.cs index b5cad870099dc..f0150097e7a10 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/MethodTypeParameterSymbolReferenceFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/MethodTypeParameterSymbolReferenceFinder.cs @@ -8,7 +8,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Shared.Collections; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.FindSymbols.Finders; diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/PreprocessingSymbolReferenceFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/PreprocessingSymbolReferenceFinder.cs index 1ab72fbc61b13..676c22b84c25f 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/PreprocessingSymbolReferenceFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/PreprocessingSymbolReferenceFinder.cs @@ -7,7 +7,6 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.FindSymbols.Finders; diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/TypeParameterSymbolReferenceFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/TypeParameterSymbolReferenceFinder.cs index 6b1ffc51734be..27c7eddcdcd89 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/TypeParameterSymbolReferenceFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/TypeParameterSymbolReferenceFinder.cs @@ -32,6 +32,8 @@ protected override Task DetermineDocumentsToSearchAsync( // parameter has a different name in different parts that we won't find it. However, // this only happens in error situations. It is not legal in C# to use a different // name for a type parameter in different parts. - return FindDocumentsAsync(project, documents, processResult, processResultData, cancellationToken, symbol.Name, symbol.ContainingType.Name); + return symbol.ContainingType is { IsExtension: true, ContainingType.Name: var staticClassName } + ? FindDocumentsAsync(project, documents, processResult, processResultData, cancellationToken, symbol.Name, staticClassName) + : FindDocumentsAsync(project, documents, processResult, processResultData, cancellationToken, symbol.Name, symbol.ContainingType.Name); } } diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/MetadataUnifyingSymbolHashSet.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/MetadataUnifyingSymbolHashSet.cs index 7f31eb6cc5306..9d7bc98372cb6 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/MetadataUnifyingSymbolHashSet.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/MetadataUnifyingSymbolHashSet.cs @@ -3,11 +3,12 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; +using System.Diagnostics; using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.FindSymbols; -internal sealed class MetadataUnifyingSymbolHashSet : HashSet +internal sealed class MetadataUnifyingSymbolHashSet : HashSet, IPooled { private static readonly ObjectPool s_metadataUnifyingSymbolHashSetPool = new(() => []); @@ -15,12 +16,19 @@ public MetadataUnifyingSymbolHashSet() : base(MetadataUnifyingEquivalenceCompare { } - public static MetadataUnifyingSymbolHashSet AllocateFromPool() - => s_metadataUnifyingSymbolHashSetPool.Allocate(); + public static PooledDisposer GetInstance(out MetadataUnifyingSymbolHashSet instance) + { + instance = s_metadataUnifyingSymbolHashSetPool.Allocate(); + Debug.Assert(instance.Count == 0); + + return new PooledDisposer(instance); + } - public static void ClearAndFree(MetadataUnifyingSymbolHashSet set) + public void Free(bool discardLargeInstances) { - set.Clear(); - s_metadataUnifyingSymbolHashSetPool.Free(set); + // ignore discardLargeInstances as we don't limit our pooled hashset capacities + Clear(); + + s_metadataUnifyingSymbolHashSetPool.Free(this); } } diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/NoOpStreamingFindReferencesProgress.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/NoOpStreamingFindReferencesProgress.cs index 4095dec2e2f8e..697da28bdee54 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/NoOpStreamingFindReferencesProgress.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/NoOpStreamingFindReferencesProgress.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; diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/StreamingFindReferencesProgress.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/StreamingFindReferencesProgress.cs index 83667475722d8..92074d8deaa54 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/StreamingFindReferencesProgress.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/StreamingFindReferencesProgress.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; diff --git a/src/Workspaces/Core/Portable/FindSymbols/IStreamingFindReferencesProgress.cs b/src/Workspaces/Core/Portable/FindSymbols/IStreamingFindReferencesProgress.cs index b9ba9ac99f35f..1fffd8c2b258f 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/IStreamingFindReferencesProgress.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/IStreamingFindReferencesProgress.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Linq; diff --git a/src/Workspaces/Core/Portable/FindSymbols/ReferencedSymbol.cs b/src/Workspaces/Core/Portable/FindSymbols/ReferencedSymbol.cs index 45e5736b371ec..210d608fa30a3 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/ReferencedSymbol.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/ReferencedSymbol.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.Diagnostics; diff --git a/src/Workspaces/Core/Portable/FindSymbols/Shared/AbstractSyntaxIndex_Persistence.cs b/src/Workspaces/Core/Portable/FindSymbols/Shared/AbstractSyntaxIndex_Persistence.cs index 5b055b96423bd..c11f879bec1a9 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/Shared/AbstractSyntaxIndex_Persistence.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/Shared/AbstractSyntaxIndex_Persistence.cs @@ -23,7 +23,7 @@ internal abstract partial class AbstractSyntaxIndex /// that we will not try to read previously cached data from a prior version of roslyn with a different format and /// will instead regenerate all the indices with the new format. /// - private static readonly Checksum s_serializationFormatChecksum = CodeAnalysis.Checksum.Create("45"); + private static readonly Checksum s_serializationFormatChecksum = CodeAnalysis.Checksum.Create("46"); /// /// Cache of ParseOptions to a checksum for the contained diff --git a/src/Workspaces/Core/Portable/FindSymbols/StreamingProgressCollector.cs b/src/Workspaces/Core/Portable/FindSymbols/StreamingProgressCollector.cs index 5e5bd005202b1..f3735feaa8a5b 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/StreamingProgressCollector.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/StreamingProgressCollector.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.Immutable; diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder.FindReferencesServerCallback.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder.FindReferencesServerCallback.cs index 2e6e6f5a832f9..0359e6fadce0f 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder.FindReferencesServerCallback.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder.FindReferencesServerCallback.cs @@ -4,12 +4,10 @@ using System.Collections.Generic; using System.Collections.Immutable; -using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Remote; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.FindSymbols; diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/MetadataInfo.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/MetadataInfo.cs index cc875c63257e5..ff76b9b36a1ca 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/MetadataInfo.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/MetadataInfo.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.FindSymbols.SymbolTree; diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfoCacheService.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfoCacheService.cs index 79fc5f5b76625..cb4122d233d18 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfoCacheService.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfoCacheService.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.FindSymbols.SymbolTree; diff --git a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.ContextInfo.cs b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.ContextInfo.cs index 9a4229298e319..bd74857164f06 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.ContextInfo.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.ContextInfo.cs @@ -37,7 +37,8 @@ public ContextInfo( bool containsCollectionInitializer, bool containsAttribute, bool containsDirective, - bool containsPrimaryConstructorBaseType) + bool containsPrimaryConstructorBaseType, + bool containsPartialClass) : this(predefinedTypes, predefinedOperators, ConvertToContainingNodeFlag( containsForEachStatement, @@ -58,7 +59,8 @@ public ContextInfo( containsCollectionInitializer, containsAttribute, containsDirective, - containsPrimaryConstructorBaseType)) + containsPrimaryConstructorBaseType, + containsPartialClass)) { } @@ -88,7 +90,8 @@ private static ContainingNodes ConvertToContainingNodeFlag( bool containsCollectionInitializer, bool containsAttribute, bool containsDirective, - bool containsPrimaryConstructorBaseType) + bool containsPrimaryConstructorBaseType, + bool containsPartialClass) { var containingNodes = ContainingNodes.None; @@ -111,6 +114,7 @@ private static ContainingNodes ConvertToContainingNodeFlag( containingNodes |= containsAttribute ? ContainingNodes.ContainsAttribute : 0; containingNodes |= containsDirective ? ContainingNodes.ContainsDirective : 0; containingNodes |= containsPrimaryConstructorBaseType ? ContainingNodes.ContainsPrimaryConstructorBaseType : 0; + containingNodes |= containsPartialClass ? ContainingNodes.ContainsPartialClass : 0; return containingNodes; } @@ -136,6 +140,9 @@ public bool ContainsImplicitObjectCreation public bool ContainsLockStatement => (_containingNodes & ContainingNodes.ContainsLockStatement) == ContainingNodes.ContainsLockStatement; + public bool ContainsPartialClass + => (_containingNodes & ContainingNodes.ContainsPartialClass) == ContainingNodes.ContainsPartialClass; + public bool ContainsUsingStatement => (_containingNodes & ContainingNodes.ContainsUsingStatement) == ContainingNodes.ContainsUsingStatement; @@ -225,6 +232,7 @@ private enum ContainingNodes ContainsAttribute = 1 << 16, ContainsDirective = 1 << 17, ContainsPrimaryConstructorBaseType = 1 << 18, + ContainsPartialClass = 1 << 19, } } } diff --git a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Create.cs b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Create.cs index c0170cd52c5bb..6299181a4f5de 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Create.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Create.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; @@ -42,6 +41,7 @@ private static SyntaxTreeIndex CreateIndex( { var syntaxFacts = project.LanguageServices.GetRequiredService(); var ignoreCase = !syntaxFacts.IsCaseSensitive; + var partialKeywordKind = syntaxFacts.SyntaxKinds.PartialKeyword; var isCaseSensitive = !ignoreCase; GetIdentifierSet(ignoreCase, out var identifiers, out var escapedIdentifiers); @@ -75,6 +75,7 @@ private static SyntaxTreeIndex CreateIndex( var containsAttribute = false; var containsDirective = root.ContainsDirectives; var containsPrimaryConstructorBaseType = false; + var containsPartialClass = false; var predefinedTypes = (int)PredefinedType.None; var predefinedOperators = (int)PredefinedOperator.None; @@ -107,6 +108,7 @@ private static SyntaxTreeIndex CreateIndex( containsCollectionInitializer = containsCollectionInitializer || syntaxFacts.IsObjectCollectionInitializer(node); containsAttribute = containsAttribute || syntaxFacts.IsAttribute(node); containsPrimaryConstructorBaseType = containsPrimaryConstructorBaseType || syntaxFacts.IsPrimaryConstructorBaseType(node); + containsPartialClass = containsPartialClass || IsPartialClass(node); TryAddAliasInfo(syntaxFacts, ref aliasInfo, node); @@ -201,7 +203,8 @@ private static SyntaxTreeIndex CreateIndex( containsCollectionInitializer, containsAttribute, containsDirective, - containsPrimaryConstructorBaseType), + containsPrimaryConstructorBaseType, + containsPartialClass), aliasInfo, interceptsLocationInfo); } @@ -211,6 +214,21 @@ private static SyntaxTreeIndex CreateIndex( StringLiteralHashSetPool.ClearAndFree(stringLiterals); LongLiteralHashSetPool.ClearAndFree(longLiterals); } + + bool IsPartialClass(SyntaxNode node) + { + if (!syntaxFacts.IsClassDeclaration(node)) + return false; + + var modifiers = syntaxFacts.GetModifiers(node); + foreach (var modifier in modifiers) + { + if (modifier.RawKind == partialKeywordKind) + return true; + } + + return false; + } } private static bool IsGlobalSuppressMessageAttribute(ISyntaxFactsService syntaxFacts, SyntaxNode node) diff --git a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Forwarders.cs b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Forwarders.cs index 1ba1ff4d09862..7d4ff66ba23c7 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Forwarders.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Forwarders.cs @@ -32,6 +32,7 @@ internal sealed partial class SyntaxTreeIndex public bool ContainsImplicitObjectCreation => _contextInfo.ContainsImplicitObjectCreation; public bool ContainsIndexerMemberCref => _contextInfo.ContainsIndexerMemberCref; public bool ContainsLockStatement => _contextInfo.ContainsLockStatement; + public bool ContainsPartialClass => _contextInfo.ContainsPartialClass; public bool ContainsQueryExpression => _contextInfo.ContainsQueryExpression; public bool ContainsThisConstructorInitializer => _contextInfo.ContainsThisConstructorInitializer; public bool ContainsTupleExpressionOrTupleType => _contextInfo.ContainsTupleExpressionOrTupleType; diff --git a/src/Workspaces/Core/Portable/Formatting/AbstractFormattingService.cs b/src/Workspaces/Core/Portable/Formatting/AbstractFormattingService.cs index e56e065978dd7..760a5b61de539 100644 --- a/src/Workspaces/Core/Portable/Formatting/AbstractFormattingService.cs +++ b/src/Workspaces/Core/Portable/Formatting/AbstractFormattingService.cs @@ -6,7 +6,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Formatting; diff --git a/src/Workspaces/Core/Portable/Log/EmptyLogger.cs b/src/Workspaces/Core/Portable/Log/EmptyLogger.cs index 2ab26a36b0288..7a118d9eae121 100644 --- a/src/Workspaces/Core/Portable/Log/EmptyLogger.cs +++ b/src/Workspaces/Core/Portable/Log/EmptyLogger.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; namespace Microsoft.CodeAnalysis.Internal.Log; diff --git a/src/Workspaces/Core/Portable/Log/EtwLogger.cs b/src/Workspaces/Core/Portable/Log/EtwLogger.cs index 898ca25dc3110..fef6bf415270b 100644 --- a/src/Workspaces/Core/Portable/Log/EtwLogger.cs +++ b/src/Workspaces/Core/Portable/Log/EtwLogger.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.Diagnostics.Tracing; using System.Threading; diff --git a/src/Workspaces/Core/Portable/Log/IErrorLogger.cs b/src/Workspaces/Core/Portable/Log/IErrorLogger.cs index 73100b5a12b39..79325d0824dfe 100644 --- a/src/Workspaces/Core/Portable/Log/IErrorLogger.cs +++ b/src/Workspaces/Core/Portable/Log/IErrorLogger.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.Host; diff --git a/src/Workspaces/Core/Portable/Log/InteractionClass.cs b/src/Workspaces/Core/Portable/Log/InteractionClass.cs index fc0abeb2fe404..065a6f1d11e2a 100644 --- a/src/Workspaces/Core/Portable/Log/InteractionClass.cs +++ b/src/Workspaces/Core/Portable/Log/InteractionClass.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; namespace Microsoft.CodeAnalysis.Internal.Log; diff --git a/src/Workspaces/Core/Portable/Log/WorkspaceErrorLogger.cs b/src/Workspaces/Core/Portable/Log/WorkspaceErrorLogger.cs index 597435b4dba98..c004f8e8ae079 100644 --- a/src/Workspaces/Core/Portable/Log/WorkspaceErrorLogger.cs +++ b/src/Workspaces/Core/Portable/Log/WorkspaceErrorLogger.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.Composition; using Microsoft.CodeAnalysis.Host.Mef; diff --git a/src/Workspaces/Core/Portable/Microsoft.CodeAnalysis.Workspaces.csproj b/src/Workspaces/Core/Portable/Microsoft.CodeAnalysis.Workspaces.csproj index 7ddf1ce681c17..e336872608f94 100644 --- a/src/Workspaces/Core/Portable/Microsoft.CodeAnalysis.Workspaces.csproj +++ b/src/Workspaces/Core/Portable/Microsoft.CodeAnalysis.Workspaces.csproj @@ -37,9 +37,10 @@ - + + @@ -123,6 +124,7 @@ + @@ -133,6 +135,7 @@ + @@ -146,6 +149,7 @@ + @@ -164,5 +168,7 @@ + + diff --git a/src/Workspaces/Core/Portable/Notification/AbstractGlobalOperationNotificationService.cs b/src/Workspaces/Core/Portable/Notification/AbstractGlobalOperationNotificationService.cs index 1256b2fa12588..c8a88b0ac843d 100644 --- a/src/Workspaces/Core/Portable/Notification/AbstractGlobalOperationNotificationService.cs +++ b/src/Workspaces/Core/Portable/Notification/AbstractGlobalOperationNotificationService.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Notification; diff --git a/src/Workspaces/Core/Portable/Options/IGlobalOptionService.cs b/src/Workspaces/Core/Portable/Options/IGlobalOptionService.cs index b5aaff7a08579..66b0223340ad5 100644 --- a/src/Workspaces/Core/Portable/Options/IGlobalOptionService.cs +++ b/src/Workspaces/Core/Portable/Options/IGlobalOptionService.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. -using System; using System.Collections.Generic; using System.Collections.Immutable; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Options; diff --git a/src/Workspaces/Core/Portable/Options/OptionKey.cs b/src/Workspaces/Core/Portable/Options/OptionKey.cs index f0e20986fe191..d35c100b36977 100644 --- a/src/Workspaces/Core/Portable/Options/OptionKey.cs +++ b/src/Workspaces/Core/Portable/Options/OptionKey.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Options; diff --git a/src/Workspaces/Core/Portable/Options/OptionSet.cs b/src/Workspaces/Core/Portable/Options/OptionSet.cs index fa85f4bd826ad..77b8e5c7f7993 100644 --- a/src/Workspaces/Core/Portable/Options/OptionSet.cs +++ b/src/Workspaces/Core/Portable/Options/OptionSet.cs @@ -4,7 +4,6 @@ using System.Diagnostics; using Microsoft.CodeAnalysis.CodeStyle; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Options; diff --git a/src/Workspaces/Core/Portable/PatternMatching/PatternMatchKind.cs b/src/Workspaces/Core/Portable/PatternMatching/PatternMatchKind.cs index d5fefcb9143b4..19b08a1276974 100644 --- a/src/Workspaces/Core/Portable/PatternMatching/PatternMatchKind.cs +++ b/src/Workspaces/Core/Portable/PatternMatching/PatternMatchKind.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 Roslyn.Utilities; namespace Microsoft.CodeAnalysis.PatternMatching; diff --git a/src/Workspaces/Core/Portable/PatternMatching/PatternMatcher.PatternSegment.cs b/src/Workspaces/Core/Portable/PatternMatching/PatternMatcher.PatternSegment.cs index 1b25dd803c39b..c485e69071993 100644 --- a/src/Workspaces/Core/Portable/PatternMatching/PatternMatcher.PatternSegment.cs +++ b/src/Workspaces/Core/Portable/PatternMatching/PatternMatcher.PatternSegment.cs @@ -2,10 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.PatternMatching; diff --git a/src/Workspaces/Core/Portable/PatternMatching/PatternMatcher.TextChunk.cs b/src/Workspaces/Core/Portable/PatternMatching/PatternMatcher.TextChunk.cs index 01fbfb1ab3bef..d00c5e73b1ee2 100644 --- a/src/Workspaces/Core/Portable/PatternMatching/PatternMatcher.TextChunk.cs +++ b/src/Workspaces/Core/Portable/PatternMatching/PatternMatcher.TextChunk.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.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Utilities; diff --git a/src/Workspaces/Core/Portable/PublicAPI.Shipped.txt b/src/Workspaces/Core/Portable/PublicAPI.Shipped.txt index 1c3695ccc2456..aaa4e6351c7fa 100644 --- a/src/Workspaces/Core/Portable/PublicAPI.Shipped.txt +++ b/src/Workspaces/Core/Portable/PublicAPI.Shipped.txt @@ -37,8 +37,6 @@ abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.AwaitExpression(Microsof abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.BaseExpression() -> Microsoft.CodeAnalysis.SyntaxNode abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.BitwiseAndExpression(Microsoft.CodeAnalysis.SyntaxNode left, Microsoft.CodeAnalysis.SyntaxNode right) -> Microsoft.CodeAnalysis.SyntaxNode abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.BitwiseNotExpression(Microsoft.CodeAnalysis.SyntaxNode operand) -> Microsoft.CodeAnalysis.SyntaxNode -abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.BitwiseOrExpression(Microsoft.CodeAnalysis.SyntaxNode left, Microsoft.CodeAnalysis.SyntaxNode right) -> Microsoft.CodeAnalysis.SyntaxNode -abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.CastExpression(Microsoft.CodeAnalysis.SyntaxNode type, Microsoft.CodeAnalysis.SyntaxNode expression) -> Microsoft.CodeAnalysis.SyntaxNode abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.CatchClause(Microsoft.CodeAnalysis.SyntaxNode type, string identifier, System.Collections.Generic.IEnumerable statements) -> Microsoft.CodeAnalysis.SyntaxNode abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.ClearTrivia(TNode node) -> TNode abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.CoalesceExpression(Microsoft.CodeAnalysis.SyntaxNode left, Microsoft.CodeAnalysis.SyntaxNode right) -> Microsoft.CodeAnalysis.SyntaxNode @@ -46,10 +44,7 @@ abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.CompilationUnit(System.C abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.ConditionalAccessExpression(Microsoft.CodeAnalysis.SyntaxNode expression, Microsoft.CodeAnalysis.SyntaxNode whenNotNull) -> Microsoft.CodeAnalysis.SyntaxNode abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.ConditionalExpression(Microsoft.CodeAnalysis.SyntaxNode condition, Microsoft.CodeAnalysis.SyntaxNode whenTrue, Microsoft.CodeAnalysis.SyntaxNode whenFalse) -> Microsoft.CodeAnalysis.SyntaxNode abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.ConstructorDeclaration(string containingTypeName = null, System.Collections.Generic.IEnumerable parameters = null, Microsoft.CodeAnalysis.Accessibility accessibility = Microsoft.CodeAnalysis.Accessibility.NotApplicable, Microsoft.CodeAnalysis.Editing.DeclarationModifiers modifiers = default(Microsoft.CodeAnalysis.Editing.DeclarationModifiers), System.Collections.Generic.IEnumerable baseConstructorArguments = null, System.Collections.Generic.IEnumerable statements = null) -> Microsoft.CodeAnalysis.SyntaxNode -abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.ConvertExpression(Microsoft.CodeAnalysis.SyntaxNode type, Microsoft.CodeAnalysis.SyntaxNode expression) -> Microsoft.CodeAnalysis.SyntaxNode abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.CustomEventDeclaration(string name, Microsoft.CodeAnalysis.SyntaxNode type, Microsoft.CodeAnalysis.Accessibility accessibility = Microsoft.CodeAnalysis.Accessibility.NotApplicable, Microsoft.CodeAnalysis.Editing.DeclarationModifiers modifiers = default(Microsoft.CodeAnalysis.Editing.DeclarationModifiers), System.Collections.Generic.IEnumerable parameters = null, System.Collections.Generic.IEnumerable addAccessorStatements = null, System.Collections.Generic.IEnumerable removeAccessorStatements = null) -> Microsoft.CodeAnalysis.SyntaxNode -abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.DefaultExpression(Microsoft.CodeAnalysis.ITypeSymbol type) -> Microsoft.CodeAnalysis.SyntaxNode -abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.DefaultExpression(Microsoft.CodeAnalysis.SyntaxNode type) -> Microsoft.CodeAnalysis.SyntaxNode abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.DefaultSwitchSection(System.Collections.Generic.IEnumerable statements) -> Microsoft.CodeAnalysis.SyntaxNode abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.DivideExpression(Microsoft.CodeAnalysis.SyntaxNode left, Microsoft.CodeAnalysis.SyntaxNode right) -> Microsoft.CodeAnalysis.SyntaxNode abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.ElementAccessExpression(Microsoft.CodeAnalysis.SyntaxNode expression, System.Collections.Generic.IEnumerable arguments) -> Microsoft.CodeAnalysis.SyntaxNode @@ -82,7 +77,6 @@ abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.GetSwitchSections(Micros abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.GetType(Microsoft.CodeAnalysis.SyntaxNode declaration) -> Microsoft.CodeAnalysis.SyntaxNode abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.GreaterThanExpression(Microsoft.CodeAnalysis.SyntaxNode left, Microsoft.CodeAnalysis.SyntaxNode right) -> Microsoft.CodeAnalysis.SyntaxNode abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.GreaterThanOrEqualExpression(Microsoft.CodeAnalysis.SyntaxNode left, Microsoft.CodeAnalysis.SyntaxNode right) -> Microsoft.CodeAnalysis.SyntaxNode -abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.IdentifierName(string identifier) -> Microsoft.CodeAnalysis.SyntaxNode abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.IfStatement(Microsoft.CodeAnalysis.SyntaxNode condition, System.Collections.Generic.IEnumerable trueStatements, System.Collections.Generic.IEnumerable falseStatements = null) -> Microsoft.CodeAnalysis.SyntaxNode abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.IndexerDeclaration(System.Collections.Generic.IEnumerable parameters, Microsoft.CodeAnalysis.SyntaxNode type, Microsoft.CodeAnalysis.Accessibility accessibility = Microsoft.CodeAnalysis.Accessibility.NotApplicable, Microsoft.CodeAnalysis.Editing.DeclarationModifiers modifiers = default(Microsoft.CodeAnalysis.Editing.DeclarationModifiers), System.Collections.Generic.IEnumerable getAccessorStatements = null, System.Collections.Generic.IEnumerable setAccessorStatements = null) -> Microsoft.CodeAnalysis.SyntaxNode abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.InsertAccessors(Microsoft.CodeAnalysis.SyntaxNode declaration, int index, System.Collections.Generic.IEnumerable accessors) -> Microsoft.CodeAnalysis.SyntaxNode @@ -444,7 +438,6 @@ Microsoft.CodeAnalysis.CodeStyle.CodeStyleOption.ToXElement() -> System.Xml.L Microsoft.CodeAnalysis.CodeStyle.CodeStyleOption.Value.get -> T Microsoft.CodeAnalysis.CodeStyle.CodeStyleOption.Value.set -> void Microsoft.CodeAnalysis.CodeStyle.CodeStyleOptions -Microsoft.CodeAnalysis.CodeStyle.CodeStyleOptions.CodeStyleOptions() -> void Microsoft.CodeAnalysis.CodeStyle.NotificationOption Microsoft.CodeAnalysis.CodeStyle.NotificationOption.Name.get -> string Microsoft.CodeAnalysis.CodeStyle.NotificationOption.Name.set -> void @@ -457,7 +450,9 @@ Microsoft.CodeAnalysis.CompilationOutputInfo Microsoft.CodeAnalysis.CompilationOutputInfo.AssemblyPath.get -> string Microsoft.CodeAnalysis.CompilationOutputInfo.CompilationOutputInfo() -> void Microsoft.CodeAnalysis.CompilationOutputInfo.Equals(Microsoft.CodeAnalysis.CompilationOutputInfo other) -> bool +Microsoft.CodeAnalysis.CompilationOutputInfo.GeneratedFilesOutputDirectory.get -> string Microsoft.CodeAnalysis.CompilationOutputInfo.WithAssemblyPath(string path) -> Microsoft.CodeAnalysis.CompilationOutputInfo +Microsoft.CodeAnalysis.CompilationOutputInfo.WithGeneratedFilesOutputDirectory(string path) -> Microsoft.CodeAnalysis.CompilationOutputInfo Microsoft.CodeAnalysis.Differencing.Edit Microsoft.CodeAnalysis.Differencing.Edit.Edit() -> void Microsoft.CodeAnalysis.Differencing.Edit.Equals(Microsoft.CodeAnalysis.Differencing.Edit other) -> bool @@ -708,14 +703,19 @@ Microsoft.CodeAnalysis.Editing.SyntaxGenerator.Attribute(Microsoft.CodeAnalysis. Microsoft.CodeAnalysis.Editing.SyntaxGenerator.Attribute(string name, params Microsoft.CodeAnalysis.SyntaxNode[] attributeArguments) -> Microsoft.CodeAnalysis.SyntaxNode Microsoft.CodeAnalysis.Editing.SyntaxGenerator.Attribute(string name, System.Collections.Generic.IEnumerable attributeArguments = null) -> Microsoft.CodeAnalysis.SyntaxNode Microsoft.CodeAnalysis.Editing.SyntaxGenerator.AttributeArgument(Microsoft.CodeAnalysis.SyntaxNode expression) -> Microsoft.CodeAnalysis.SyntaxNode +Microsoft.CodeAnalysis.Editing.SyntaxGenerator.BitwiseOrExpression(Microsoft.CodeAnalysis.SyntaxNode left, Microsoft.CodeAnalysis.SyntaxNode right) -> Microsoft.CodeAnalysis.SyntaxNode Microsoft.CodeAnalysis.Editing.SyntaxGenerator.CastExpression(Microsoft.CodeAnalysis.ITypeSymbol type, Microsoft.CodeAnalysis.SyntaxNode expression) -> Microsoft.CodeAnalysis.SyntaxNode +Microsoft.CodeAnalysis.Editing.SyntaxGenerator.CastExpression(Microsoft.CodeAnalysis.SyntaxNode type, Microsoft.CodeAnalysis.SyntaxNode expression) -> Microsoft.CodeAnalysis.SyntaxNode Microsoft.CodeAnalysis.Editing.SyntaxGenerator.CatchClause(Microsoft.CodeAnalysis.ITypeSymbol type, string identifier, System.Collections.Generic.IEnumerable statements) -> Microsoft.CodeAnalysis.SyntaxNode Microsoft.CodeAnalysis.Editing.SyntaxGenerator.ClassDeclaration(string name, System.Collections.Generic.IEnumerable typeParameters = null, Microsoft.CodeAnalysis.Accessibility accessibility = Microsoft.CodeAnalysis.Accessibility.NotApplicable, Microsoft.CodeAnalysis.Editing.DeclarationModifiers modifiers = default(Microsoft.CodeAnalysis.Editing.DeclarationModifiers), Microsoft.CodeAnalysis.SyntaxNode baseType = null, System.Collections.Generic.IEnumerable interfaceTypes = null, System.Collections.Generic.IEnumerable members = null) -> Microsoft.CodeAnalysis.SyntaxNode Microsoft.CodeAnalysis.Editing.SyntaxGenerator.CompilationUnit(params Microsoft.CodeAnalysis.SyntaxNode[] declarations) -> Microsoft.CodeAnalysis.SyntaxNode Microsoft.CodeAnalysis.Editing.SyntaxGenerator.ConstructorDeclaration(Microsoft.CodeAnalysis.IMethodSymbol constructorMethod, System.Collections.Generic.IEnumerable baseConstructorArguments = null, System.Collections.Generic.IEnumerable statements = null) -> Microsoft.CodeAnalysis.SyntaxNode Microsoft.CodeAnalysis.Editing.SyntaxGenerator.ConvertExpression(Microsoft.CodeAnalysis.ITypeSymbol type, Microsoft.CodeAnalysis.SyntaxNode expression) -> Microsoft.CodeAnalysis.SyntaxNode +Microsoft.CodeAnalysis.Editing.SyntaxGenerator.ConvertExpression(Microsoft.CodeAnalysis.SyntaxNode type, Microsoft.CodeAnalysis.SyntaxNode expression) -> Microsoft.CodeAnalysis.SyntaxNode Microsoft.CodeAnalysis.Editing.SyntaxGenerator.CustomEventDeclaration(Microsoft.CodeAnalysis.IEventSymbol symbol, System.Collections.Generic.IEnumerable addAccessorStatements = null, System.Collections.Generic.IEnumerable removeAccessorStatements = null) -> Microsoft.CodeAnalysis.SyntaxNode Microsoft.CodeAnalysis.Editing.SyntaxGenerator.Declaration(Microsoft.CodeAnalysis.ISymbol symbol) -> Microsoft.CodeAnalysis.SyntaxNode +Microsoft.CodeAnalysis.Editing.SyntaxGenerator.DefaultExpression(Microsoft.CodeAnalysis.ITypeSymbol type) -> Microsoft.CodeAnalysis.SyntaxNode +Microsoft.CodeAnalysis.Editing.SyntaxGenerator.DefaultExpression(Microsoft.CodeAnalysis.SyntaxNode type) -> Microsoft.CodeAnalysis.SyntaxNode Microsoft.CodeAnalysis.Editing.SyntaxGenerator.DelegateDeclaration(string name, System.Collections.Generic.IEnumerable parameters = null, System.Collections.Generic.IEnumerable typeParameters = null, Microsoft.CodeAnalysis.SyntaxNode returnType = null, Microsoft.CodeAnalysis.Accessibility accessibility = Microsoft.CodeAnalysis.Accessibility.NotApplicable, Microsoft.CodeAnalysis.Editing.DeclarationModifiers modifiers = default(Microsoft.CodeAnalysis.Editing.DeclarationModifiers)) -> Microsoft.CodeAnalysis.SyntaxNode Microsoft.CodeAnalysis.Editing.SyntaxGenerator.DottedName(string dottedName) -> Microsoft.CodeAnalysis.SyntaxNode Microsoft.CodeAnalysis.Editing.SyntaxGenerator.ElementAccessExpression(Microsoft.CodeAnalysis.SyntaxNode expression, params Microsoft.CodeAnalysis.SyntaxNode[] arguments) -> Microsoft.CodeAnalysis.SyntaxNode @@ -730,6 +730,7 @@ Microsoft.CodeAnalysis.Editing.SyntaxGenerator.GenericName(string identifier, Sy Microsoft.CodeAnalysis.Editing.SyntaxGenerator.GetAccessor(Microsoft.CodeAnalysis.SyntaxNode declaration, Microsoft.CodeAnalysis.Editing.DeclarationKind kind) -> Microsoft.CodeAnalysis.SyntaxNode Microsoft.CodeAnalysis.Editing.SyntaxGenerator.GetDeclaration(Microsoft.CodeAnalysis.SyntaxNode node) -> Microsoft.CodeAnalysis.SyntaxNode Microsoft.CodeAnalysis.Editing.SyntaxGenerator.GetDeclaration(Microsoft.CodeAnalysis.SyntaxNode node, Microsoft.CodeAnalysis.Editing.DeclarationKind kind) -> Microsoft.CodeAnalysis.SyntaxNode +Microsoft.CodeAnalysis.Editing.SyntaxGenerator.IdentifierName(string identifier) -> Microsoft.CodeAnalysis.SyntaxNode Microsoft.CodeAnalysis.Editing.SyntaxGenerator.IfStatement(Microsoft.CodeAnalysis.SyntaxNode condition, System.Collections.Generic.IEnumerable trueStatements, Microsoft.CodeAnalysis.SyntaxNode falseStatement) -> Microsoft.CodeAnalysis.SyntaxNode Microsoft.CodeAnalysis.Editing.SyntaxGenerator.IndexerDeclaration(Microsoft.CodeAnalysis.IPropertySymbol indexer, System.Collections.Generic.IEnumerable getAccessorStatements = null, System.Collections.Generic.IEnumerable setAccessorStatements = null) -> Microsoft.CodeAnalysis.SyntaxNode Microsoft.CodeAnalysis.Editing.SyntaxGenerator.IndexOf(System.Collections.Generic.IReadOnlyList list, T element) -> int @@ -744,6 +745,7 @@ Microsoft.CodeAnalysis.Editing.SyntaxGenerator.LambdaParameter(string identifier Microsoft.CodeAnalysis.Editing.SyntaxGenerator.LiteralExpression(object value) -> Microsoft.CodeAnalysis.SyntaxNode Microsoft.CodeAnalysis.Editing.SyntaxGenerator.LocalDeclarationStatement(Microsoft.CodeAnalysis.ITypeSymbol type, string name, Microsoft.CodeAnalysis.SyntaxNode initializer = null, bool isConst = false) -> Microsoft.CodeAnalysis.SyntaxNode Microsoft.CodeAnalysis.Editing.SyntaxGenerator.LocalDeclarationStatement(string name, Microsoft.CodeAnalysis.SyntaxNode initializer) -> Microsoft.CodeAnalysis.SyntaxNode +Microsoft.CodeAnalysis.Editing.SyntaxGenerator.MemberAccessExpression(Microsoft.CodeAnalysis.SyntaxNode expression, Microsoft.CodeAnalysis.SyntaxNode memberName) -> Microsoft.CodeAnalysis.SyntaxNode Microsoft.CodeAnalysis.Editing.SyntaxGenerator.MemberAccessExpression(Microsoft.CodeAnalysis.SyntaxNode expression, string memberName) -> Microsoft.CodeAnalysis.SyntaxNode Microsoft.CodeAnalysis.Editing.SyntaxGenerator.MethodDeclaration(Microsoft.CodeAnalysis.IMethodSymbol method, System.Collections.Generic.IEnumerable statements = null) -> Microsoft.CodeAnalysis.SyntaxNode Microsoft.CodeAnalysis.Editing.SyntaxGenerator.MethodDeclaration(string name, System.Collections.Generic.IEnumerable parameters = null, System.Collections.Generic.IEnumerable typeParameters = null, Microsoft.CodeAnalysis.SyntaxNode returnType = null, Microsoft.CodeAnalysis.Accessibility accessibility = Microsoft.CodeAnalysis.Accessibility.NotApplicable, Microsoft.CodeAnalysis.Editing.DeclarationModifiers modifiers = default(Microsoft.CodeAnalysis.Editing.DeclarationModifiers), System.Collections.Generic.IEnumerable statements = null) -> Microsoft.CodeAnalysis.SyntaxNode @@ -1007,6 +1009,7 @@ Microsoft.CodeAnalysis.Project.GetSemanticVersionAsync(System.Threading.Cancella Microsoft.CodeAnalysis.Project.GetSourceGeneratedDocumentAsync(Microsoft.CodeAnalysis.DocumentId documentId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask Microsoft.CodeAnalysis.Project.GetSourceGeneratedDocumentsAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask> Microsoft.CodeAnalysis.Project.HasDocuments.get -> bool +Microsoft.CodeAnalysis.Project.HostAnalyzerOptions.get -> Microsoft.CodeAnalysis.Diagnostics.AnalyzerOptions Microsoft.CodeAnalysis.Project.Id.get -> Microsoft.CodeAnalysis.ProjectId Microsoft.CodeAnalysis.Project.IsSubmission.get -> bool Microsoft.CodeAnalysis.Project.Language.get -> string @@ -1101,6 +1104,7 @@ Microsoft.CodeAnalysis.ProjectInfo.WithCompilationOutputInfo(in Microsoft.CodeAn Microsoft.CodeAnalysis.ProjectInfo.WithDefaultNamespace(string defaultNamespace) -> Microsoft.CodeAnalysis.ProjectInfo Microsoft.CodeAnalysis.ProjectInfo.WithDocuments(System.Collections.Generic.IEnumerable documents) -> Microsoft.CodeAnalysis.ProjectInfo Microsoft.CodeAnalysis.ProjectInfo.WithFilePath(string filePath) -> Microsoft.CodeAnalysis.ProjectInfo +Microsoft.CodeAnalysis.ProjectInfo.WithId(Microsoft.CodeAnalysis.ProjectId id) -> Microsoft.CodeAnalysis.ProjectInfo Microsoft.CodeAnalysis.ProjectInfo.WithMetadataReferences(System.Collections.Generic.IEnumerable metadataReferences) -> Microsoft.CodeAnalysis.ProjectInfo Microsoft.CodeAnalysis.ProjectInfo.WithName(string name) -> Microsoft.CodeAnalysis.ProjectInfo Microsoft.CodeAnalysis.ProjectInfo.WithOutputFilePath(string outputFilePath) -> Microsoft.CodeAnalysis.ProjectInfo @@ -1758,12 +1762,13 @@ virtual Microsoft.CodeAnalysis.Editing.SymbolEditor.AsyncDeclarationEditAction.I virtual Microsoft.CodeAnalysis.Editing.SymbolEditor.DeclarationEditAction.Invoke(Microsoft.CodeAnalysis.Editing.DocumentEditor editor, Microsoft.CodeAnalysis.SyntaxNode declaration) -> void virtual Microsoft.CodeAnalysis.Editing.SyntaxGenerator.InsertNodesAfter(Microsoft.CodeAnalysis.SyntaxNode root, Microsoft.CodeAnalysis.SyntaxNode node, System.Collections.Generic.IEnumerable newDeclarations) -> Microsoft.CodeAnalysis.SyntaxNode virtual Microsoft.CodeAnalysis.Editing.SyntaxGenerator.InsertNodesBefore(Microsoft.CodeAnalysis.SyntaxNode root, Microsoft.CodeAnalysis.SyntaxNode node, System.Collections.Generic.IEnumerable newDeclarations) -> Microsoft.CodeAnalysis.SyntaxNode -virtual Microsoft.CodeAnalysis.Editing.SyntaxGenerator.MemberAccessExpression(Microsoft.CodeAnalysis.SyntaxNode expression, Microsoft.CodeAnalysis.SyntaxNode memberName) -> Microsoft.CodeAnalysis.SyntaxNode virtual Microsoft.CodeAnalysis.Editing.SyntaxGenerator.OperatorDeclaration(Microsoft.CodeAnalysis.Editing.OperatorKind kind, System.Collections.Generic.IEnumerable parameters = null, Microsoft.CodeAnalysis.SyntaxNode returnType = null, Microsoft.CodeAnalysis.Accessibility accessibility = Microsoft.CodeAnalysis.Accessibility.NotApplicable, Microsoft.CodeAnalysis.Editing.DeclarationModifiers modifiers = default(Microsoft.CodeAnalysis.Editing.DeclarationModifiers), System.Collections.Generic.IEnumerable statements = null) -> Microsoft.CodeAnalysis.SyntaxNode virtual Microsoft.CodeAnalysis.Editing.SyntaxGenerator.RemoveNode(Microsoft.CodeAnalysis.SyntaxNode root, Microsoft.CodeAnalysis.SyntaxNode node) -> Microsoft.CodeAnalysis.SyntaxNode virtual Microsoft.CodeAnalysis.Editing.SyntaxGenerator.RemoveNode(Microsoft.CodeAnalysis.SyntaxNode root, Microsoft.CodeAnalysis.SyntaxNode node, Microsoft.CodeAnalysis.SyntaxRemoveOptions options) -> Microsoft.CodeAnalysis.SyntaxNode virtual Microsoft.CodeAnalysis.Editing.SyntaxGenerator.ReplaceNode(Microsoft.CodeAnalysis.SyntaxNode root, Microsoft.CodeAnalysis.SyntaxNode node, Microsoft.CodeAnalysis.SyntaxNode newDeclaration) -> Microsoft.CodeAnalysis.SyntaxNode virtual Microsoft.CodeAnalysis.FileTextLoader.CreateText(System.IO.Stream stream, Microsoft.CodeAnalysis.Workspace workspace) -> Microsoft.CodeAnalysis.Text.SourceText +virtual Microsoft.CodeAnalysis.Host.HostLanguageServices.Dispose() -> void +virtual Microsoft.CodeAnalysis.Host.HostWorkspaceServices.Dispose() -> void virtual Microsoft.CodeAnalysis.Host.HostWorkspaceServices.GetLanguageServices(string languageName) -> Microsoft.CodeAnalysis.Host.HostLanguageServices virtual Microsoft.CodeAnalysis.Host.HostWorkspaceServices.IsSupported(string languageName) -> bool virtual Microsoft.CodeAnalysis.Host.HostWorkspaceServices.MetadataFilter.Invoke(System.Collections.Generic.IReadOnlyDictionary metadata) -> bool diff --git a/src/Workspaces/Core/Portable/PublicAPI.Unshipped.txt b/src/Workspaces/Core/Portable/PublicAPI.Unshipped.txt index 8de73f47e1af4..b875c8fa4eccf 100644 --- a/src/Workspaces/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Workspaces/Core/Portable/PublicAPI.Unshipped.txt @@ -1,21 +1,2 @@ -*REMOVED*Microsoft.CodeAnalysis.CodeStyle.CodeStyleOptions.CodeStyleOptions() -> void -*REMOVED*abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.BitwiseOrExpression(Microsoft.CodeAnalysis.SyntaxNode left, Microsoft.CodeAnalysis.SyntaxNode right) -> Microsoft.CodeAnalysis.SyntaxNode -*REMOVED*abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.CastExpression(Microsoft.CodeAnalysis.SyntaxNode type, Microsoft.CodeAnalysis.SyntaxNode expression) -> Microsoft.CodeAnalysis.SyntaxNode -*REMOVED*abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.ConvertExpression(Microsoft.CodeAnalysis.SyntaxNode type, Microsoft.CodeAnalysis.SyntaxNode expression) -> Microsoft.CodeAnalysis.SyntaxNode -*REMOVED*abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.DefaultExpression(Microsoft.CodeAnalysis.ITypeSymbol type) -> Microsoft.CodeAnalysis.SyntaxNode -*REMOVED*abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.DefaultExpression(Microsoft.CodeAnalysis.SyntaxNode type) -> Microsoft.CodeAnalysis.SyntaxNode -*REMOVED*abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.IdentifierName(string identifier) -> Microsoft.CodeAnalysis.SyntaxNode -*REMOVED*virtual Microsoft.CodeAnalysis.Editing.SyntaxGenerator.MemberAccessExpression(Microsoft.CodeAnalysis.SyntaxNode expression, Microsoft.CodeAnalysis.SyntaxNode memberName) -> Microsoft.CodeAnalysis.SyntaxNode -Microsoft.CodeAnalysis.CompilationOutputInfo.GeneratedFilesOutputDirectory.get -> string -Microsoft.CodeAnalysis.CompilationOutputInfo.WithGeneratedFilesOutputDirectory(string path) -> Microsoft.CodeAnalysis.CompilationOutputInfo -Microsoft.CodeAnalysis.Editing.SyntaxGenerator.BitwiseOrExpression(Microsoft.CodeAnalysis.SyntaxNode left, Microsoft.CodeAnalysis.SyntaxNode right) -> Microsoft.CodeAnalysis.SyntaxNode -Microsoft.CodeAnalysis.Editing.SyntaxGenerator.CastExpression(Microsoft.CodeAnalysis.SyntaxNode type, Microsoft.CodeAnalysis.SyntaxNode expression) -> Microsoft.CodeAnalysis.SyntaxNode -Microsoft.CodeAnalysis.Editing.SyntaxGenerator.ConvertExpression(Microsoft.CodeAnalysis.SyntaxNode type, Microsoft.CodeAnalysis.SyntaxNode expression) -> Microsoft.CodeAnalysis.SyntaxNode -Microsoft.CodeAnalysis.Editing.SyntaxGenerator.DefaultExpression(Microsoft.CodeAnalysis.ITypeSymbol type) -> Microsoft.CodeAnalysis.SyntaxNode -Microsoft.CodeAnalysis.Editing.SyntaxGenerator.DefaultExpression(Microsoft.CodeAnalysis.SyntaxNode type) -> Microsoft.CodeAnalysis.SyntaxNode -Microsoft.CodeAnalysis.Editing.SyntaxGenerator.IdentifierName(string identifier) -> Microsoft.CodeAnalysis.SyntaxNode -Microsoft.CodeAnalysis.Editing.SyntaxGenerator.MemberAccessExpression(Microsoft.CodeAnalysis.SyntaxNode expression, Microsoft.CodeAnalysis.SyntaxNode memberName) -> Microsoft.CodeAnalysis.SyntaxNode -Microsoft.CodeAnalysis.Project.HostAnalyzerOptions.get -> Microsoft.CodeAnalysis.Diagnostics.AnalyzerOptions -Microsoft.CodeAnalysis.ProjectInfo.WithId(Microsoft.CodeAnalysis.ProjectId id) -> Microsoft.CodeAnalysis.ProjectInfo -virtual Microsoft.CodeAnalysis.Host.HostLanguageServices.Dispose() -> void -virtual Microsoft.CodeAnalysis.Host.HostWorkspaceServices.Dispose() -> void +*REMOVED*abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.WithModifiers(Microsoft.CodeAnalysis.SyntaxNode declaration, Microsoft.CodeAnalysis.Editing.DeclarationModifiers modifiers) -> Microsoft.CodeAnalysis.SyntaxNode +Microsoft.CodeAnalysis.Editing.SyntaxGenerator.WithModifiers(Microsoft.CodeAnalysis.SyntaxNode declaration, Microsoft.CodeAnalysis.Editing.DeclarationModifiers modifiers) -> Microsoft.CodeAnalysis.SyntaxNode diff --git a/src/Workspaces/Core/Portable/Recommendations/AbstractRecommendationServiceRunner.cs b/src/Workspaces/Core/Portable/Recommendations/AbstractRecommendationServiceRunner.cs index 19cb44579d20b..91487e267bb9f 100644 --- a/src/Workspaces/Core/Portable/Recommendations/AbstractRecommendationServiceRunner.cs +++ b/src/Workspaces/Core/Portable/Recommendations/AbstractRecommendationServiceRunner.cs @@ -388,7 +388,17 @@ protected ImmutableArray LookupSymbolsInContainer( INamespaceOrTypeSymbol container, int position, bool excludeInstance) { if (excludeInstance) - return _context.SemanticModel.LookupStaticMembers(position, container); + { + var staticMembers = _context.SemanticModel.LookupStaticMembers(position, container); + if (container is not INamedTypeSymbol) + return staticMembers; + + var staticExtensionsMembers = _context.SemanticModel + .LookupSymbols(position, container, includeReducedExtensionMethods: true) + .WhereAsArray(static (s, staticMembers) => s is { IsStatic: true, ContainingType.IsExtension: true } && !staticMembers.Contains(s), staticMembers); + + return [.. staticMembers, .. staticExtensionsMembers]; + } var containerMembers = SuppressDefaultTupleElements( container, diff --git a/src/Workspaces/Core/Portable/Remote/ExportRemoteServiceCallbackDispatcherAttribute.cs b/src/Workspaces/Core/Portable/Remote/ExportRemoteServiceCallbackDispatcherAttribute.cs index 151b79a118599..621010e21f7a0 100644 --- a/src/Workspaces/Core/Portable/Remote/ExportRemoteServiceCallbackDispatcherAttribute.cs +++ b/src/Workspaces/Core/Portable/Remote/ExportRemoteServiceCallbackDispatcherAttribute.cs @@ -4,7 +4,6 @@ using System; using System.Composition; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Remote; diff --git a/src/Workspaces/Core/Portable/Remote/IRemoteKeepAliveService.cs b/src/Workspaces/Core/Portable/Remote/IRemoteKeepAliveService.cs index 024db2a78d641..44fef3920f41a 100644 --- a/src/Workspaces/Core/Portable/Remote/IRemoteKeepAliveService.cs +++ b/src/Workspaces/Core/Portable/Remote/IRemoteKeepAliveService.cs @@ -6,7 +6,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Shared.TestHooks; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Remote; diff --git a/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.Session.cs b/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.Session.cs index ed62b06e69b62..8d8f373ce19be 100644 --- a/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.Session.cs +++ b/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.Session.cs @@ -10,7 +10,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.Host; diff --git a/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.cs b/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.cs index 8bffb26643a13..103368e0802a2 100644 --- a/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.cs +++ b/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.cs @@ -11,7 +11,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.Host; diff --git a/src/Workspaces/Core/Portable/Rename/IRemoteRenamerService.cs b/src/Workspaces/Core/Portable/Rename/IRemoteRenamerService.cs index ba47ab9ec4d61..953abf73dcbaa 100644 --- a/src/Workspaces/Core/Portable/Rename/IRemoteRenamerService.cs +++ b/src/Workspaces/Core/Portable/Rename/IRemoteRenamerService.cs @@ -2,15 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Immutable; -using System.Composition; using System.Linq; using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeCleanup; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Rename.ConflictEngine; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Workspaces/Core/Portable/Rename/LightweightRenameLocations.cs b/src/Workspaces/Core/Portable/Rename/LightweightRenameLocations.cs index 15d6b885e6b8b..7df6929dcabe9 100644 --- a/src/Workspaces/Core/Portable/Rename/LightweightRenameLocations.cs +++ b/src/Workspaces/Core/Portable/Rename/LightweightRenameLocations.cs @@ -8,7 +8,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Rename.ConflictEngine; diff --git a/src/Workspaces/Core/Portable/Rename/RenameUtilities.cs b/src/Workspaces/Core/Portable/Rename/RenameUtilities.cs index def784de0012b..471b1941a4742 100644 --- a/src/Workspaces/Core/Portable/Rename/RenameUtilities.cs +++ b/src/Workspaces/Core/Portable/Rename/RenameUtilities.cs @@ -327,55 +327,24 @@ public static async Task FindDefinitionSymbolAsync( // If we're renaming a property, it might be a synthesized property for a method // backing field. - if (symbol.Kind == SymbolKind.Parameter) + if (symbol is IParameterSymbol { ContainingSymbol: IMethodSymbol { AssociatedSymbol: IPropertySymbol associatedParameterProperty } containingMethod }) { - if (symbol.ContainingSymbol.Kind == SymbolKind.Method) - { - var containingMethod = (IMethodSymbol)symbol.ContainingSymbol; - if (containingMethod.AssociatedSymbol is IPropertySymbol) - { - var associatedPropertyOrEvent = (IPropertySymbol)containingMethod.AssociatedSymbol; - var ordinal = containingMethod.Parameters.IndexOf((IParameterSymbol)symbol); - if (ordinal < associatedPropertyOrEvent.Parameters.Length) - { - return associatedPropertyOrEvent.Parameters[ordinal]; - } - } - } + var ordinal = containingMethod.Parameters.IndexOf((IParameterSymbol)symbol); + if (ordinal < associatedParameterProperty.Parameters.Length) + return associatedParameterProperty.Parameters[ordinal]; } // if we are renaming a compiler generated delegate for an event, cascade to the event - if (symbol.Kind == SymbolKind.NamedType) - { - var typeSymbol = (INamedTypeSymbol)symbol; - if (typeSymbol.IsImplicitlyDeclared && typeSymbol.IsDelegateType() && typeSymbol.AssociatedSymbol != null) - { - return typeSymbol.AssociatedSymbol; - } - } + if (symbol is INamedTypeSymbol { IsImplicitlyDeclared: true, TypeKind: TypeKind.Delegate, AssociatedSymbol: not null } typeSymbol) + return typeSymbol.AssociatedSymbol; // If we are renaming a constructor or destructor, we wish to rename the whole type - if (symbol.Kind == SymbolKind.Method) - { - var methodSymbol = (IMethodSymbol)symbol; - if (methodSymbol.MethodKind is MethodKind.Constructor or - MethodKind.StaticConstructor or - MethodKind.Destructor) - { - return methodSymbol.ContainingType; - } - } + if (symbol is IMethodSymbol { MethodKind: MethodKind.Constructor or MethodKind.StaticConstructor or MethodKind.Destructor }) + return symbol.ContainingType; // If we are renaming a backing field for a property, cascade to the property - if (symbol.Kind == SymbolKind.Field) - { - var fieldSymbol = (IFieldSymbol)symbol; - if (fieldSymbol.IsImplicitlyDeclared && - fieldSymbol.AssociatedSymbol.IsKind(SymbolKind.Property)) - { - return fieldSymbol.AssociatedSymbol; - } - } + if (symbol is IFieldSymbol { IsImplicitlyDeclared: true, AssociatedSymbol: IPropertySymbol associatedProperty }) + return associatedProperty; // in case this is e.g. an overridden property accessor, we'll treat the property itself as the definition symbol var property = await TryGetPropertyFromAccessorOrAnOverrideAsync(bestSymbol, solution, cancellationToken).ConfigureAwait(false); diff --git a/src/Workspaces/Core/Portable/Rename/Renamer.SyncNamespaceDocumentAction.cs b/src/Workspaces/Core/Portable/Rename/Renamer.SyncNamespaceDocumentAction.cs index dcb74146489ce..939aa383eb500 100644 --- a/src/Workspaces/Core/Portable/Rename/Renamer.SyncNamespaceDocumentAction.cs +++ b/src/Workspaces/Core/Portable/Rename/Renamer.SyncNamespaceDocumentAction.cs @@ -7,7 +7,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.ChangeNamespace; -using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; diff --git a/src/Workspaces/Core/Portable/Rename/Renamer.cs b/src/Workspaces/Core/Portable/Rename/Renamer.cs index ff7be7c19f700..7e79da036c022 100644 --- a/src/Workspaces/Core/Portable/Rename/Renamer.cs +++ b/src/Workspaces/Core/Portable/Rename/Renamer.cs @@ -8,8 +8,6 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Options; diff --git a/src/Workspaces/Core/Portable/Rename/SymbolicRenameLocations.SearchResult.cs b/src/Workspaces/Core/Portable/Rename/SymbolicRenameLocations.SearchResult.cs index 09b5525a06faa..4c469290d3611 100644 --- a/src/Workspaces/Core/Portable/Rename/SymbolicRenameLocations.SearchResult.cs +++ b/src/Workspaces/Core/Portable/Rename/SymbolicRenameLocations.SearchResult.cs @@ -4,7 +4,6 @@ using System.Collections.Immutable; using Microsoft.CodeAnalysis.FindSymbols; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Rename; diff --git a/src/Workspaces/Core/Portable/Rename/SymbolicRenameLocations.cs b/src/Workspaces/Core/Portable/Rename/SymbolicRenameLocations.cs index 35dbd0265304c..6c3440d1a04d1 100644 --- a/src/Workspaces/Core/Portable/Rename/SymbolicRenameLocations.cs +++ b/src/Workspaces/Core/Portable/Rename/SymbolicRenameLocations.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Immutable; using System.Diagnostics; using System.Linq; diff --git a/src/Workspaces/Core/Portable/SemanticModelReuse/AbstractSemanticModelReuseLanguageService.cs b/src/Workspaces/Core/Portable/SemanticModelReuse/AbstractSemanticModelReuseLanguageService.cs index 0d4712b4ce423..a9cadd71cb2a9 100644 --- a/src/Workspaces/Core/Portable/SemanticModelReuse/AbstractSemanticModelReuseLanguageService.cs +++ b/src/Workspaces/Core/Portable/SemanticModelReuse/AbstractSemanticModelReuseLanguageService.cs @@ -3,12 +3,12 @@ // 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; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.LanguageService; +using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.SemanticModelReuse; @@ -106,26 +106,58 @@ protected SyntaxNode GetPreviousBodyNode(SyntaxNode previousRoot, SyntaxNode cur } else { - using var pooledCurrentMembers = this.SyntaxFacts.GetMethodLevelMembers(currentRoot); - var currentMembers = pooledCurrentMembers.Object; + // Walk up the ancestor nodes of currentBodyNode, finding child indexes up to the root. + using var _ = ArrayBuilder.GetInstance(out var indexPath); + GetNodeChildIndexPathToRootReversed(currentBodyNode, indexPath); - var index = currentMembers.IndexOf(currentBodyNode); - if (index < 0) + // Then use those indexes to walk back down the previous tree to find the equivalent node. + var previousNode = previousRoot; + for (var i = indexPath.Count - 1; i >= 0; i--) { - Debug.Fail($"Unhandled member type in {nameof(GetPreviousBodyNode)}"); - return null; + var childIndex = indexPath[i]; + var children = previousNode.ChildNodesAndTokens(); + + if (children.Count <= childIndex) + { + Debug.Fail("Member count shouldn't have changed as there were no top level edits."); + return null; + } + + var childAsNode = children[childIndex].AsNode(); + if (childAsNode is null) + { + Debug.Fail("Child at indicated index should be a node as there were no top level edits."); + return null; + } + + previousNode = childAsNode; } - using var pooledPreviousMembers = this.SyntaxFacts.GetMethodLevelMembers(previousRoot); - var previousMembers = pooledPreviousMembers.Object; + return previousNode; + } + } + + private static void GetNodeChildIndexPathToRootReversed(SyntaxNode node, ArrayBuilder path) + { + var current = node; + var parent = current.Parent; - if (currentMembers.Count != previousMembers.Count) + while (parent != null) + { + var childIndex = 0; + foreach (var child in parent.ChildNodesAndTokens()) { - Debug.Fail("Member count shouldn't have changed as there were no top level edits."); - return null; + if (child.AsNode() == current) + { + path.Add(childIndex); + break; + } + + childIndex++; } - return previousMembers[index]; + current = parent; + parent = current.Parent; } } diff --git a/src/Workspaces/Core/Portable/Serialization/IOptionsSerializationService.cs b/src/Workspaces/Core/Portable/Serialization/IOptionsSerializationService.cs index a742660c977ca..8e2e8c4f4f076 100644 --- a/src/Workspaces/Core/Portable/Serialization/IOptionsSerializationService.cs +++ b/src/Workspaces/Core/Portable/Serialization/IOptionsSerializationService.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 Microsoft.CodeAnalysis.Host; using Roslyn.Utilities; diff --git a/src/Workspaces/Core/Portable/Serialization/SerializableSourceText.cs b/src/Workspaces/Core/Portable/Serialization/SerializableSourceText.cs index 2a46a92588341..340d7a155c9fe 100644 --- a/src/Workspaces/Core/Portable/Serialization/SerializableSourceText.cs +++ b/src/Workspaces/Core/Portable/Serialization/SerializableSourceText.cs @@ -15,7 +15,6 @@ using static Microsoft.CodeAnalysis.Host.TemporaryStorageService; #if DEBUG -using System.Linq; #endif namespace Microsoft.CodeAnalysis.Serialization; diff --git a/src/Workspaces/Core/Portable/Serialization/SerializerService_Reference.cs b/src/Workspaces/Core/Portable/Serialization/SerializerService_Reference.cs index 7bb2618b19b0a..9c1adb44c8940 100644 --- a/src/Workspaces/Core/Portable/Serialization/SerializerService_Reference.cs +++ b/src/Workspaces/Core/Portable/Serialization/SerializerService_Reference.cs @@ -15,6 +15,7 @@ namespace Microsoft.CodeAnalysis.Serialization; +using static Microsoft.CodeAnalysis.Serialization.SerializerService.TestAccessor; using static TemporaryStorageService; internal partial class SerializerService @@ -29,18 +30,18 @@ internal partial class SerializerService /// pretend that a is a during tests. /// private static readonly object s_analyzerImageReferenceMapGate = new(); - private static IBidirectionalMap s_analyzerImageReferenceMap = BidirectionalMap.Empty; + private static IBidirectionalMap s_analyzerReferenceMap = BidirectionalMap.Empty; private static bool TryGetAnalyzerImageReferenceGuid(AnalyzerImageReference imageReference, out Guid guid) { lock (s_analyzerImageReferenceMapGate) - return s_analyzerImageReferenceMap.TryGetValue(imageReference, out guid); + return s_analyzerReferenceMap.TryGetValue(imageReference, out guid); } - private static bool TryGetAnalyzerImageReferenceFromGuid(Guid guid, [NotNullWhen(true)] out AnalyzerImageReference? imageReference) + private static bool TryGetAnalyzerImageReferenceFromGuid(Guid guid, [NotNullWhen(true)] out AnalyzerReference? analyzerReference) { lock (s_analyzerImageReferenceMapGate) - return s_analyzerImageReferenceMap.TryGetKey(guid, out imageReference); + return s_analyzerReferenceMap.TryGetKey(guid, out analyzerReference); } private static Checksum CreateChecksum(MetadataReference reference) @@ -78,6 +79,12 @@ protected virtual Checksum CreateChecksum(AnalyzerReference reference) writer.WriteGuid(guid); break; + case IAnalyzerReferenceWithGuid analyzerReferenceWithGuid: + lock (s_analyzerImageReferenceMapGate) + s_analyzerReferenceMap = s_analyzerReferenceMap.Add(reference, analyzerReferenceWithGuid.Guid); + writer.WriteGuid(analyzerReferenceWithGuid.Guid); + break; + default: throw ExceptionUtilities.UnexpectedValue(reference); } @@ -482,12 +489,6 @@ private static unsafe void WriteTo(MetadataReader reader, ObjectWriter writer) writer.WriteSpan(new ReadOnlySpan(reader.MetadataPointer, reader.MetadataLength)); } - private static void WriteUnresolvedAnalyzerReferenceTo(AnalyzerReference reference, ObjectWriter writer) - { - writer.WriteString(nameof(UnresolvedAnalyzerReference)); - writer.WriteString(reference.FullPath); - } - private static Metadata? TryGetMetadata(PortableExecutableReference reference) { try @@ -541,9 +542,23 @@ public static void AddAnalyzerImageReference(AnalyzerImageReference analyzerImag { lock (s_analyzerImageReferenceMapGate) { - if (!s_analyzerImageReferenceMap.ContainsKey(analyzerImageReference)) - s_analyzerImageReferenceMap = s_analyzerImageReferenceMap.Add(analyzerImageReference, Guid.NewGuid()); + if (!s_analyzerReferenceMap.ContainsKey(analyzerImageReference)) + s_analyzerReferenceMap = s_analyzerReferenceMap.Add(analyzerImageReference, Guid.NewGuid()); } } + + public static void AddAnalyzerImageReferences(IReadOnlyList analyzerReferences) + { + foreach (var analyzer in analyzerReferences) + { + if (analyzer is AnalyzerImageReference analyzerImageReference) + AddAnalyzerImageReference(analyzerImageReference); + } + } + + public interface IAnalyzerReferenceWithGuid + { + Guid Guid { get; } + } } } diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/BackgroundAnalysisScopeExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/BackgroundAnalysisScopeExtensions.cs index 055abe3c1a694..255c995a19327 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/BackgroundAnalysisScopeExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/BackgroundAnalysisScopeExtensions.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.SolutionCrawler; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/DocumentExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/DocumentExtensions.cs index dc01cc80dc577..e1d14075ad59c 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/DocumentExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/DocumentExtensions.cs @@ -6,7 +6,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.Options; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/FileLinePositionSpanExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/FileLinePositionSpanExtensions.cs index d7ed3e8f755da..ad82edce0d405 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/FileLinePositionSpanExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/FileLinePositionSpanExtensions.cs @@ -4,7 +4,6 @@ using System; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/IMethodSymbolExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/IMethodSymbolExtensions.cs index 2c72995aba362..ec237d9a40532 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/IMethodSymbolExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/IMethodSymbolExtensions.cs @@ -3,12 +3,8 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CodeGeneration; -using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs index 9cf71fefedc3f..37d4a15b0195a 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs @@ -645,7 +645,17 @@ private static bool ElementNameIs(XElement element, string name) public static ImmutableArray FilterToVisibleAndBrowsableSymbols( this ImmutableArray symbols, bool hideAdvancedMembers, Compilation compilation) where T : ISymbol { - symbols = symbols.RemoveOverriddenSymbolsWithinSet(); + if (symbols.Length == 0) + return []; + + using var _ = MetadataUnifyingSymbolHashSet.GetInstance(out var overriddenSymbols); + + foreach (var symbol in symbols) + { + var overriddenMember = symbol.GetOverriddenMember(); + if (overriddenMember != null) + overriddenSymbols.Add(overriddenMember); + } // Since all symbols are from the same compilation, find the required attribute // constructors once and reuse. @@ -653,30 +663,19 @@ public static ImmutableArray FilterToVisibleAndBrowsableSymbols( // PERF: HasUnsupportedMetadata may require recreating the syntax tree to get the base class, so first // check to see if we're referencing a symbol defined in source. - return symbols.WhereAsArray((s, arg) => + var filteredSymbols = symbols.WhereAsArray(static (s, arg) => // Check if symbol is namespace (which is always visible) first to avoid realizing all locations // of each namespace symbol, which might end up allocating in LOH + !arg.overriddenSymbols.Contains(s) && (s is INamespaceSymbol || s.Locations.Any(static loc => loc.IsInSource) || !s.HasUnsupportedMetadata) && !s.IsDestructor() && s.IsEditorBrowsable( arg.hideAdvancedMembers, arg.editorBrowsableInfo.Compilation, arg.editorBrowsableInfo), - (hideAdvancedMembers, editorBrowsableInfo)); - } - - private static ImmutableArray RemoveOverriddenSymbolsWithinSet(this ImmutableArray symbols) where T : ISymbol - { - var overriddenSymbols = new MetadataUnifyingSymbolHashSet(); - - foreach (var symbol in symbols) - { - var overriddenMember = symbol.GetOverriddenMember(); - if (overriddenMember != null && !overriddenSymbols.Contains(overriddenMember)) - overriddenSymbols.Add(overriddenMember); - } + arg: (hideAdvancedMembers, editorBrowsableInfo, overriddenSymbols)); - return symbols.WhereAsArray(s => !overriddenSymbols.Contains(s)); + return filteredSymbols; } public static ImmutableArray FilterToVisibleAndBrowsableSymbolsAndNotUnsafeSymbols( diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/SafeHandleLease.cs b/src/Workspaces/Core/Portable/Shared/Extensions/SafeHandleLease.cs index c97015d5e201b..fcf5bcc237321 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/SafeHandleLease.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/SafeHandleLease.cs @@ -4,7 +4,6 @@ using System; using System.Runtime.InteropServices; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Workspaces/Core/Portable/Shared/TestHooks/FeatureAttribute.cs b/src/Workspaces/Core/Portable/Shared/TestHooks/FeatureAttribute.cs index 732aa7f640968..343deb91c658c 100644 --- a/src/Workspaces/Core/Portable/Shared/TestHooks/FeatureAttribute.cs +++ b/src/Workspaces/Core/Portable/Shared/TestHooks/FeatureAttribute.cs @@ -18,6 +18,7 @@ internal static class FeatureAttribute public const string CodeModel = nameof(CodeModel); public const string ColorScheme = nameof(ColorScheme); public const string CompletionSet = nameof(CompletionSet); + public const string CopilotImplementNotImplementedException = nameof(CopilotImplementNotImplementedException); public const string CopilotSuggestions = nameof(CopilotSuggestions); public const string DesignerAttributes = nameof(DesignerAttributes); public const string DiagnosticService = nameof(DiagnosticService); @@ -30,6 +31,7 @@ internal static class FeatureAttribute public const string ExtractMethod = nameof(ExtractMethod); public const string FindReferences = nameof(FindReferences); public const string SemanticSearch = nameof(SemanticSearch); + public const string GenerateDocumentation = nameof(GenerateDocumentation); public const string GlobalOperation = nameof(GlobalOperation); public const string GoToBase = nameof(GoToBase); public const string GoToDefinition = nameof(GoToDefinition); diff --git a/src/Workspaces/Core/Portable/Shared/TestHooks/TaskExtensions.cs b/src/Workspaces/Core/Portable/Shared/TestHooks/TaskExtensions.cs index 5db50f3c9a6a9..61a50ca6b3f81 100644 --- a/src/Workspaces/Core/Portable/Shared/TestHooks/TaskExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/TestHooks/TaskExtensions.cs @@ -4,8 +4,8 @@ using System; using System.Diagnostics.CodeAnalysis; -using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Shared.TestHooks; diff --git a/src/Workspaces/Core/Portable/Shared/Utilities/ExtensionOrderer.Graph.cs b/src/Workspaces/Core/Portable/Shared/Utilities/ExtensionOrderer.Graph.cs index 05632f8418f70..f902c29113e50 100644 --- a/src/Workspaces/Core/Portable/Shared/Utilities/ExtensionOrderer.Graph.cs +++ b/src/Workspaces/Core/Portable/Shared/Utilities/ExtensionOrderer.Graph.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Shared.Utilities; diff --git a/src/Workspaces/Core/Portable/Shared/Utilities/ExtensionOrderer.Node.cs b/src/Workspaces/Core/Portable/Shared/Utilities/ExtensionOrderer.Node.cs index f1d81852e6810..14f6a8810b12d 100644 --- a/src/Workspaces/Core/Portable/Shared/Utilities/ExtensionOrderer.Node.cs +++ b/src/Workspaces/Core/Portable/Shared/Utilities/ExtensionOrderer.Node.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; diff --git a/src/Workspaces/Core/Portable/Shared/Utilities/SemanticMap.Walker.cs b/src/Workspaces/Core/Portable/Shared/Utilities/SemanticMap.Walker.cs index e17598e9f492d..bfc0b801fefa6 100644 --- a/src/Workspaces/Core/Portable/Shared/Utilities/SemanticMap.Walker.cs +++ b/src/Workspaces/Core/Portable/Shared/Utilities/SemanticMap.Walker.cs @@ -4,7 +4,6 @@ using System.Threading; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Shared.Utilities; diff --git a/src/Workspaces/Core/Portable/Shared/Utilities/XmlFragmentParser.cs b/src/Workspaces/Core/Portable/Shared/Utilities/XmlFragmentParser.cs index 9a99200dcc57f..b97e0f47d1ef7 100644 --- a/src/Workspaces/Core/Portable/Shared/Utilities/XmlFragmentParser.cs +++ b/src/Workspaces/Core/Portable/Shared/Utilities/XmlFragmentParser.cs @@ -9,7 +9,6 @@ using System.IO; using System.Xml; using Microsoft.CodeAnalysis.PooledObjects; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Shared.Utilities; diff --git a/src/Workspaces/Core/Portable/SolutionCrawler/InvocationReasons_Constants.cs b/src/Workspaces/Core/Portable/SolutionCrawler/InvocationReasons_Constants.cs index 31c3ecc9163ef..3b456841701fa 100644 --- a/src/Workspaces/Core/Portable/SolutionCrawler/InvocationReasons_Constants.cs +++ b/src/Workspaces/Core/Portable/SolutionCrawler/InvocationReasons_Constants.cs @@ -2,10 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - -using System.Collections.Immutable; - namespace Microsoft.CodeAnalysis.SolutionCrawler; internal readonly partial struct InvocationReasons diff --git a/src/Workspaces/Core/Portable/SolutionCrawler/PredefinedInvocationReasons.cs b/src/Workspaces/Core/Portable/SolutionCrawler/PredefinedInvocationReasons.cs index 04cde7b87a27b..41f9e02ce7ed1 100644 --- a/src/Workspaces/Core/Portable/SolutionCrawler/PredefinedInvocationReasons.cs +++ b/src/Workspaces/Core/Portable/SolutionCrawler/PredefinedInvocationReasons.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.SolutionCrawler; internal static class PredefinedInvocationReasons diff --git a/src/Workspaces/Core/Portable/Storage/SQLite/v2/Database.cs b/src/Workspaces/Core/Portable/Storage/SQLite/v2/Database.cs index aa6ae8b5a5c90..67a77bba01a78 100644 --- a/src/Workspaces/Core/Portable/Storage/SQLite/v2/Database.cs +++ b/src/Workspaces/Core/Portable/Storage/SQLite/v2/Database.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Roslyn.Utilities; - namespace Microsoft.CodeAnalysis.SQLite.v2; internal enum Database 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 3a77291393a0d..f031e22a1522d 100644 --- a/src/Workspaces/Core/Portable/Storage/SQLite/v2/Interop/SqlStatement.cs +++ b/src/Workspaces/Core/Portable/Storage/SQLite/v2/Interop/SqlStatement.cs @@ -5,7 +5,6 @@ using System; using System.Text; using Microsoft.CodeAnalysis.SQLite.Interop; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.SQLite.v2.Interop; diff --git a/src/Workspaces/Core/Portable/Storage/SQLite/v2/SQLitePersistentStorage.cs b/src/Workspaces/Core/Portable/Storage/SQLite/v2/SQLitePersistentStorage.cs index 9ea33b38eff0f..d39132afee723 100644 --- a/src/Workspaces/Core/Portable/Storage/SQLite/v2/SQLitePersistentStorage.cs +++ b/src/Workspaces/Core/Portable/Storage/SQLite/v2/SQLitePersistentStorage.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.SQLite.Interop; using Microsoft.CodeAnalysis.SQLite.v2.Interop; using Microsoft.CodeAnalysis.Storage; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.SQLite.v2; diff --git a/src/Workspaces/Core/Portable/Storage/SQLite/v2/SQLitePersistentStorageService.cs b/src/Workspaces/Core/Portable/Storage/SQLite/v2/SQLitePersistentStorageService.cs index 9f1570f00f3b6..c17666916d22d 100644 --- a/src/Workspaces/Core/Portable/Storage/SQLite/v2/SQLitePersistentStorageService.cs +++ b/src/Workspaces/Core/Portable/Storage/SQLite/v2/SQLitePersistentStorageService.cs @@ -12,7 +12,6 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Storage; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.SQLite.v2; diff --git a/src/Workspaces/Core/Portable/Storage/SQLite/v2/SQLitePersistentStorage_FlushWrites.cs b/src/Workspaces/Core/Portable/Storage/SQLite/v2/SQLitePersistentStorage_FlushWrites.cs index a796a791df4ef..74befe59bd8c9 100644 --- a/src/Workspaces/Core/Portable/Storage/SQLite/v2/SQLitePersistentStorage_FlushWrites.cs +++ b/src/Workspaces/Core/Portable/Storage/SQLite/v2/SQLitePersistentStorage_FlushWrites.cs @@ -4,7 +4,7 @@ using System.Threading; using System.Threading.Tasks; -using Roslyn.Utilities; +using Microsoft.CodeAnalysis.Threading; namespace Microsoft.CodeAnalysis.SQLite.v2; diff --git a/src/Workspaces/Core/Portable/Storage/SQLite/v2/SQLitePersistentStorage_StringIds.cs b/src/Workspaces/Core/Portable/Storage/SQLite/v2/SQLitePersistentStorage_StringIds.cs index 75fd83781412a..4acf727ffb6be 100644 --- a/src/Workspaces/Core/Portable/Storage/SQLite/v2/SQLitePersistentStorage_StringIds.cs +++ b/src/Workspaces/Core/Portable/Storage/SQLite/v2/SQLitePersistentStorage_StringIds.cs @@ -8,7 +8,6 @@ using Microsoft.CodeAnalysis.SQLite.Interop; using Microsoft.CodeAnalysis.SQLite.v2.Interop; using Microsoft.CodeAnalysis.Storage; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.SQLite.v2; diff --git a/src/Workspaces/Core/Portable/Telemetry/ITelemetryLog.cs b/src/Workspaces/Core/Portable/Telemetry/ITelemetryLog.cs index 585b3ec32a858..c96bba2b4bb39 100644 --- a/src/Workspaces/Core/Portable/Telemetry/ITelemetryLog.cs +++ b/src/Workspaces/Core/Portable/Telemetry/ITelemetryLog.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 Microsoft.CodeAnalysis.Internal.Log; namespace Microsoft.CodeAnalysis.Telemetry; diff --git a/src/Workspaces/Core/Portable/TemporaryStorage/TemporaryStorageService.cs b/src/Workspaces/Core/Portable/TemporaryStorage/TemporaryStorageService.cs index adf3210139dbd..259db7cc54e15 100644 --- a/src/Workspaces/Core/Portable/TemporaryStorage/TemporaryStorageService.cs +++ b/src/Workspaces/Core/Portable/TemporaryStorage/TemporaryStorageService.cs @@ -15,6 +15,7 @@ using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Host; diff --git a/src/Workspaces/Core/Portable/Workspace/DocumentActiveContextChangedEventArgs.cs b/src/Workspaces/Core/Portable/Workspace/DocumentActiveContextChangedEventArgs.cs index 8f5d28b512b64..c477787e6594e 100644 --- a/src/Workspaces/Core/Portable/Workspace/DocumentActiveContextChangedEventArgs.cs +++ b/src/Workspaces/Core/Portable/Workspace/DocumentActiveContextChangedEventArgs.cs @@ -2,11 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis; diff --git a/src/Workspaces/Core/Portable/Workspace/DocumentEventArgs.cs b/src/Workspaces/Core/Portable/Workspace/DocumentEventArgs.cs index bee387ad8a8b1..fd930457e41ce 100644 --- a/src/Workspaces/Core/Portable/Workspace/DocumentEventArgs.cs +++ b/src/Workspaces/Core/Portable/Workspace/DocumentEventArgs.cs @@ -2,10 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis; diff --git a/src/Workspaces/Core/Portable/Workspace/Host/Caching/IWorkspaceCacheService.cs b/src/Workspaces/Core/Portable/Workspace/Host/Caching/IWorkspaceCacheService.cs index 6c2cf88538f16..2e4c486d9219b 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/Caching/IWorkspaceCacheService.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/Caching/IWorkspaceCacheService.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; namespace Microsoft.CodeAnalysis.Host; diff --git a/src/Workspaces/Core/Portable/Workspace/Host/DocumentService/AbstractSpanMappingService.cs b/src/Workspaces/Core/Portable/Workspace/Host/DocumentService/AbstractSpanMappingService.cs index e297815f4850d..efde1ef60f746 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/DocumentService/AbstractSpanMappingService.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/DocumentService/AbstractSpanMappingService.cs @@ -8,7 +8,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Host; diff --git a/src/Workspaces/Core/Portable/Workspace/Host/DocumentService/IDocumentExcerptService.cs b/src/Workspaces/Core/Portable/Workspace/Host/DocumentService/IDocumentExcerptService.cs index b30eb4f687061..0cdac83b98a19 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/DocumentService/IDocumentExcerptService.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/DocumentService/IDocumentExcerptService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; diff --git a/src/Workspaces/Core/Portable/Workspace/Host/DocumentService/IDocumentOperationService.cs b/src/Workspaces/Core/Portable/Workspace/Host/DocumentService/IDocumentOperationService.cs index 67185e9a4a0a7..bb013103bee19 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/DocumentService/IDocumentOperationService.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/DocumentService/IDocumentOperationService.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.Host; /// diff --git a/src/Workspaces/Core/Portable/Workspace/Host/DocumentService/ISpanMappingService.cs b/src/Workspaces/Core/Portable/Workspace/Host/DocumentService/ISpanMappingService.cs index acb0bf65e0f9f..99a99fdeee7d7 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/DocumentService/ISpanMappingService.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/DocumentService/ISpanMappingService.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; diff --git a/src/Workspaces/Core/Portable/Workspace/Host/EventListener/EventListenerTracker.cs b/src/Workspaces/Core/Portable/Workspace/Host/EventListener/EventListenerTracker.cs index 620179260d5af..7d3ed18e13edc 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/EventListener/EventListenerTracker.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/EventListener/EventListenerTracker.cs @@ -8,65 +8,39 @@ using System.Linq; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Host +namespace Microsoft.CodeAnalysis.Host; + +/// +/// helper type to track whether has been initialized. +/// +/// currently, this helper only supports services whose lifetime is same as Host (ex, VS) +/// +internal sealed class EventListenerTracker( + IEnumerable> eventListeners, string kind) { - /// - /// helper type to track whether has been initialized. - /// - /// currently, this helper only supports services whose lifetime is same as Host (ex, VS) - /// - /// TService for - internal sealed class EventListenerTracker( - IEnumerable> eventListeners, string kind) - { - /// - /// Workspace kind this event listener is initialized for - /// - private readonly HashSet _eventListenerInitialized = []; - private readonly ImmutableArray> _eventListeners = [.. eventListeners.Where(el => el.Metadata.Service == kind)]; - - public void EnsureEventListener(Workspace workspace, TService serviceOpt) - { - Contract.ThrowIfNull(workspace.Kind); - - lock (_eventListenerInitialized) - { - if (!_eventListenerInitialized.Add(workspace.Kind)) - { - // already initialized - return; - } - } + private readonly ImmutableArray> _eventListeners = [.. eventListeners.Where(el => el.Metadata.Service == kind)]; - foreach (var listener in GetListeners(workspace.Kind, _eventListeners)) - { - listener.StartListening(workspace, serviceOpt); - } - } - - public static IEnumerable> GetListeners( - string? workspaceKind, IEnumerable> eventListeners) - { - return (workspaceKind == null) ? [] : eventListeners - .Where(l => l.Metadata.WorkspaceKinds.Contains(workspaceKind)) - .Select(l => l.Value) - .OfType>(); - } + public static IEnumerable GetListeners( + string? workspaceKind, IEnumerable> eventListeners) + { + return (workspaceKind == null) ? [] : eventListeners + .Where(l => l.Metadata.WorkspaceKinds.Contains(workspaceKind)) + .Select(l => l.Value); + } - internal TestAccessor GetTestAccessor() - { - return new TestAccessor(this); - } + internal TestAccessor GetTestAccessor() + { + return new TestAccessor(this); + } - internal readonly struct TestAccessor - { - private readonly EventListenerTracker _eventListenerTracker; + internal readonly struct TestAccessor + { + private readonly EventListenerTracker _eventListenerTracker; - internal TestAccessor(EventListenerTracker eventListenerTracker) - => _eventListenerTracker = eventListenerTracker; + internal TestAccessor(EventListenerTracker eventListenerTracker) + => _eventListenerTracker = eventListenerTracker; - internal ref readonly ImmutableArray> EventListeners - => ref _eventListenerTracker._eventListeners; - } + internal ref readonly ImmutableArray> EventListeners + => ref _eventListenerTracker._eventListeners; } } diff --git a/src/Workspaces/Core/Portable/Workspace/Host/EventListener/IEventListener.cs b/src/Workspaces/Core/Portable/Workspace/Host/EventListener/IEventListener.cs index 29ed8b1a9dac9..7ee76dbd2b946 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/EventListener/IEventListener.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/EventListener/IEventListener.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.Host; /// @@ -13,4 +11,6 @@ namespace Microsoft.CodeAnalysis.Host; /// internal interface IEventListener { + void StartListening(Workspace workspace); + void StopListening(Workspace workspace); } diff --git a/src/Workspaces/Core/Portable/Workspace/Host/EventListener/IEventListenerStoppable.cs b/src/Workspaces/Core/Portable/Workspace/Host/EventListener/IEventListenerStoppable.cs deleted file mode 100644 index 5456c01c6f56c..0000000000000 --- a/src/Workspaces/Core/Portable/Workspace/Host/EventListener/IEventListenerStoppable.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#nullable disable - -namespace Microsoft.CodeAnalysis.Host; - -/// -/// provide a way for to mark it as stoppable -/// -/// for example, if the service is used for is a disposable -/// service, the service can call Stop when the service go away -/// -internal interface IEventListenerStoppable -{ - void StopListening(Workspace workspace); -} diff --git a/src/Workspaces/Core/Portable/Workspace/Host/EventListener/IEventListener`1.cs b/src/Workspaces/Core/Portable/Workspace/Host/EventListener/IEventListener`1.cs deleted file mode 100644 index bc2f1f407573b..0000000000000 --- a/src/Workspaces/Core/Portable/Workspace/Host/EventListener/IEventListener`1.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#nullable disable - -namespace Microsoft.CodeAnalysis.Host; - -/// -/// provide a way for features to lazily subscribe to a service event for particular workspace -/// -/// see for supported services -/// -internal interface IEventListener : IEventListener -{ - void StartListening(Workspace workspace, TService serviceOpt); -} diff --git a/src/Workspaces/Core/Portable/Workspace/Host/EventListener/IWorkspaceEventListenerProvider.cs b/src/Workspaces/Core/Portable/Workspace/Host/EventListener/IWorkspaceEventListenerProvider.cs index 48fc12f4b5475..b68a7371e27a0 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/EventListener/IWorkspaceEventListenerProvider.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/EventListener/IWorkspaceEventListenerProvider.cs @@ -2,76 +2,67 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Composition; using Microsoft.CodeAnalysis.Host.Mef; -namespace Microsoft.CodeAnalysis.Host +namespace Microsoft.CodeAnalysis.Host; + +/// +/// Ensure is called for the workspace +/// +internal interface IWorkspaceEventListenerService : IWorkspaceService +{ + void EnsureListeners(); + void Stop(); +} + +[ExportWorkspaceServiceFactory(typeof(IWorkspaceEventListenerService), layer: ServiceLayer.Default), Shared] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class DefaultWorkspaceEventListenerServiceFactory( + [ImportMany] IEnumerable> eventListeners) : IWorkspaceServiceFactory { - /// - /// Ensure is called for the workspace - /// - internal interface IWorkspaceEventListenerService : IWorkspaceService + public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) { - void EnsureListeners(); - void Stop(); + var workspace = workspaceServices.Workspace; + return new Service(workspace, EventListenerTracker.GetListeners(workspace.Kind, eventListeners)); } - [ExportWorkspaceServiceFactory(typeof(IWorkspaceEventListenerService), layer: ServiceLayer.Default), Shared] - [method: ImportingConstructor] - [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - internal sealed class DefaultWorkspaceEventListenerServiceFactory( - [ImportMany] IEnumerable> eventListeners) : IWorkspaceServiceFactory + internal sealed class Service(Workspace workspace, IEnumerable eventListeners) : IWorkspaceEventListenerService { - public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) - { - var workspace = workspaceServices.Workspace; - return new Service(workspace, EventListenerTracker.GetListeners(workspace.Kind, eventListeners)); - } + private readonly object _gate = new(); + private bool _initialized = false; + private readonly ImmutableArray _eventListeners = [.. eventListeners]; - internal sealed class Service(Workspace workspace, IEnumerable> eventListeners) : IWorkspaceEventListenerService + public void EnsureListeners() { - private readonly object _gate = new(); - private bool _initialized = false; - private readonly ImmutableArray> _eventListeners = [.. eventListeners]; - - public void EnsureListeners() + lock (_gate) { - lock (_gate) + if (_initialized) { - if (_initialized) - { - // already initialized - return; - } - - _initialized = true; + // already initialized + return; } - foreach (var listener in _eventListeners) - { - listener.StartListening(workspace, serviceOpt: null); - } + _initialized = true; } - public void Stop() + foreach (var listener in _eventListeners) + listener.StartListening(workspace); + } + + public void Stop() + { + lock (_gate) { - lock (_gate) + // If we were never initialized, then there's nothing to do + if (_initialized) { - if (!_initialized) - { - // never initialized. nothing to do - return; - } - - foreach (var listener in _eventListeners.OfType()) - { + foreach (var listener in _eventListeners) listener.StopListening(workspace); - } } } } diff --git a/src/Workspaces/Core/Portable/Workspace/Host/HostServices.cs b/src/Workspaces/Core/Portable/Workspace/Host/HostServices.cs index 7e433f92f2b14..d2b49dc35382a 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/HostServices.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/HostServices.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.Host; /// diff --git a/src/Workspaces/Core/Portable/Workspace/Host/Mef/ILanguageServiceFactory.cs b/src/Workspaces/Core/Portable/Workspace/Host/Mef/ILanguageServiceFactory.cs index 5917bff8aa89b..ad56650e5911f 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/Mef/ILanguageServiceFactory.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/Mef/ILanguageServiceFactory.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.Host.Mef; /// diff --git a/src/Workspaces/Core/Portable/Workspace/Host/Mef/IWorkspaceServiceFactory.cs b/src/Workspaces/Core/Portable/Workspace/Host/Mef/IWorkspaceServiceFactory.cs index 271ad1bf80719..bad0c61f57215 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/Mef/IWorkspaceServiceFactory.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/Mef/IWorkspaceServiceFactory.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.Host.Mef; /// diff --git a/src/Workspaces/Core/Portable/Workspace/Host/Metadata/DefaultAnalyzerService.cs b/src/Workspaces/Core/Portable/Workspace/Host/Metadata/DefaultAnalyzerService.cs index 55d4ea4546492..4e50f52536036 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/Metadata/DefaultAnalyzerService.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/Metadata/DefaultAnalyzerService.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.Composition; using Microsoft.CodeAnalysis.Host.Mef; @@ -13,7 +11,7 @@ namespace Microsoft.CodeAnalysis.Host; [ExportWorkspaceService(typeof(IAnalyzerService)), Shared] internal sealed class DefaultAnalyzerService : IAnalyzerService { - private readonly DefaultAnalyzerAssemblyLoader _loader = new(); + private readonly AnalyzerAssemblyLoader _loader = new(); [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] diff --git a/src/Workspaces/Core/Portable/Workspace/Host/Metadata/IAnalyzerAssemblyLoaderProvider.cs b/src/Workspaces/Core/Portable/Workspace/Host/Metadata/IAnalyzerAssemblyLoaderProvider.cs index 9acb18e7fd0e8..6a74e816a1bf7 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/Metadata/IAnalyzerAssemblyLoaderProvider.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/Metadata/IAnalyzerAssemblyLoaderProvider.cs @@ -35,12 +35,13 @@ internal interface IAnalyzerAssemblyLoaderProvider : IWorkspaceService /// internal abstract class AbstractAnalyzerAssemblyLoaderProvider : IAnalyzerAssemblyLoaderProvider { - private readonly ImmutableArray _externalResolvers; +#if NET private readonly Lazy _shadowCopyLoader; + private readonly ImmutableArray _assemblyResolvers; - public AbstractAnalyzerAssemblyLoaderProvider(IEnumerable externalResolvers) + public AbstractAnalyzerAssemblyLoaderProvider(IEnumerable assemblyResolvers) { - _externalResolvers = [.. externalResolvers]; + _assemblyResolvers = [.. assemblyResolvers]; _shadowCopyLoader = new(CreateNewShadowCopyLoader); } @@ -48,17 +49,46 @@ public IAnalyzerAssemblyLoaderInternal SharedShadowCopyLoader => _shadowCopyLoader.Value; public IAnalyzerAssemblyLoaderInternal CreateNewShadowCopyLoader() - => this.WrapLoader(DefaultAnalyzerAssemblyLoader.CreateNonLockingLoader( + => this.WrapLoader(AnalyzerAssemblyLoader.CreateNonLockingLoader( Path.Combine(Path.GetTempPath(), nameof(Roslyn), "AnalyzerAssemblyLoader"), - _externalResolvers)); + pathResolvers: default, + _assemblyResolvers)); +#else + private readonly Lazy _shadowCopyLoader; + + public AbstractAnalyzerAssemblyLoaderProvider() + { + _shadowCopyLoader = new(CreateNewShadowCopyLoader); + } + + public IAnalyzerAssemblyLoaderInternal SharedShadowCopyLoader + => _shadowCopyLoader.Value; + + public IAnalyzerAssemblyLoaderInternal CreateNewShadowCopyLoader() + => this.WrapLoader(AnalyzerAssemblyLoader.CreateNonLockingLoader( + Path.Combine(Path.GetTempPath(), nameof(Roslyn), "AnalyzerAssemblyLoader"), + pathResolvers: default)); +#endif 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); +internal sealed class DefaultAnalyzerAssemblyLoaderProvider : AbstractAnalyzerAssemblyLoaderProvider +{ +#if NET + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public DefaultAnalyzerAssemblyLoaderProvider([ImportMany] IEnumerable assemblyResolvers) + : base(assemblyResolvers) + { + } +#else + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public DefaultAnalyzerAssemblyLoaderProvider() + { + } +#endif +} diff --git a/src/Workspaces/Core/Portable/Workspace/Host/Metadata/IAnalyzerService.cs b/src/Workspaces/Core/Portable/Workspace/Host/Metadata/IAnalyzerService.cs index 9fbfd46fab7b6..f4c21256290f5 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/Metadata/IAnalyzerService.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/Metadata/IAnalyzerService.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.Host; // Obsolete - used only for MSBuild workspace extensibility, diff --git a/src/Workspaces/Core/Portable/Workspace/Host/Metadata/IMetadataService.cs b/src/Workspaces/Core/Portable/Workspace/Host/Metadata/IMetadataService.cs index be13a41b192b2..cfc670a491954 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/Metadata/IMetadataService.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/Metadata/IMetadataService.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.Host; internal interface IMetadataService : IWorkspaceService diff --git a/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/IPersistentStorageConfiguration.cs b/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/IPersistentStorageConfiguration.cs index 0e747988fbb70..d7cf48a9fd132 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/IPersistentStorageConfiguration.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/IPersistentStorageConfiguration.cs @@ -10,7 +10,6 @@ using System.Linq; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Storage; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Host; diff --git a/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/IPersistentStorageFaultInjectionService.cs b/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/IPersistentStorageFaultInjectionService.cs index 3b5ddfdb06549..d193b73108df5 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/IPersistentStorageFaultInjectionService.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/IPersistentStorageFaultInjectionService.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; namespace Microsoft.CodeAnalysis.Host; diff --git a/src/Workspaces/Core/Portable/Workspace/Host/TemporaryStorage/ITemporaryStorage.cs b/src/Workspaces/Core/Portable/Workspace/Host/TemporaryStorage/ITemporaryStorage.cs index d458ba5ca481c..dd5fbb1842f03 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/TemporaryStorage/ITemporaryStorage.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/TemporaryStorage/ITemporaryStorage.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.IO; using System.Threading; diff --git a/src/Workspaces/Core/Portable/Workspace/IsolatedAnalyzerFileReference.cs b/src/Workspaces/Core/Portable/Workspace/IsolatedAnalyzerFileReference.cs index 6db69d9a65935..614c890088fa6 100644 --- a/src/Workspaces/Core/Portable/Workspace/IsolatedAnalyzerFileReference.cs +++ b/src/Workspaces/Core/Portable/Workspace/IsolatedAnalyzerFileReference.cs @@ -7,9 +7,9 @@ using System; using System.Collections.Immutable; using System.Runtime.CompilerServices; -using Microsoft.CodeAnalysis.Diagnostics; using System.Runtime.Loader; -using Roslyn.Utilities; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Threading; namespace Microsoft.CodeAnalysis; diff --git a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/FileWatchedPortableExecutableReferenceFactory.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/FileWatchedPortableExecutableReferenceFactory.cs index 66880110e594b..f68e3fa6861e7 100644 --- a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/FileWatchedPortableExecutableReferenceFactory.cs +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/FileWatchedPortableExecutableReferenceFactory.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ProjectSystem; diff --git a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/IAnalyzerAssemblyRedirector.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/IAnalyzerAssemblyRedirector.cs new file mode 100644 index 0000000000000..c1881e5ccc073 --- /dev/null +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/IAnalyzerAssemblyRedirector.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. + +namespace Microsoft.CodeAnalysis.Workspaces.AnalyzerRedirecting; + +/// +/// Any MEF component implementing this interface will be used to redirect analyzer assemblies. +/// +/// +/// The redirected path is passed to the compiler where it is processed in the standard way, +/// e.g., the redirected assembly is shadow copied before it's loaded +/// (this could be improved in the future since shadow copying redirected assemblies is usually unnecessary). +/// +internal interface IAnalyzerAssemblyRedirector +{ + /// + /// Original full path of the analyzer assembly. + /// + /// + /// The redirected full path of the analyzer assembly + /// or if this instance cannot redirect the given assembly. + /// + /// + /// + /// If two redirectors return different paths for the same assembly, no redirection will be performed. + /// + /// + /// No thread switching inside this method is allowed. + /// + /// + string? RedirectPath(string fullPath); +} diff --git a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/IRuleSetFile.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/IRuleSetFile.cs index 1bf90df106eb1..1394b208f1856 100644 --- a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/IRuleSetFile.cs +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/IRuleSetFile.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Immutable; diff --git a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.cs index aa75a5cd9f367..fdf1663a2a0b5 100644 --- a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.cs +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.PooledObjects; @@ -22,6 +23,7 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Telemetry; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Utilities; using static Microsoft.CodeAnalysis.Workspaces.ProjectSystem.ProjectSystemProjectFactory; @@ -1126,9 +1128,43 @@ private OneOrMany GetMappedAnalyzerPaths(string fullPath) return GetMappedRazorSourceGenerator(fullPath); } + if (TryRedirectAnalyzerAssembly(fullPath) is { } redirectedPath) + { + return OneOrMany.Create(redirectedPath); + } + return OneOrMany.Create(fullPath); } + private string? TryRedirectAnalyzerAssembly(string fullPath) + { + string? redirectedPath = null; + + foreach (var redirector in _hostInfo.AnalyzerAssemblyRedirectors) + { + try + { + if (redirector.RedirectPath(fullPath) is { } currentlyRedirectedPath) + { + if (redirectedPath == null) + { + redirectedPath = currentlyRedirectedPath; + } + else if (redirectedPath != currentlyRedirectedPath) + { + throw new InvalidOperationException($"Multiple redirectors disagree on the path to redirect '{fullPath}' to ('{redirectedPath}' vs '{currentlyRedirectedPath}')."); + } + } + } + catch (Exception ex) when (FatalError.ReportAndCatch(ex, ErrorSeverity.General)) + { + // Ignore if the external redirector throws. + } + } + + return redirectedPath; + } + private static readonly string s_csharpCodeStyleAnalyzerSdkDirectory = CreateDirectoryPathFragment("Sdks", "Microsoft.NET.Sdk", "codestyle", "cs"); private static readonly string s_visualBasicCodeStyleAnalyzerSdkDirectory = CreateDirectoryPathFragment("Sdks", "Microsoft.NET.Sdk", "codestyle", "vb"); diff --git a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectFactory.ProjectUpdateState.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectFactory.ProjectUpdateState.cs index 93962e6fa2e0f..b77f38e86c83c 100644 --- a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectFactory.ProjectUpdateState.cs +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectFactory.ProjectUpdateState.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using Microsoft.CodeAnalysis.Diagnostics; namespace Microsoft.CodeAnalysis.Workspaces.ProjectSystem; diff --git a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectFactory.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectFactory.cs index 6b47e6cfdfd01..a08cafbe655a5 100644 --- a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectFactory.cs +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectFactory.cs @@ -3,7 +3,6 @@ // 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; @@ -603,11 +602,12 @@ private static bool CanConvertMetadataReferenceToProjectReference(Solution solut Contract.ThrowIfNull(projectWithMetadataReference); Contract.ThrowIfNull(referencedProject); - // We don't want to convert a metadata reference to a project reference if the project being referenced isn't something - // we can create a Compilation for. For example, if we have a C# project, and it's referencing a F# project via a metadata reference - // everything would be fine if we left it a metadata reference. Converting it to a project reference means we couldn't create a Compilation - // anymore in the IDE, since the C# compilation would need to reference an F# compilation. F# projects referencing other F# projects though - // do expect this to work, and so we'll always allow references through of the same language. + // We don't want to convert a metadata reference to a project reference if the project being referenced isn't + // something we can create a Compilation for. For example, if we have a C# project, and it's referencing a F# + // project via a metadata reference everything would be fine if we left it a metadata reference. Converting it + // to a project reference means we couldn't create a Compilation anymore in the IDE, since the C# compilation + // would need to reference an F# compilation. F# projects referencing other F# projects though do expect this to + // work, and so we'll always allow references through of the same language. if (projectWithMetadataReference.Language != referencedProject.Language) { if (projectWithMetadataReference.LanguageServices.GetService() != null && @@ -618,6 +618,12 @@ private static bool CanConvertMetadataReferenceToProjectReference(Solution solut } } + // Getting a metadata reference from a 'module' is not supported from the compilation layer. Nor is emitting a + // 'metadata-only' stream for it (a 'skeleton' reference). So converting a NetModule reference to a project + // reference won't actually help us out. Best to keep this as a plain metadata reference. + if (referencedProject.CompilationOptions?.OutputKind == OutputKind.NetModule) + return false; + // If this is going to cause a circular reference, also disallow it if (solution.GetProjectDependencyGraph().GetProjectsThatThisProjectTransitivelyDependsOn(referencedProjectId).Contains(projectIdWithMetadataReference)) { diff --git a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectHostInfo.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectHostInfo.cs index fc3f0a58ef18a..5bb5f96513091 100644 --- a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectHostInfo.cs +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectHostInfo.cs @@ -6,9 +6,11 @@ using System.Collections.Immutable; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Workspaces.AnalyzerRedirecting; namespace Microsoft.CodeAnalysis.Workspaces.ProjectSystem; internal record ProjectSystemHostInfo( ImmutableArray> DynamicFileInfoProviders, - IHostDiagnosticAnalyzerProvider HostDiagnosticAnalyzerProvider); + IHostDiagnosticAnalyzerProvider HostDiagnosticAnalyzerProvider, + ImmutableArray AnalyzerAssemblyRedirectors); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/Document.cs b/src/Workspaces/Core/Portable/Workspace/Solution/Document.cs index 59be45860e30e..c966aea508619 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/Document.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/Document.cs @@ -7,7 +7,6 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Diagnostics; diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/DocumentDiagnostic.cs b/src/Workspaces/Core/Portable/Workspace/Solution/DocumentDiagnostic.cs index 6a616117f2836..0ed4eab2779d2 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/DocumentDiagnostic.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/DocumentDiagnostic.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; public class DocumentDiagnostic(WorkspaceDiagnosticKind kind, string message, DocumentId documentId) : WorkspaceDiagnostic(kind, message) diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState.EquivalenceResult.cs b/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState.EquivalenceResult.cs index 730d282e1330c..b4f7e9449b0a7 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState.EquivalenceResult.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState.EquivalenceResult.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; internal partial class DocumentState diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState.cs index 07baa5aaf65f9..df54d1161d0ef 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState.cs @@ -3,9 +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.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Text; @@ -497,6 +495,20 @@ internal DocumentState UpdateTree(SyntaxNode newRoot, PreservationMode mode) // use the encoding that we get from the new root var encoding = newRoot.SyntaxTree.Encoding; + if (encoding is null) + { + // The new tree doesn't specify an encoding. For these cases, continue to use the previous encoding of the + // document. + if (TryGetSyntaxTree(out var priorTree)) + { + // this is most likely available since UpdateTree is normally called after modifying the existing tree. + encoding = priorTree.Encoding; + } + else if (TryGetText(out var priorText)) + { + encoding = priorText.Encoding; + } + } var syntaxTreeFactory = LanguageServices.GetRequiredService(); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/IDocumentTextDifferencingService.cs b/src/Workspaces/Core/Portable/Workspace/Solution/IDocumentTextDifferencingService.cs index d89e12d177a2a..b84bd15888288 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/IDocumentTextDifferencingService.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/IDocumentTextDifferencingService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/PreservationMode.cs b/src/Workspaces/Core/Portable/Workspace/Solution/PreservationMode.cs index 5dd506da3a935..815ab649152b2 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/PreservationMode.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/PreservationMode.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; /// diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/Project.EquivalenceResult.cs b/src/Workspaces/Core/Portable/Workspace/Solution/Project.EquivalenceResult.cs index dd937f489b9b2..681cc69572653 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/Project.EquivalenceResult.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/Project.EquivalenceResult.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; public partial class Project diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/Project.cs b/src/Workspaces/Core/Portable/Workspace/Solution/Project.cs index c76d53fcca168..7cde4a683971c 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/Project.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/Project.cs @@ -544,34 +544,6 @@ public Task GetDependentSemanticVersionAsync(CancellationToken can public Task GetSemanticVersionAsync(CancellationToken cancellationToken = default) => State.GetSemanticVersionAsync(cancellationToken); - /// - /// Calculates a checksum that contains a project's checksum along with a checksum for each of the project's - /// transitive dependencies. - /// - /// - /// This checksum calculation can be used for cases where a feature needs to know if the semantics in this project - /// changed. For example, for diagnostics or caching computed semantic data. The goal is to ensure that changes to - /// - /// Files inside the current project - /// Project properties of the current project - /// Visible files in referenced projects - /// Project properties in referenced projects - /// - /// are reflected in the metadata we keep so that comparing solutions accurately tells us when we need to recompute - /// semantic work. - /// - /// This method of checking for changes has a few important properties that differentiate it from other methods of determining project version. - /// - /// Changes to methods inside the current project will be reflected to compute updated diagnostics. - /// does not change as it only returns top level changes. - /// Reloading a project without making any changes will re-use cached diagnostics. - /// changes as the project is removed, then added resulting in a version change. - /// - /// - /// - internal Task GetDependentChecksumAsync(CancellationToken cancellationToken) - => Solution.CompilationState.GetDependentChecksumAsync(this.Id, cancellationToken); - /// /// Creates a new instance of this project updated to have the new assembly name. /// @@ -830,9 +802,6 @@ internal StructuredAnalyzerConfigOptions GetFallbackAnalyzerOptions() private string GetDebuggerDisplay() => this.Name; - internal SkippedHostAnalyzersInfo GetSkippedAnalyzersInfo(DiagnosticAnalyzerInfoCache infoCache) - => Solution.SolutionState.Analyzers.GetSkippedAnalyzersInfo(this, infoCache); - internal async ValueTask GetDocumentAsync(ImmutableArray contentHash, CancellationToken cancellationToken) { var documentId = await State.GetDocumentIdAsync(contentHash, cancellationToken).ConfigureAwait(false); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectCone.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectCone.cs index 19b6c7f9ee372..34bdf18a7e6d0 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectCone.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectCone.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Frozen; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis; diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph_AddProject.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph_AddProject.cs index a4f220b6b68d8..da0a6f30bc601 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph_AddProject.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph_AddProject.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Immutable; - namespace Microsoft.CodeAnalysis; public partial class ProjectDependencyGraph diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDiagnostic.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDiagnostic.cs index 510311dd2dc0b..29454c0e31cb8 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDiagnostic.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDiagnostic.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; public class ProjectDiagnostic(WorkspaceDiagnosticKind kind, string message, ProjectId projectId) : WorkspaceDiagnostic(kind, message) diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs index 94bd2575abfd3..b764e8ab829ea 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs @@ -116,7 +116,7 @@ public ProjectState(LanguageServices languageServices, ProjectInfo projectInfo, DocumentStates = new TextDocumentStates(projectInfoFixed.Documents, info => CreateDocument(info, parseOptions, loadTextOptions)); AdditionalDocumentStates = new TextDocumentStates(projectInfoFixed.AdditionalDocuments, info => new AdditionalDocumentState(languageServices.SolutionServices, info, loadTextOptions)); - _lazyLatestDocumentVersion = AsyncLazy.Create(static (self, c) => ComputeLatestDocumentVersionAsync(self.DocumentStates, self.AdditionalDocumentStates, c), arg: this); + _lazyLatestDocumentVersion = AsyncLazy.Create(static async (self, c) => await ComputeLatestDocumentVersionAsync(self.DocumentStates, self.AdditionalDocumentStates, c).ConfigureAwait(false), arg: this); _lazyLatestDocumentTopLevelChangeVersion = AsyncLazy.Create(static (self, c) => ComputeLatestDocumentTopLevelChangeVersionAsync(self.DocumentStates, self.AdditionalDocumentStates, c), arg: this); // ownership of information on document has moved to project state. clear out documentInfo the state is @@ -220,7 +220,7 @@ private ProjectInfo FixProjectInfo(ProjectInfo projectInfo) return projectInfo; } - private static async Task ComputeLatestDocumentVersionAsync(TextDocumentStates documentStates, TextDocumentStates additionalDocumentStates, CancellationToken cancellationToken) + private static async ValueTask ComputeLatestDocumentVersionAsync(TextDocumentStates documentStates, TextDocumentStates additionalDocumentStates, CancellationToken cancellationToken) { // this may produce a version that is out of sync with the actual Document versions. var latestVersion = VersionStamp.Default; @@ -1090,8 +1090,8 @@ private void GetLatestDependentVersions( if (recalculateDocumentVersion) { - dependentDocumentVersion = AsyncLazy.Create(static (arg, cancellationToken) => - ComputeLatestDocumentVersionAsync(arg.newDocumentStates, arg.newAdditionalDocumentStates, cancellationToken), + dependentDocumentVersion = AsyncLazy.Create(static async (arg, cancellationToken) => + await ComputeLatestDocumentVersionAsync(arg.newDocumentStates, arg.newAdditionalDocumentStates, cancellationToken).ConfigureAwait(false), arg: (newDocumentStates, newAdditionalDocumentStates)); } else if (contentChanged) diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.ICompilationTracker.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.ICompilationTracker.cs index 66568e3f6d5f7..2f92683ad69dd 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.ICompilationTracker.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.ICompilationTracker.cs @@ -53,7 +53,6 @@ bool ContainsAssemblyOrModuleOrDynamic( Task GetDependentVersionAsync(SolutionCompilationState compilationState, CancellationToken cancellationToken); Task GetDependentSemanticVersionAsync(SolutionCompilationState compilationState, CancellationToken cancellationToken); - Task GetDependentChecksumAsync(SolutionCompilationState compilationState, CancellationToken cancellationToken); /// /// Gets the source generator files generated by this . Fork(newProjectState, translate); + /// /// Creates a new instance of the compilation info, retaining any already built /// compilation state as the now 'old' state /// - public ICompilationTracker Fork( + public RegularCompilationTracker Fork( ProjectState newProjectState, TranslationAction? translate) { @@ -679,7 +683,10 @@ private async Task HasSuccessfullyLoadedSlowAsync( return finalState.HasSuccessfullyLoaded; } - public ICompilationTracker WithCreateCreationPolicy(bool forceRegeneration) + ICompilationTracker ICompilationTracker.WithCreateCreationPolicy(bool forceRegeneration) + => WithCreateCreationPolicy(forceRegeneration); + + public RegularCompilationTracker WithCreateCreationPolicy(bool forceRegeneration) { var state = this.ReadState(); @@ -735,7 +742,10 @@ public ICompilationTracker WithCreateCreationPolicy(bool forceRegeneration) skeletonReferenceCacheToClone: _skeletonReferenceCache); } - public ICompilationTracker WithDoNotCreateCreationPolicy() + ICompilationTracker ICompilationTracker.WithDoNotCreateCreationPolicy() + => WithDoNotCreateCreationPolicy(); + + public RegularCompilationTracker WithDoNotCreateCreationPolicy() { var state = this.ReadState(); @@ -1007,7 +1017,6 @@ public CompilationTrackerValidationException(string message, Exception inner) : private AsyncLazy? _lazyDependentVersion; private AsyncLazy? _lazyDependentSemanticVersion; - private AsyncLazy? _lazyDependentChecksum; public Task GetDependentVersionAsync( SolutionCompilationState compilationState, CancellationToken cancellationToken) @@ -1086,56 +1095,6 @@ private async Task ComputeDependentSemanticVersionAsync( return version; } - public Task GetDependentChecksumAsync( - SolutionCompilationState compilationState, CancellationToken cancellationToken) - { - if (_lazyDependentChecksum == null) - { - // note: solution is captured here, but it will go away once GetValueAsync executes. - Interlocked.CompareExchange( - ref _lazyDependentChecksum, - AsyncLazy.Create(static (arg, c) => - arg.self.ComputeDependentChecksumAsync(arg.SolutionState, c), - arg: (self: this, compilationState.SolutionState)), - null); - } - - return _lazyDependentChecksum.GetValueAsync(cancellationToken); - } - - private async Task ComputeDependentChecksumAsync(SolutionState solution, CancellationToken cancellationToken) - { - using var _ = ArrayBuilder.GetInstance(out var tempChecksumArray); - - // Get the checksum for the project itself. - var projectChecksum = await this.ProjectState.GetChecksumAsync(cancellationToken).ConfigureAwait(false); - tempChecksumArray.Add(projectChecksum); - - // Calculate a checksum this project and for each dependent project that could affect semantics for - // this project. Ensure that the checksum calculation orders the projects consistently so that we get - // the same checksum across sessions of VS. Note: we use the project filepath+name as a unique way - // to reference a project. This matches the logic in our persistence-service implemention as to how - // information is associated with a project. - var transitiveDependencies = solution.GetProjectDependencyGraph().GetProjectsThatThisProjectTransitivelyDependsOn(this.ProjectState.Id); - var orderedProjectIds = transitiveDependencies.OrderBy(id => - { - var depProject = solution.GetRequiredProjectState(id); - return (depProject.FilePath, depProject.Name); - }); - - foreach (var projectId in orderedProjectIds) - { - var referencedProject = solution.GetRequiredProjectState(projectId); - - // Note that these checksums should only actually be calculated once, if the project is unchanged - // the same checksum will be returned. - var referencedProjectChecksum = await referencedProject.GetChecksumAsync(cancellationToken).ConfigureAwait(false); - tempChecksumArray.Add(referencedProjectChecksum); - } - - return Checksum.Create(tempChecksumArray); - } - #endregion } } 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 32d50e7f8e9fd..dfb473ea9a080 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.TranslationAction_Actions.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.TranslationAction_Actions.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Utilities; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis; diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.WithFrozenSourceGeneratedDocumentsCompilationTracker.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.WithFrozenSourceGeneratedDocumentsCompilationTracker.cs index 0f56b6fa9968d..c16d37789870a 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.WithFrozenSourceGeneratedDocumentsCompilationTracker.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.WithFrozenSourceGeneratedDocumentsCompilationTracker.cs @@ -28,8 +28,6 @@ private sealed class WithFrozenSourceGeneratedDocumentsCompilationTracker : ICom { private readonly TextDocumentStates _replacementDocumentStates; - private AsyncLazy? _lazyDependentChecksum; - /// /// The lazily-produced compilation that has the generated document updated. This is initialized by call to /// . @@ -37,7 +35,7 @@ private sealed class WithFrozenSourceGeneratedDocumentsCompilationTracker : ICom [DisallowNull] private Compilation? _compilationWithReplacements; - public ICompilationTracker UnderlyingTracker { get; } + public RegularCompilationTracker UnderlyingTracker { get; } public ProjectState ProjectState => UnderlyingTracker.ProjectState; public GeneratorDriver? GeneratorDriver => UnderlyingTracker.GeneratorDriver; @@ -48,7 +46,7 @@ private sealed class WithFrozenSourceGeneratedDocumentsCompilationTracker : ICom private SkeletonReferenceCache _skeletonReferenceCache; public WithFrozenSourceGeneratedDocumentsCompilationTracker( - ICompilationTracker underlyingTracker, + RegularCompilationTracker underlyingTracker, TextDocumentStates replacementDocumentStates) { this.UnderlyingTracker = underlyingTracker; @@ -145,28 +143,6 @@ public Task GetDependentVersionAsync(SolutionCompilationState comp public Task GetDependentSemanticVersionAsync(SolutionCompilationState compilationState, CancellationToken cancellationToken) => UnderlyingTracker.GetDependentSemanticVersionAsync(compilationState, cancellationToken); - public Task GetDependentChecksumAsync(SolutionCompilationState compilationState, CancellationToken cancellationToken) - { - if (_lazyDependentChecksum == null) - { - var tmp = compilationState; // temp. local to avoid a closure allocation for the fast path - // note: solution is captured here, but it will go away once GetValueAsync executes. - Interlocked.CompareExchange( - ref _lazyDependentChecksum, - AsyncLazy.Create(static (arg, c) => - arg.self.ComputeDependentChecksumAsync(arg.tmp, c), - arg: (self: this, tmp)), - null); - } - - return _lazyDependentChecksum.GetValueAsync(cancellationToken); - } - - private async Task ComputeDependentChecksumAsync(SolutionCompilationState compilationState, CancellationToken cancellationToken) - => Checksum.Create( - await UnderlyingTracker.GetDependentChecksumAsync(compilationState, cancellationToken).ConfigureAwait(false), - (await _replacementDocumentStates.GetDocumentChecksumsAndIdsAsync(cancellationToken).ConfigureAwait(false)).Checksum); - public async ValueTask> GetSourceGeneratedDocumentStatesAsync( SolutionCompilationState compilationState, bool withFrozenSourceGeneratedDocuments, CancellationToken cancellationToken) { diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs index 83eb6fae6fa13..95269c31933cc 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs @@ -19,6 +19,7 @@ using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Utilities; using ReferenceEqualityComparer = Roslyn.Utilities.ReferenceEqualityComparer; @@ -1109,9 +1110,6 @@ public Task GetDependentVersionAsync(ProjectId projectId, Cancella public Task GetDependentSemanticVersionAsync(ProjectId projectId, CancellationToken cancellationToken) => this.GetCompilationTracker(projectId).GetDependentSemanticVersionAsync(this, cancellationToken); - public Task GetDependentChecksumAsync(ProjectId projectId, CancellationToken cancellationToken) - => this.GetCompilationTracker(projectId).GetDependentChecksumAsync(this, cancellationToken); - public bool TryGetCompilation(ProjectId projectId, [NotNullWhen(returnValue: true)] out Compilation? compilation) { this.SolutionState.CheckContainsProject(projectId); @@ -1216,6 +1214,17 @@ public ValueTask> GetSourceGeneratorDiagnosticsAsync( { try { + // Getting a metadata reference from a 'module' is not supported from the compilation layer. Nor is + // emitting a 'metadata-only' stream for it (a 'skeleton' reference). So we just bail here. Note: this is + // not a common user scenario (they have to be explicitly creating 'modules' which are a feature practically + // never used anymore). So it's not worthwhile trying to merge the referenced module into the current + // compilation in any fashion. + // + // Note: ProjectSystemProjectFactory.CanConvertMetadataReferenceToProjectReference attempts to prevent this + // scenario from arising. However, this code just acts as a final failsafe to ensure we don't crash. + if (tracker.ProjectState.CompilationOptions?.OutputKind == OutputKind.NetModule) + return null; + // If same language then we can wrap the other project's compilation into a compilation reference if (tracker.ProjectState.LanguageServices == fromProject.LanguageServices) { @@ -1376,7 +1385,12 @@ public SolutionCompilationState WithFrozenSourceGeneratedDocuments( existingTracker = CreateCompilationTracker(projectId, arg.SolutionState); } - trackerMap[projectId] = new WithFrozenSourceGeneratedDocumentsCompilationTracker(existingTracker, new(documentStatesForProject)); + // We should never be wrapping a WithFrozenSourceGeneratedDocumentsCompilationTracker with another + // WithFrozenSourceGeneratedDocumentsCompilationTracker. If we do, that's a straight bug that + // should fail immediately. So blind casting is here is appropriate. + var regularCompilationTracker = (RegularCompilationTracker)existingTracker; + trackerMap[projectId] = new WithFrozenSourceGeneratedDocumentsCompilationTracker( + regularCompilationTracker, new(documentStatesForProject)); } }, (documentStatesByProjectId, this.SolutionState), diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState_Checksum.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState_Checksum.cs index ac0918671d4ff..db9b1b5dc66b1 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState_Checksum.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState_Checksum.cs @@ -6,12 +6,10 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Serialization; using Roslyn.Utilities; diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/Solution_SemanticModelCaching.cs b/src/Workspaces/Core/Portable/Workspace/Solution/Solution_SemanticModelCaching.cs index 92c49675d850a..bd71bc3fdc0d9 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/Solution_SemanticModelCaching.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/Solution_SemanticModelCaching.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis; diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SourceGeneratedDocumentState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SourceGeneratedDocumentState.cs index deddcb770fcfe..2dac3eca73250 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SourceGeneratedDocumentState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SourceGeneratedDocumentState.cs @@ -3,11 +3,9 @@ // 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; diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SourceGeneratorExecutionVersion.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SourceGeneratorExecutionVersion.cs index db17349aa041e..a8eabc3e626c2 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SourceGeneratorExecutionVersion.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SourceGeneratorExecutionVersion.cs @@ -46,6 +46,8 @@ public static SourceGeneratorExecutionVersion ReadFrom(ObjectReader reader) public override string ToString() => $"{MajorVersion}.{MinorVersion}"; + + public Checksum Checksum => new(MajorVersion, MinorVersion); } /// diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SourceGeneratorIdentity.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SourceGeneratorIdentity.cs index 90115c90fed6c..8a6aa479fc826 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SourceGeneratorIdentity.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SourceGeneratorIdentity.cs @@ -7,7 +7,6 @@ using System.Runtime.Serialization; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.PooledObjects; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis; diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/TextDifferenceTypes.cs b/src/Workspaces/Core/Portable/Workspace/Solution/TextDifferenceTypes.cs index 0d07214dae653..133f095641f65 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/TextDifferenceTypes.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/TextDifferenceTypes.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; namespace Microsoft.CodeAnalysis; diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocument.cs b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocument.cs index d746eb8576229..3a9709df1273e 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocument.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocument.cs @@ -8,7 +8,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis; @@ -90,8 +89,8 @@ internal SourceText GetTextSynchronously(CancellationToken cancellationToken) /// /// Gets the version of the document's text. /// - public Task GetTextVersionAsync(CancellationToken cancellationToken = default) - => State.GetTextVersionAsync(cancellationToken); + public async Task GetTextVersionAsync(CancellationToken cancellationToken = default) + => await State.GetTextVersionAsync(cancellationToken).ConfigureAwait(false); /// /// Fetches the current version for the document synchronously. diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentState.cs index dc92003f45237..cfc5deda9b82a 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentState.cs @@ -123,7 +123,7 @@ public VersionStamp GetTextVersionSynchronously(CancellationToken cancellationTo return textAndVersion.Version; } - public async Task GetTextVersionAsync(CancellationToken cancellationToken) + public async ValueTask GetTextVersionAsync(CancellationToken cancellationToken) { // try fast path first if (TryGetTextVersion(out var version)) diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/VersionSource/RecoverableTextAndVersion.RecoverableText.cs b/src/Workspaces/Core/Portable/Workspace/Solution/VersionSource/RecoverableTextAndVersion.RecoverableText.cs index f8ded8d24ae96..6997357e85bf7 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/VersionSource/RecoverableTextAndVersion.RecoverableText.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/VersionSource/RecoverableTextAndVersion.RecoverableText.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis; diff --git a/src/Workspaces/Core/Portable/Workspace/SourceGeneratorExecution.cs b/src/Workspaces/Core/Portable/Workspace/SourceGeneratorExecution.cs index 500c1abdde35c..845686f901a96 100644 --- a/src/Workspaces/Core/Portable/Workspace/SourceGeneratorExecution.cs +++ b/src/Workspaces/Core/Portable/Workspace/SourceGeneratorExecution.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Roslyn.Utilities; - namespace Microsoft.CodeAnalysis.Host; internal enum SourceGeneratorExecutionPreference diff --git a/src/Workspaces/Core/Portable/Workspace/TextExtensions.cs b/src/Workspaces/Core/Portable/Workspace/TextExtensions.cs index da91f2c6f1a09..a97af4ec15f2f 100644 --- a/src/Workspaces/Core/Portable/Workspace/TextExtensions.cs +++ b/src/Workspaces/Core/Portable/Workspace/TextExtensions.cs @@ -5,7 +5,6 @@ using System.Collections.Immutable; using System.Threading; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Text; diff --git a/src/Workspaces/Core/Portable/Workspace/Workspace.cs b/src/Workspaces/Core/Portable/Workspace/Workspace.cs index 2e71d615b880c..3c7117483f2af 100644 --- a/src/Workspaces/Core/Portable/Workspace/Workspace.cs +++ b/src/Workspaces/Core/Portable/Workspace/Workspace.cs @@ -21,6 +21,7 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis; diff --git a/src/Workspaces/Core/Portable/Workspace/WorkspaceChangeKind.cs b/src/Workspaces/Core/Portable/Workspace/WorkspaceChangeKind.cs index 90f0a0d17832f..f6331752ea5f4 100644 --- a/src/Workspaces/Core/Portable/Workspace/WorkspaceChangeKind.cs +++ b/src/Workspaces/Core/Portable/Workspace/WorkspaceChangeKind.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; public enum WorkspaceChangeKind diff --git a/src/Workspaces/Core/Portable/Workspace/WorkspaceDiagnostic.cs b/src/Workspaces/Core/Portable/Workspace/WorkspaceDiagnostic.cs index c9d6229cf663e..fdbdd0243cb94 100644 --- a/src/Workspaces/Core/Portable/Workspace/WorkspaceDiagnostic.cs +++ b/src/Workspaces/Core/Portable/Workspace/WorkspaceDiagnostic.cs @@ -2,10 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - -using Roslyn.Utilities; - namespace Microsoft.CodeAnalysis; public class WorkspaceDiagnostic(WorkspaceDiagnosticKind kind, string message) diff --git a/src/Workspaces/Core/Portable/Workspace/WorkspaceDiagnosticDescriptors.cs b/src/Workspaces/Core/Portable/Workspace/WorkspaceDiagnosticDescriptors.cs index 4aa0dce91ecaf..725380a9a9a5d 100644 --- a/src/Workspaces/Core/Portable/Workspace/WorkspaceDiagnosticDescriptors.cs +++ b/src/Workspaces/Core/Portable/Workspace/WorkspaceDiagnosticDescriptors.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; internal sealed class WorkspaceDiagnosticDescriptors diff --git a/src/Workspaces/Core/Portable/Workspace/WorkspaceDiagnosticEventArgs.cs b/src/Workspaces/Core/Portable/Workspace/WorkspaceDiagnosticEventArgs.cs index 60fdf17281c9b..2e5bd0004c57e 100644 --- a/src/Workspaces/Core/Portable/Workspace/WorkspaceDiagnosticEventArgs.cs +++ b/src/Workspaces/Core/Portable/Workspace/WorkspaceDiagnosticEventArgs.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; namespace Microsoft.CodeAnalysis; diff --git a/src/Workspaces/Core/Portable/Workspace/Workspace_Events.cs b/src/Workspaces/Core/Portable/Workspace/Workspace_Events.cs index a54a64ccfc8bf..aef7f056656e1 100644 --- a/src/Workspaces/Core/Portable/Workspace/Workspace_Events.cs +++ b/src/Workspaces/Core/Portable/Workspace/Workspace_Events.cs @@ -19,6 +19,7 @@ public abstract partial class Workspace private readonly EventMap _eventMap = new(); private const string WorkspaceChangeEventName = "WorkspaceChanged"; + private const string WorkspaceChangedImmediateEventName = "WorkspaceChangedImmediate"; private const string WorkspaceFailedEventName = "WorkspaceFailed"; private const string DocumentOpenedEventName = "DocumentOpened"; private const string DocumentClosedEventName = "DocumentClosed"; @@ -42,6 +43,24 @@ public event EventHandler WorkspaceChanged } } + /// + /// An event raised *immediately* whenever the current solution is changed. Handlers + /// should be written to be very fast. Called on the same thread changing the workspace, + /// which may vary depending on the workspace. + /// + internal event EventHandler WorkspaceChangedImmediate + { + add + { + _eventMap.AddEventHandler(WorkspaceChangedImmediateEventName, value); + } + + remove + { + _eventMap.RemoveEventHandler(WorkspaceChangedImmediateEventName, value); + } + } + protected Task RaiseWorkspaceChangedEventAsync(WorkspaceChangeKind kind, Solution oldSolution, Solution newSolution, ProjectId projectId = null, DocumentId documentId = null) { if (newSolution == null) @@ -59,22 +78,40 @@ protected Task RaiseWorkspaceChangedEventAsync(WorkspaceChangeKind kind, Solutio projectId = documentId.ProjectId; } - var ev = GetEventHandlers(WorkspaceChangeEventName); + WorkspaceChangeEventArgs args = null; + var ev = GetEventHandlers(WorkspaceChangedImmediateEventName); + + if (ev.HasHandlers) + { + args = new WorkspaceChangeEventArgs(kind, oldSolution, newSolution, projectId, documentId); + RaiseEventForHandlers(ev, sender: this, args, FunctionId.Workspace_EventsImmediate); + } + + ev = GetEventHandlers(WorkspaceChangeEventName); if (ev.HasHandlers) { + args ??= new WorkspaceChangeEventArgs(kind, oldSolution, newSolution, projectId, documentId); return this.ScheduleTask(() => { - using (Logger.LogBlock(FunctionId.Workspace_Events, (s, p, d, k) => $"{s.Id} - {p} - {d} {kind.ToString()}", newSolution, projectId, documentId, kind, CancellationToken.None)) - { - var args = new WorkspaceChangeEventArgs(kind, oldSolution, newSolution, projectId, documentId); - ev.RaiseEvent(static (handler, arg) => handler(arg.self, arg.args), (self: this, args)); - } + RaiseEventForHandlers(ev, sender: this, args, FunctionId.Workspace_Events); }, WorkspaceChangeEventName); } else { return Task.CompletedTask; } + + static void RaiseEventForHandlers( + EventMap.EventHandlerSet> handlers, + Workspace sender, + WorkspaceChangeEventArgs args, + FunctionId functionId) + { + using (Logger.LogBlock(functionId, (s, p, d, k) => $"{s.Id} - {p} - {d} {args.Kind.ToString()}", args.NewSolution, args.ProjectId, args.DocumentId, args.Kind, CancellationToken.None)) + { + handlers.RaiseEvent(static (handler, arg) => handler(arg.sender, arg.args), (sender, args)); + } + } } /// diff --git a/src/Workspaces/Core/Portable/Workspace/Workspace_SourceGeneration.cs b/src/Workspaces/Core/Portable/Workspace/Workspace_SourceGeneration.cs index 2de8d674b6024..e4bdc6b38c9a0 100644 --- a/src/Workspaces/Core/Portable/Workspace/Workspace_SourceGeneration.cs +++ b/src/Workspaces/Core/Portable/Workspace/Workspace_SourceGeneration.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis; diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.cs.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.cs.xlf index 2f221e6af16e5..6f3c02b099a6f 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.cs.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.cs.xlf @@ -9,7 +9,7 @@ Absolute path expected - Absolute path expected + Očekávala se absolutní cesta. @@ -19,7 +19,7 @@ After - After + Za @@ -199,7 +199,7 @@ TODO: Unmerged change from project '{0}' - TODO: Unmerged change from project '{0}' + TODO: Nesloučené změny z projektu {0} {Locked="TODO"} diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.de.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.de.xlf index 44cec8f9ddf87..ae60405c80f86 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.de.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.de.xlf @@ -9,7 +9,7 @@ Absolute path expected - Absolute path expected + Absoluter Pfad erwartet. @@ -19,7 +19,7 @@ After - After + Nach @@ -199,7 +199,7 @@ TODO: Unmerged change from project '{0}' - TODO: Unmerged change from project '{0}' + TODO: Nicht zusammengeführte Änderung von Projekt „{0}“ {Locked="TODO"} diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.es.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.es.xlf index 2114a90441bdf..aa2dcd8e1def6 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.es.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.es.xlf @@ -9,7 +9,7 @@ Absolute path expected - Absolute path expected + Ruta de acceso absoluta esperada. @@ -19,7 +19,7 @@ After - After + Después @@ -199,7 +199,7 @@ TODO: Unmerged change from project '{0}' - TODO: Unmerged change from project '{0}' + TODO: cambio sin combinar del proyecto "{0}" {Locked="TODO"} diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.fr.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.fr.xlf index d8a55f70c9ee0..40c6817aaf968 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.fr.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.fr.xlf @@ -9,7 +9,7 @@ Absolute path expected - Absolute path expected + Chemin d'accès absolu attendu @@ -19,7 +19,7 @@ After - After + Après diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.it.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.it.xlf index 540ed5596a248..ed94312cb0855 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.it.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.it.xlf @@ -9,7 +9,7 @@ Absolute path expected - Absolute path expected + È previsto il percorso assoluto @@ -19,7 +19,7 @@ After - After + Dopo @@ -199,7 +199,7 @@ TODO: Unmerged change from project '{0}' - TODO: Unmerged change from project '{0}' + TODO: Modifica senza merge dal progetto '{0}' {Locked="TODO"} diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ja.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ja.xlf index 6f39c3461acdc..ef15dd8acb00e 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ja.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ja.xlf @@ -9,7 +9,7 @@ Absolute path expected - Absolute path expected + 絶対パスが必要です @@ -19,7 +19,7 @@ After - After + @@ -199,7 +199,7 @@ TODO: Unmerged change from project '{0}' - TODO: Unmerged change from project '{0}' + TODO: プロジェクト '{0}' からのマージされていない変更 {Locked="TODO"} diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ko.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ko.xlf index e11bc6259f096..97cf3eb6b8780 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ko.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ko.xlf @@ -9,7 +9,7 @@ Absolute path expected - Absolute path expected + 절대 경로가 필요합니다. @@ -19,7 +19,7 @@ After - After + 이후 @@ -199,7 +199,7 @@ TODO: Unmerged change from project '{0}' - TODO: Unmerged change from project '{0}' + TODO: '{0}' 프로젝트에서 병합되지 않은 변경 내용 {Locked="TODO"} diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pl.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pl.xlf index b830e74e4ed04..6fc52f63bf76b 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pl.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pl.xlf @@ -9,7 +9,7 @@ Absolute path expected - Absolute path expected + Oczekiwano ścieżki bezwzględnej @@ -19,7 +19,7 @@ After - After + Za @@ -199,7 +199,7 @@ TODO: Unmerged change from project '{0}' - TODO: Unmerged change from project '{0}' + TODO: niescalona zmiana z projektu „{0}” {Locked="TODO"} diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pt-BR.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pt-BR.xlf index 132289554e41c..56953c04630a8 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pt-BR.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pt-BR.xlf @@ -9,7 +9,7 @@ Absolute path expected - Absolute path expected + Caminho absoluto esperado @@ -19,7 +19,7 @@ After - After + Após @@ -199,7 +199,7 @@ TODO: Unmerged change from project '{0}' - TODO: Unmerged change from project '{0}' + TODO: Alteração não mesclada do projeto "{0}" {Locked="TODO"} diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ru.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ru.xlf index 98ef67b1ec6e8..f249d27fe757c 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ru.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ru.xlf @@ -9,7 +9,7 @@ Absolute path expected - Absolute path expected + Ожидался абсолютный путь @@ -19,7 +19,7 @@ After - After + После @@ -199,7 +199,7 @@ TODO: Unmerged change from project '{0}' - TODO: Unmerged change from project '{0}' + TODO: необъединенное изменение из проекта "{0}" {Locked="TODO"} diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.tr.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.tr.xlf index 4949ac695a677..86f5e4e2ce62c 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.tr.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.tr.xlf @@ -9,7 +9,7 @@ Absolute path expected - Absolute path expected + Mutlak yol bekleniyor @@ -19,7 +19,7 @@ After - After + Sonra @@ -199,7 +199,7 @@ TODO: Unmerged change from project '{0}' - TODO: Unmerged change from project '{0}' + TODO: '{0}' projesinden birleştirilmemiş değişiklik {Locked="TODO"} diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hans.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hans.xlf index bb8b8fbcb9562..09c6694563df9 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hans.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hans.xlf @@ -9,7 +9,7 @@ Absolute path expected - Absolute path expected + 预期的绝对路径 @@ -19,7 +19,7 @@ After - After + 晚于 @@ -199,7 +199,7 @@ TODO: Unmerged change from project '{0}' - TODO: Unmerged change from project '{0}' + TODO: 项目“{0}”的未合并的更改 {Locked="TODO"} diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hant.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hant.xlf index 982b61f0127f7..e5902fdec6735 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hant.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hant.xlf @@ -9,7 +9,7 @@ Absolute path expected - Absolute path expected + 必須是絕對路徑 @@ -19,7 +19,7 @@ After - After + 後方 @@ -199,7 +199,7 @@ TODO: Unmerged change from project '{0}' - TODO: Unmerged change from project '{0}' + TODO: 取消合併專案 '{0}' 的變更 {Locked="TODO"} diff --git a/src/Workspaces/CoreTest/CodeCleanup/MockCodeCleanupProvider.cs b/src/Workspaces/CoreTest/CodeCleanup/MockCodeCleanupProvider.cs index 4984445d61f22..c528983d55ab8 100644 --- a/src/Workspaces/CoreTest/CodeCleanup/MockCodeCleanupProvider.cs +++ b/src/Workspaces/CoreTest/CodeCleanup/MockCodeCleanupProvider.cs @@ -3,7 +3,6 @@ // 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; diff --git a/src/Workspaces/CoreTest/Differencing/LongestCommonSubsequenceTests.cs b/src/Workspaces/CoreTest/Differencing/LongestCommonSubsequenceTests.cs index cfadd6ca7288b..a40fe57391503 100644 --- a/src/Workspaces/CoreTest/Differencing/LongestCommonSubsequenceTests.cs +++ b/src/Workspaces/CoreTest/Differencing/LongestCommonSubsequenceTests.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.Text; using Xunit; diff --git a/src/Workspaces/CoreTest/Differencing/MatchTests.cs b/src/Workspaces/CoreTest/Differencing/MatchTests.cs index fadfcfdc0fb48..fa9c549bb7256 100644 --- a/src/Workspaces/CoreTest/Differencing/MatchTests.cs +++ b/src/Workspaces/CoreTest/Differencing/MatchTests.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 Roslyn.Utilities; using Xunit; diff --git a/src/Workspaces/CoreTest/Differencing/TestTreeComparer.cs b/src/Workspaces/CoreTest/Differencing/TestTreeComparer.cs index 7553741ef1e89..c75c69740f1a2 100644 --- a/src/Workspaces/CoreTest/Differencing/TestTreeComparer.cs +++ b/src/Workspaces/CoreTest/Differencing/TestTreeComparer.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using Microsoft.CodeAnalysis.Text; diff --git a/src/Workspaces/CoreTest/FindAllDeclarationsTests.TestSolutionsAndProject.cs b/src/Workspaces/CoreTest/FindAllDeclarationsTests.TestSolutionsAndProject.cs index bab48686708c0..5d003c2c632f5 100644 --- a/src/Workspaces/CoreTest/FindAllDeclarationsTests.TestSolutionsAndProject.cs +++ b/src/Workspaces/CoreTest/FindAllDeclarationsTests.TestSolutionsAndProject.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.Linq; diff --git a/src/Workspaces/CoreTest/FunctionIdTests.cs b/src/Workspaces/CoreTest/FunctionIdTests.cs index d1cfeae7f1be0..b022251da2c07 100644 --- a/src/Workspaces/CoreTest/FunctionIdTests.cs +++ b/src/Workspaces/CoreTest/FunctionIdTests.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using Microsoft.CodeAnalysis.Internal.Log; diff --git a/src/Workspaces/CoreTest/Options/EditorConfigNamingStyleParserTests.cs b/src/Workspaces/CoreTest/Options/EditorConfigNamingStyleParserTests.cs index 427bae7fd5494..4ccb7d7878f13 100644 --- a/src/Workspaces/CoreTest/Options/EditorConfigNamingStyleParserTests.cs +++ b/src/Workspaces/CoreTest/Options/EditorConfigNamingStyleParserTests.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Microsoft.CodeAnalysis.Test.Utilities; diff --git a/src/Workspaces/CoreTest/Options/NamingStylePreferencesTests.cs b/src/Workspaces/CoreTest/Options/NamingStylePreferencesTests.cs index d6a84049fc6eb..91e4719618b20 100644 --- a/src/Workspaces/CoreTest/Options/NamingStylePreferencesTests.cs +++ b/src/Workspaces/CoreTest/Options/NamingStylePreferencesTests.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.Linq; using System.Xml.Linq; diff --git a/src/Workspaces/CoreTest/Remote/ServiceDescriptorTests.cs b/src/Workspaces/CoreTest/Remote/ServiceDescriptorTests.cs index 0e9c68fc1b5bb..a686b89c49ab8 100644 --- a/src/Workspaces/CoreTest/Remote/ServiceDescriptorTests.cs +++ b/src/Workspaces/CoreTest/Remote/ServiceDescriptorTests.cs @@ -18,12 +18,10 @@ using MessagePack; using MessagePack.Formatters; using Microsoft.CodeAnalysis.AddImport; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeGeneration; -using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.DocumentationComments; @@ -36,7 +34,6 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.UnitTests; using Microsoft.CodeAnalysis.VisualBasic.CodeGeneration; -using Microsoft.CodeAnalysis.VisualBasic.CodeStyle; using Microsoft.CodeAnalysis.VisualBasic.Formatting; using Microsoft.CodeAnalysis.VisualBasic.Simplification; using Roslyn.Test.Utilities; diff --git a/src/Workspaces/CoreTest/Shared/Extensions/TelemetryExtensions/TelemetryExtensionTests.cs b/src/Workspaces/CoreTest/Shared/Extensions/TelemetryExtensions/TelemetryExtensionTests.cs index 2dcc610ce941b..86c1eb8d3a57e 100644 --- a/src/Workspaces/CoreTest/Shared/Extensions/TelemetryExtensions/TelemetryExtensionTests.cs +++ b/src/Workspaces/CoreTest/Shared/Extensions/TelemetryExtensions/TelemetryExtensionTests.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.Shared.Extensions; using Xunit; diff --git a/src/Workspaces/CoreTest/Shared/Extensions/TextSpanExtensions/SubtractTests.cs b/src/Workspaces/CoreTest/Shared/Extensions/TextSpanExtensions/SubtractTests.cs index 3e431a299a4db..7fbbeb34e1b92 100644 --- a/src/Workspaces/CoreTest/Shared/Extensions/TextSpanExtensions/SubtractTests.cs +++ b/src/Workspaces/CoreTest/Shared/Extensions/TextSpanExtensions/SubtractTests.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; diff --git a/src/Workspaces/CoreTest/SolutionTests/ProjectInfoTests.cs b/src/Workspaces/CoreTest/SolutionTests/ProjectInfoTests.cs index 0b04a4d145f39..6aaab605082bb 100644 --- a/src/Workspaces/CoreTest/SolutionTests/ProjectInfoTests.cs +++ b/src/Workspaces/CoreTest/SolutionTests/ProjectInfoTests.cs @@ -6,7 +6,6 @@ using System; using System.Collections.Immutable; -using System.IO; using System.Linq; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Test.Utilities; diff --git a/src/Workspaces/CoreTest/SolutionTests/SolutionTests.cs b/src/Workspaces/CoreTest/SolutionTests/SolutionTests.cs index 73f7d29d9fe0c..cc0f85f6d993c 100644 --- a/src/Workspaces/CoreTest/SolutionTests/SolutionTests.cs +++ b/src/Workspaces/CoreTest/SolutionTests/SolutionTests.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -2820,7 +2818,10 @@ public async Task TestCrossLanguageProjectsAsync() using var workspace = CreateWorkspace(); var solution = workspace.CurrentSolution - .AddProject(pm1, "goo", "goo.dll", LanguageNames.CSharp) + .AddProject(ProjectInfo.Create(pm1, VersionStamp.Create(), "goo", "goo.dll", LanguageNames.CSharp, compilationOptions: workspace.Services + .GetLanguageService(LanguageNames.CSharp) + .GetDefaultCompilationOptions() + .WithOutputKind(OutputKind.DynamicallyLinkedLibrary))) .AddMetadataReference(pm1, s_mscorlib) .AddProject(pm2, "bar", "bar.dll", LanguageNames.VisualBasic) .AddMetadataReference(pm2, s_mscorlib) @@ -3968,6 +3969,13 @@ public class C : A { .AddProjectReference(pid3, new ProjectReference(pid1)) .AddProjectReference(pid3, new ProjectReference(pid2)); + var options = solution.Workspace.Services + .GetLanguageService(LanguageNames.VisualBasic) + .GetDefaultCompilationOptions() + .WithOutputKind(OutputKind.DynamicallyLinkedLibrary); + solution = solution.WithProjectCompilationOptions(pid1, options) + .WithProjectCompilationOptions(pid2, options); + var project3 = solution.GetProject(pid3); var comp3 = project3.GetCompilationAsync().Result; var classC = comp3.GetTypeByMetadataName("C"); @@ -4020,7 +4028,11 @@ public async Task TestProjectWithNoBrokenReferencesHasNoIncompleteReferences() "CSharpProject", "CSharpProject", LanguageNames.CSharp, - metadataReferences: [MscorlibRef])); + metadataReferences: [MscorlibRef], + compilationOptions: workspace.Services + .GetLanguageService(LanguageNames.CSharp) + .GetDefaultCompilationOptions() + .WithOutputKind(OutputKind.DynamicallyLinkedLibrary))); var project2 = workspace.AddProject( ProjectInfo.Create( ProjectId.CreateNewId(), @@ -4221,7 +4233,11 @@ public async Task TestFrozenPartialProjectAlwaysIsIncomplete() "CSharpProject", "CSharpProject", LanguageNames.CSharp, - metadataReferences: [MscorlibRef])); + metadataReferences: [MscorlibRef], + compilationOptions: workspace.Services + .GetLanguageService(LanguageNames.CSharp) + .GetDefaultCompilationOptions() + .WithOutputKind(OutputKind.DynamicallyLinkedLibrary))); var project2 = workspace.AddProject( ProjectInfo.Create( @@ -5326,7 +5342,12 @@ private static void GetMultipleProjects( "CSharpProject", "CSharpProject", LanguageNames.CSharp, - metadataReferences: [MscorlibRef]).WithHasAllInformation(hasAllInformation: false)); + metadataReferences: [MscorlibRef], + compilationOptions: workspace.Services + .GetLanguageService(LanguageNames.CSharp) + .GetDefaultCompilationOptions() + .WithOutputKind(OutputKind.DynamicallyLinkedLibrary)) + .WithHasAllInformation(hasAllInformation: false)); vbNormalProject = workspace.AddProject( ProjectInfo.Create( @@ -5335,7 +5356,11 @@ private static void GetMultipleProjects( "VisualBasicProject", "VisualBasicProject", LanguageNames.VisualBasic, - metadataReferences: [MscorlibRef])); + metadataReferences: [MscorlibRef], + compilationOptions: workspace.Services + .GetLanguageService(LanguageNames.VisualBasic) + .GetDefaultCompilationOptions() + .WithOutputKind(OutputKind.DynamicallyLinkedLibrary))); dependsOnBrokenProject = workspace.AddProject( ProjectInfo.Create( @@ -5345,7 +5370,11 @@ private static void GetMultipleProjects( "VisualBasicProject", LanguageNames.VisualBasic, metadataReferences: [MscorlibRef], - projectReferences: [new ProjectReference(csBrokenProject.Id), new ProjectReference(vbNormalProject.Id)])); + projectReferences: [new ProjectReference(csBrokenProject.Id), new ProjectReference(vbNormalProject.Id)], + compilationOptions: workspace.Services + .GetLanguageService(LanguageNames.VisualBasic) + .GetDefaultCompilationOptions() + .WithOutputKind(OutputKind.DynamicallyLinkedLibrary))); dependsOnVbNormalProject = workspace.AddProject( ProjectInfo.Create( @@ -5355,7 +5384,11 @@ private static void GetMultipleProjects( "CSharpProject", LanguageNames.CSharp, metadataReferences: [MscorlibRef], - projectReferences: [new ProjectReference(vbNormalProject.Id)])); + projectReferences: [new ProjectReference(vbNormalProject.Id)], + compilationOptions: workspace.Services + .GetLanguageService(LanguageNames.CSharp) + .GetDefaultCompilationOptions() + .WithOutputKind(OutputKind.DynamicallyLinkedLibrary))); transitivelyDependsOnBrokenProjects = workspace.AddProject( ProjectInfo.Create( diff --git a/src/Workspaces/CoreTest/SolutionTests/SolutionWithSourceGeneratorTests.cs b/src/Workspaces/CoreTest/SolutionTests/SolutionWithSourceGeneratorTests.cs index 24126d40f789c..52743b8027436 100644 --- a/src/Workspaces/CoreTest/SolutionTests/SolutionWithSourceGeneratorTests.cs +++ b/src/Workspaces/CoreTest/SolutionTests/SolutionWithSourceGeneratorTests.cs @@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Remote.Testing; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Workspaces/CoreTest/UtilityTest/AsyncLazyTests.cs b/src/Workspaces/CoreTest/UtilityTest/AsyncLazyTests.cs index ff97ddfac212b..417597ee5f63c 100644 --- a/src/Workspaces/CoreTest/UtilityTest/AsyncLazyTests.cs +++ b/src/Workspaces/CoreTest/UtilityTest/AsyncLazyTests.cs @@ -5,8 +5,8 @@ using System; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; diff --git a/src/Workspaces/CoreTest/UtilityTest/CancellationSeriesTests.cs b/src/Workspaces/CoreTest/UtilityTest/CancellationSeriesTests.cs index b34fddf770451..2634f592348ee 100644 --- a/src/Workspaces/CoreTest/UtilityTest/CancellationSeriesTests.cs +++ b/src/Workspaces/CoreTest/UtilityTest/CancellationSeriesTests.cs @@ -11,6 +11,7 @@ using System; using System.Linq; using System.Threading; +using Microsoft.CodeAnalysis.Threading; using Xunit; namespace Roslyn.Utilities diff --git a/src/Workspaces/CoreTest/UtilityTest/DocumentationCommentTests.cs b/src/Workspaces/CoreTest/UtilityTest/DocumentationCommentTests.cs index 2664563f9815e..89e187edc3da5 100644 --- a/src/Workspaces/CoreTest/UtilityTest/DocumentationCommentTests.cs +++ b/src/Workspaces/CoreTest/UtilityTest/DocumentationCommentTests.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Test.Utilities; using Xunit; diff --git a/src/Workspaces/CoreTest/UtilityTest/EditDistanceTests.cs b/src/Workspaces/CoreTest/UtilityTest/EditDistanceTests.cs index 03f61dd4753d8..de4445d9088ab 100644 --- a/src/Workspaces/CoreTest/UtilityTest/EditDistanceTests.cs +++ b/src/Workspaces/CoreTest/UtilityTest/EditDistanceTests.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Linq; using Roslyn.Utilities; using Xunit; diff --git a/src/Workspaces/CoreTest/UtilityTest/ExceptionHelpersTests.cs b/src/Workspaces/CoreTest/UtilityTest/ExceptionHelpersTests.cs index a135e545e529a..f4ffc4f1c78f2 100644 --- a/src/Workspaces/CoreTest/UtilityTest/ExceptionHelpersTests.cs +++ b/src/Workspaces/CoreTest/UtilityTest/ExceptionHelpersTests.cs @@ -2,13 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Text.Json; using Microsoft.CodeAnalysis.ErrorReporting; using Roslyn.Test.Utilities; -using Roslyn.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.UnitTests diff --git a/src/Workspaces/CoreTest/UtilityTest/FilePathUtilitiesTests.cs b/src/Workspaces/CoreTest/UtilityTest/FilePathUtilitiesTests.cs index 6d198f0a9b8d0..f687a8aa1e89c 100644 --- a/src/Workspaces/CoreTest/UtilityTest/FilePathUtilitiesTests.cs +++ b/src/Workspaces/CoreTest/UtilityTest/FilePathUtilitiesTests.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 Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; diff --git a/src/Workspaces/CoreTest/UtilityTest/FormattingRangeHelperTests.cs b/src/Workspaces/CoreTest/UtilityTest/FormattingRangeHelperTests.cs index 0a42b5e98df10..8150a77dc81e0 100644 --- a/src/Workspaces/CoreTest/UtilityTest/FormattingRangeHelperTests.cs +++ b/src/Workspaces/CoreTest/UtilityTest/FormattingRangeHelperTests.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Utilities; using Roslyn.Test.Utilities; diff --git a/src/Workspaces/CoreTest/UtilityTest/SerializableBytesTests.cs b/src/Workspaces/CoreTest/UtilityTest/SerializableBytesTests.cs index 5dacf5cd41ff3..7229cdcb82419 100644 --- a/src/Workspaces/CoreTest/UtilityTest/SerializableBytesTests.cs +++ b/src/Workspaces/CoreTest/UtilityTest/SerializableBytesTests.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.IO; using System.Threading; diff --git a/src/Workspaces/CoreTest/UtilityTest/SpellCheckerTests.cs b/src/Workspaces/CoreTest/UtilityTest/SpellCheckerTests.cs index 3d90395b6a7a4..3547841433026 100644 --- a/src/Workspaces/CoreTest/UtilityTest/SpellCheckerTests.cs +++ b/src/Workspaces/CoreTest/UtilityTest/SpellCheckerTests.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 Roslyn.Utilities; using Xunit; diff --git a/src/Workspaces/CoreTest/UtilityTest/StringEscapingTests.cs b/src/Workspaces/CoreTest/UtilityTest/StringEscapingTests.cs index 62f5b9e0a5517..311821d39b5a1 100644 --- a/src/Workspaces/CoreTest/UtilityTest/StringEscapingTests.cs +++ b/src/Workspaces/CoreTest/UtilityTest/StringEscapingTests.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 Roslyn.Utilities; using Xunit; diff --git a/src/Workspaces/CoreTest/UtilityTest/TaskExtensionsTests.cs b/src/Workspaces/CoreTest/UtilityTest/TaskExtensionsTests.cs index 4ad2eb003fc47..e21cbb5b649c5 100644 --- a/src/Workspaces/CoreTest/UtilityTest/TaskExtensionsTests.cs +++ b/src/Workspaces/CoreTest/UtilityTest/TaskExtensionsTests.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.Runtime.CompilerServices; using System.Threading; diff --git a/src/Workspaces/CoreTest/WorkspaceServiceTests/GlobalOptionServiceTests.cs b/src/Workspaces/CoreTest/WorkspaceServiceTests/GlobalOptionServiceTests.cs index 5e37a6187cde0..28f4b3cb79e5c 100644 --- a/src/Workspaces/CoreTest/WorkspaceServiceTests/GlobalOptionServiceTests.cs +++ b/src/Workspaces/CoreTest/WorkspaceServiceTests/GlobalOptionServiceTests.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis.CodeStyle; diff --git a/src/Workspaces/CoreTest/WorkspaceTests/DynamicFileInfoProviderMefTests.cs b/src/Workspaces/CoreTest/WorkspaceTests/DynamicFileInfoProviderMefTests.cs index 47ebc52769afa..3e3afdf8eb6f7 100644 --- a/src/Workspaces/CoreTest/WorkspaceTests/DynamicFileInfoProviderMefTests.cs +++ b/src/Workspaces/CoreTest/WorkspaceTests/DynamicFileInfoProviderMefTests.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.Linq; using Microsoft.CodeAnalysis.Host; diff --git a/src/Workspaces/CoreTest/WorkspaceTests/WorkspaceReferenceTests.cs b/src/Workspaces/CoreTest/WorkspaceTests/WorkspaceReferenceTests.cs index 6e0ac037e2caa..ed4bd9f80652f 100644 --- a/src/Workspaces/CoreTest/WorkspaceTests/WorkspaceReferenceTests.cs +++ b/src/Workspaces/CoreTest/WorkspaceTests/WorkspaceReferenceTests.cs @@ -4,7 +4,6 @@ #nullable disable -using System.Collections.Immutable; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; diff --git a/src/Workspaces/CoreTestUtilities/Fakes/MockWorkspaceEventListenerProvider.cs b/src/Workspaces/CoreTestUtilities/Fakes/MockWorkspaceEventListenerProvider.cs index 9e5d51cab93a1..7fe42945fb3c8 100644 --- a/src/Workspaces/CoreTestUtilities/Fakes/MockWorkspaceEventListenerProvider.cs +++ b/src/Workspaces/CoreTestUtilities/Fakes/MockWorkspaceEventListenerProvider.cs @@ -17,8 +17,8 @@ namespace Microsoft.CodeAnalysis.Test.Utilities; [method: Obsolete(MefConstruction.ImportingConstructorMessage, true)] internal sealed class MockWorkspaceEventListenerProvider() : IWorkspaceServiceFactory { - public IEnumerable>? EventListeners; + public IEnumerable? EventListeners; - public IWorkspaceService? CreateService(HostWorkspaceServices workspaceServices) - => EventListeners != null ? new DefaultWorkspaceEventListenerServiceFactory.Service(workspaceServices.Workspace, EventListeners) : null; + public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) + => EventListeners != null ? new DefaultWorkspaceEventListenerServiceFactory.Service(workspaceServices.Workspace, EventListeners) : null!; } diff --git a/src/Workspaces/CoreTestUtilities/Logging/TestOutputLoggerProvider.cs b/src/Workspaces/CoreTestUtilities/Logging/TestOutputLoggerProvider.cs new file mode 100644 index 0000000000000..681622f567569 --- /dev/null +++ b/src/Workspaces/CoreTestUtilities/Logging/TestOutputLoggerProvider.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 Microsoft.Extensions.Logging; +using Xunit.Abstractions; + +namespace Microsoft.CodeAnalysis.UnitTests; + +public sealed class TestOutputLoggerProvider(ITestOutputHelper testOutputHelper) : ILoggerProvider +{ + public ILogger CreateLogger(string categoryName) + { + return new TestOutputLogger(testOutputHelper, categoryName); + } + + private sealed class TestOutputLogger(ITestOutputHelper testOutputHelper, string categoryName) : ILogger + { + public IDisposable BeginScope(TState state) where TState : notnull + { + return new NoOpDisposable(); + } + + public bool IsEnabled(LogLevel logLevel) + { + return true; + } + + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) + { + testOutputHelper.WriteLine($"[{DateTime.UtcNow:hh:mm:ss.fff}] [{logLevel}] [{categoryName}] {formatter(state, exception)}"); + + if (exception is not null) + testOutputHelper.WriteLine(exception.ToString()); + } + + private sealed class NoOpDisposable : IDisposable + { + public void Dispose() + { + } + } + } + + public void Dispose() + { + } +} diff --git a/src/Workspaces/CoreTestUtilities/MEF/IMefHostExportProviderExtensions.cs b/src/Workspaces/CoreTestUtilities/MEF/IMefHostExportProviderExtensions.cs index 3cac780a71373..1fd996980f76a 100644 --- a/src/Workspaces/CoreTestUtilities/MEF/IMefHostExportProviderExtensions.cs +++ b/src/Workspaces/CoreTestUtilities/MEF/IMefHostExportProviderExtensions.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.Linq; using Microsoft.CodeAnalysis.Host.Mef; diff --git a/src/Workspaces/CoreTestUtilities/Microsoft.CodeAnalysis.Workspaces.Test.Utilities.csproj b/src/Workspaces/CoreTestUtilities/Microsoft.CodeAnalysis.Workspaces.Test.Utilities.csproj index 633d78b7eb8f1..cfc6c47a176a1 100644 --- a/src/Workspaces/CoreTestUtilities/Microsoft.CodeAnalysis.Workspaces.Test.Utilities.csproj +++ b/src/Workspaces/CoreTestUtilities/Microsoft.CodeAnalysis.Workspaces.Test.Utilities.csproj @@ -35,9 +35,6 @@ - - - diff --git a/src/Workspaces/CoreTestUtilities/Options/OptionsTestHelpers.cs b/src/Workspaces/CoreTestUtilities/Options/OptionsTestHelpers.cs index ac269e5f96997..cadd0ccff9d83 100644 --- a/src/Workspaces/CoreTestUtilities/Options/OptionsTestHelpers.cs +++ b/src/Workspaces/CoreTestUtilities/Options/OptionsTestHelpers.cs @@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.NamingStyles; using Microsoft.CodeAnalysis.Options; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.UnitTests { diff --git a/src/Workspaces/CoreTestUtilities/TestAnalyzerReferenceByLanguage.cs b/src/Workspaces/CoreTestUtilities/TestAnalyzerReferenceByLanguage.cs index c8a762042ae32..5371d55acc443 100644 --- a/src/Workspaces/CoreTestUtilities/TestAnalyzerReferenceByLanguage.cs +++ b/src/Workspaces/CoreTestUtilities/TestAnalyzerReferenceByLanguage.cs @@ -6,11 +6,14 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using Microsoft.CodeAnalysis.Serialization; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Diagnostics { - internal class TestAnalyzerReferenceByLanguage : AnalyzerReference + internal class TestAnalyzerReferenceByLanguage : + AnalyzerReference, + SerializerService.TestAccessor.IAnalyzerReferenceWithGuid { private readonly IReadOnlyDictionary> _analyzersMap; @@ -28,6 +31,7 @@ public TestAnalyzerReferenceByLanguage(IReadOnlyDictionary nameof(TestAnalyzerReferenceByLanguage); public override object Id => Display; + public Guid Guid { get; } = Guid.NewGuid(); public Checksum Checksum; diff --git a/src/Workspaces/CoreTestUtilities/TestExportJoinableTaskContext+DenyExecutionSynchronizationContext.cs b/src/Workspaces/CoreTestUtilities/TestExportJoinableTaskContext+DenyExecutionSynchronizationContext.cs index 3b6e7ad8ab153..1a11e5bd9879f 100644 --- a/src/Workspaces/CoreTestUtilities/TestExportJoinableTaskContext+DenyExecutionSynchronizationContext.cs +++ b/src/Workspaces/CoreTestUtilities/TestExportJoinableTaskContext+DenyExecutionSynchronizationContext.cs @@ -6,7 +6,6 @@ using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using System.Threading; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Test.Utilities { diff --git a/src/Workspaces/CoreTestUtilities/TestExportJoinableTaskContext.cs b/src/Workspaces/CoreTestUtilities/TestExportJoinableTaskContext.cs index 0672cf8596567..bf526cbf46f59 100644 --- a/src/Workspaces/CoreTestUtilities/TestExportJoinableTaskContext.cs +++ b/src/Workspaces/CoreTestUtilities/TestExportJoinableTaskContext.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.VisualStudio.Threading; using Roslyn.Test.Utilities; -using Roslyn.Utilities; using Xunit.Sdk; namespace Microsoft.CodeAnalysis.Test.Utilities diff --git a/src/Workspaces/CoreTestUtilities/TestTextLoader.cs b/src/Workspaces/CoreTestUtilities/TestTextLoader.cs index b21164fce03e3..01c2832f1f4a0 100644 --- a/src/Workspaces/CoreTestUtilities/TestTextLoader.cs +++ b/src/Workspaces/CoreTestUtilities/TestTextLoader.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; diff --git a/src/Workspaces/CoreTestUtilities/Workspaces/AbstractTestHostProject.cs b/src/Workspaces/CoreTestUtilities/Workspaces/AbstractTestHostProject.cs index 4386053a286ff..f81c5ed5db2ac 100644 --- a/src/Workspaces/CoreTestUtilities/Workspaces/AbstractTestHostProject.cs +++ b/src/Workspaces/CoreTestUtilities/Workspaces/AbstractTestHostProject.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.IO; using Microsoft.CodeAnalysis.Host; diff --git a/src/EditorFeatures/TestUtilities/DocumentTracking/TestDocumentTrackingService.cs b/src/Workspaces/CoreTestUtilities/Workspaces/TestDocumentTrackingService.cs similarity index 95% rename from src/EditorFeatures/TestUtilities/DocumentTracking/TestDocumentTrackingService.cs rename to src/Workspaces/CoreTestUtilities/Workspaces/TestDocumentTrackingService.cs index ec01c8c69affc..529f126e62ef1 100644 --- a/src/EditorFeatures/TestUtilities/DocumentTracking/TestDocumentTrackingService.cs +++ b/src/Workspaces/CoreTestUtilities/Workspaces/TestDocumentTrackingService.cs @@ -7,7 +7,7 @@ using System.Composition; using Microsoft.CodeAnalysis.Host.Mef; -namespace Microsoft.CodeAnalysis.Editor.Test; +namespace Microsoft.CodeAnalysis.Test.Utilities; [ExportWorkspaceService(typeof(IDocumentTrackingService), ServiceLayer.Test), Shared, PartNotDiscoverable] [method: ImportingConstructor] diff --git a/src/Workspaces/CoreTestUtilities/Workspaces/TestHostSolution.cs b/src/Workspaces/CoreTestUtilities/Workspaces/TestHostSolution.cs index 342f684f71906..00eb9ffcd4204 100644 --- a/src/Workspaces/CoreTestUtilities/Workspaces/TestHostSolution.cs +++ b/src/Workspaces/CoreTestUtilities/Workspaces/TestHostSolution.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.Test.Utilities; diff --git a/src/Workspaces/CoreTestUtilities/Workspaces/TestWorkspace_XmlConsumption.cs b/src/Workspaces/CoreTestUtilities/Workspaces/TestWorkspace_XmlConsumption.cs index 84b7ad0cef98d..f885cca71ae7f 100644 --- a/src/Workspaces/CoreTestUtilities/Workspaces/TestWorkspace_XmlConsumption.cs +++ b/src/Workspaces/CoreTestUtilities/Workspaces/TestWorkspace_XmlConsumption.cs @@ -15,7 +15,6 @@ using System.Threading; using System.Xml.Linq; using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.DecompiledSource; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.UnitTests.Extensions; using Microsoft.CodeAnalysis.Host; diff --git a/src/Workspaces/CoreTestUtilities/Workspaces/TestWorkspace_XmlCreation.cs b/src/Workspaces/CoreTestUtilities/Workspaces/TestWorkspace_XmlCreation.cs index d88eb5524d93f..52f5b8b502e2c 100644 --- a/src/Workspaces/CoreTestUtilities/Workspaces/TestWorkspace_XmlCreation.cs +++ b/src/Workspaces/CoreTestUtilities/Workspaces/TestWorkspace_XmlCreation.cs @@ -10,7 +10,6 @@ using System.Xml.Linq; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.VisualBasic; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Test.Utilities { diff --git a/src/Workspaces/CoreTestUtilities/Workspaces/TestWorkspace`1.cs b/src/Workspaces/CoreTestUtilities/Workspaces/TestWorkspace`1.cs index bac4fc5437153..40533be8db84b 100644 --- a/src/Workspaces/CoreTestUtilities/Workspaces/TestWorkspace`1.cs +++ b/src/Workspaces/CoreTestUtilities/Workspaces/TestWorkspace`1.cs @@ -774,15 +774,9 @@ public override bool TryApplyChanges(Solution newSolution) // Ensure that any in-memory analyzer references in this test workspace are known by the serializer service // so that we can validate OOP scenarios involving analyzers. - foreach (var analyzer in this.CurrentSolution.AnalyzerReferences) - { - if (analyzer is AnalyzerImageReference analyzerImageReference) - { #pragma warning disable CA1416 // Validate platform compatibility - SerializerService.TestAccessor.AddAnalyzerImageReference(analyzerImageReference); + SerializerService.TestAccessor.AddAnalyzerImageReferences(this.CurrentSolution.AnalyzerReferences); #pragma warning restore CA1416 // Validate platform compatibility - } - } return result; } diff --git a/src/Workspaces/MSBuild/BuildHost/MSBuild/ProjectFile/ProjectFile.cs b/src/Workspaces/MSBuild/BuildHost/MSBuild/ProjectFile/ProjectFile.cs index 49dbebb4b17a6..cb763993aad9b 100644 --- a/src/Workspaces/MSBuild/BuildHost/MSBuild/ProjectFile/ProjectFile.cs +++ b/src/Workspaces/MSBuild/BuildHost/MSBuild/ProjectFile/ProjectFile.cs @@ -10,8 +10,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Build.Evaluation; -using Microsoft.Build.Globbing; -using Microsoft.Build.Globbing.Extensions; using Roslyn.Utilities; using MSB = Microsoft.Build; @@ -207,7 +205,10 @@ private ProjectFileInfo CreateProjectFileInfo(MSB.Execution.ProjectInstance proj static FileGlobs GetFileGlobs(GlobResult g) { - return new FileGlobs([.. g.IncludeGlobs], [.. g.Excludes], [.. g.Removes]); + return new FileGlobs( + Includes: [.. g.IncludeGlobs.Select(PathUtilities.ExpandAbsolutePathWithRelativeParts)], + Excludes: [.. g.Excludes.Select(PathUtilities.ExpandAbsolutePathWithRelativeParts)], + Removes: [.. g.Removes.Select(PathUtilities.ExpandAbsolutePathWithRelativeParts)]); } } @@ -273,7 +274,7 @@ private ImmutableArray GetRelativeFolders(MSB.Framework.ITaskItem docume { var filePath = documentItem.ItemSpec; var relativePath = PathUtilities.GetDirectoryName(PathUtilities.GetRelativePath(_projectDirectory, filePath)); - var folders = relativePath == null ? [] : relativePath.Split(PathUtilities.DirectorySeparatorChar, PathUtilities.AltDirectorySeparatorChar).ToImmutableArray(); + var folders = relativePath == null ? [] : relativePath.Split([PathUtilities.DirectorySeparatorChar, PathUtilities.AltDirectorySeparatorChar], StringSplitOptions.RemoveEmptyEntries).ToImmutableArray(); return folders; } } diff --git a/src/Workspaces/MSBuild/BuildHost/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.csproj b/src/Workspaces/MSBuild/BuildHost/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.csproj index 8101f56b8be6c..969b4616a298f 100644 --- a/src/Workspaces/MSBuild/BuildHost/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.csproj +++ b/src/Workspaces/MSBuild/BuildHost/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.csproj @@ -27,6 +27,8 @@ The version targeted is only used for build time, since we use MSBuildLocator to discover the proper version at runtime. --> <_MsbuildVersion>17.3.4 + + true @@ -67,15 +69,12 @@ - - - @@ -112,5 +111,6 @@ - + + diff --git a/src/Workspaces/MSBuild/BuildHost/Program.cs b/src/Workspaces/MSBuild/BuildHost/Program.cs index 48605a392742a..7fee5ac1ad2ea 100644 --- a/src/Workspaces/MSBuild/BuildHost/Program.cs +++ b/src/Workspaces/MSBuild/BuildHost/Program.cs @@ -8,7 +8,6 @@ using System.Globalization; using System.IO.Pipes; using System.Threading.Tasks; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.MSBuild; @@ -52,7 +51,7 @@ internal static async Task Main(string[] args) var pipeServer = NamedPipeUtil.CreateServer(pipeName, PipeDirection.InOut); await pipeServer.WaitForConnectionAsync().ConfigureAwait(false); - var server = new RpcServer(sendingStream: pipeServer, receivingStream: pipeServer); + var server = new RpcServer(pipeServer); var targetObject = server.AddTarget(new BuildHost(logger, propertiesBuilder.ToImmutable(), binaryLogPath, server)); Contract.ThrowIfFalse(targetObject == 0, "The first object registered should have target 0, which is assumed by the client."); diff --git a/src/Workspaces/MSBuild/BuildHost/Rpc/RpcServer.cs b/src/Workspaces/MSBuild/BuildHost/Rpc/RpcServer.cs index a6a08b8ed3050..e161bc6fa0c2a 100644 --- a/src/Workspaces/MSBuild/BuildHost/Rpc/RpcServer.cs +++ b/src/Workspaces/MSBuild/BuildHost/Rpc/RpcServer.cs @@ -6,6 +6,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; +using System.IO.Pipes; using System.Reflection; using System.Threading; using System.Threading.Tasks; @@ -25,19 +26,19 @@ namespace Microsoft.CodeAnalysis.MSBuild; /// internal sealed class RpcServer { - private readonly TextWriter _sendingStream; + private readonly TextWriter _streamWriter; private readonly SemaphoreSlim _sendingStreamSemaphore = new SemaphoreSlim(initialCount: 1); - private readonly TextReader _receivingStream; + private readonly TextReader _streamReader; private readonly ConcurrentDictionary _rpcTargets = []; private volatile int _nextRpcTargetIndex = -1; // We'll start at -1 so the first value becomes zero private readonly CancellationTokenSource _shutdownTokenSource = new CancellationTokenSource(); - public RpcServer(Stream sendingStream, Stream receivingStream) + public RpcServer(PipeStream stream) { - _sendingStream = new StreamWriter(sendingStream, JsonSettings.StreamEncoding); - _receivingStream = new StreamReader(receivingStream, JsonSettings.StreamEncoding); + _streamWriter = new StreamWriter(stream, JsonSettings.StreamEncoding); + _streamReader = new StreamReader(stream, JsonSettings.StreamEncoding); } public int AddTarget(object rpcTarget) @@ -61,7 +62,7 @@ public async Task RunAsync() var runningTasks = new ConcurrentSet(); string? line; - while ((line = await _receivingStream.TryReadLineOrReturnNullIfCancelledAsync(_shutdownTokenSource.Token).ConfigureAwait(false)) != null) + while ((line = await _streamReader.TryReadLineOrReturnNullIfCancelledAsync(_shutdownTokenSource.Token).ConfigureAwait(false)) != null) { Request? request; @@ -173,8 +174,8 @@ private async Task ProcessRequestAsync(Request request) #endif using (await _sendingStreamSemaphore.DisposableWaitAsync().ConfigureAwait(false)) { - await _sendingStream.WriteLineAsync(responseJson).ConfigureAwait(false); - await _sendingStream.FlushAsync().ConfigureAwait(false); + await _streamWriter.WriteLineAsync(responseJson).ConfigureAwait(false); + await _streamWriter.FlushAsync().ConfigureAwait(false); } } diff --git a/src/Workspaces/MSBuild/Core/MSBuild/BuildHostProcessManager.cs b/src/Workspaces/MSBuild/Core/MSBuild/BuildHostProcessManager.cs index 1592705b0962a..057a90fafd4bb 100644 --- a/src/Workspaces/MSBuild/Core/MSBuild/BuildHostProcessManager.cs +++ b/src/Workspaces/MSBuild/Core/MSBuild/BuildHostProcessManager.cs @@ -389,7 +389,7 @@ public BuildHostProcess(Process process, string pipeName, ILoggerFactory? logger throw new Exception("Ownership of BuildHost pipe is incorrect."); } - _rpcClient = new RpcClient(sendingStream: pipeClient, receivingStream: pipeClient); + _rpcClient = new RpcClient(pipeClient); _rpcClient.Start(); _rpcClient.Disconnected += Process_Exited; BuildHost = new RemoteBuildHost(_rpcClient); diff --git a/src/Workspaces/MSBuild/Core/MSBuild/DiagnosticReporterLoggerProvider.cs b/src/Workspaces/MSBuild/Core/MSBuild/DiagnosticReporterLoggerProvider.cs index 2f3feaa431f28..fea58aff5d40b 100644 --- a/src/Workspaces/MSBuild/Core/MSBuild/DiagnosticReporterLoggerProvider.cs +++ b/src/Workspaces/MSBuild/Core/MSBuild/DiagnosticReporterLoggerProvider.cs @@ -11,7 +11,7 @@ internal class DiagnosticReporterLoggerProvider : ILoggerProvider { private readonly DiagnosticReporter _reporter; - private DiagnosticReporterLoggerProvider(DiagnosticReporter reporter) + public DiagnosticReporterLoggerProvider(DiagnosticReporter reporter) { _reporter = reporter; } @@ -25,14 +25,6 @@ public void Dispose() { } - public static ILoggerFactory CreateLoggerFactoryForDiagnosticReporter(DiagnosticReporter reporter) - { - // Note: it's important we set MinLevel here, or otherwise we'll still get called in Log() for things below LogLevel.Warning. - return new LoggerFactory( - [new DiagnosticReporterLoggerProvider(reporter)], - new LoggerFilterOptions() { MinLevel = LogLevel.Warning }); - } - private sealed class Logger(DiagnosticReporter reporter, string categoryName) : ILogger { public IDisposable? BeginScope(TState state) where TState : notnull @@ -47,11 +39,19 @@ public bool IsEnabled(LogLevel logLevel) public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) { + // Despite returning IsEnabled somebody might still call us anyways, so filter it out + if (logLevel < LogLevel.Warning) + return; + var kind = logLevel == LogLevel.Warning ? WorkspaceDiagnosticKind.Warning : WorkspaceDiagnosticKind.Failure; var message = formatter(state, exception); if (!string.IsNullOrEmpty(categoryName)) message = $"[{categoryName}] {message}"; + // The standard formatters don't actually include the exception, so let's include it ourselves + if (exception is not null) + message += Environment.NewLine + exception.ToString(); + reporter.Report(new WorkspaceDiagnostic(kind, message)); } } diff --git a/src/Workspaces/MSBuild/Core/MSBuild/MSBuildProjectLoader.cs b/src/Workspaces/MSBuild/Core/MSBuild/MSBuildProjectLoader.cs index 4487e1f70532f..50971a42caf27 100644 --- a/src/Workspaces/MSBuild/Core/MSBuild/MSBuildProjectLoader.cs +++ b/src/Workspaces/MSBuild/Core/MSBuild/MSBuildProjectLoader.cs @@ -61,7 +61,7 @@ public MSBuildProjectLoader(Workspace workspace, ImmutableDictionary properties, Ho return new MSBuildWorkspace(hostServices, properties.ToImmutableDictionary()); } + internal void AddLoggerProvider(Microsoft.Extensions.Logging.ILoggerProvider loggerProvider) => _loggerFactory.AddProvider(loggerProvider); + /// /// The MSBuild properties used when interpreting project files. /// These are the same properties that are passed to msbuild via the /property:<n>=<v> command line argument. diff --git a/src/Workspaces/MSBuild/Core/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj b/src/Workspaces/MSBuild/Core/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj index 3b9134d8249c5..0b4d11ad2192c 100644 --- a/src/Workspaces/MSBuild/Core/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj +++ b/src/Workspaces/MSBuild/Core/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj @@ -28,7 +28,6 @@ - + <_ExcludeRuntimeLibraries Condition="'$(OfficialBuild)' == 'true'">false + + <_PublishPaths Include="@(PublishItemsOutputGroupOutputs->'%(OutputPath)')" /> <_PublishDllPaths Include="@(_PublishPaths)" Condition="'%(Extension)' == '.dll'" /> @@ -58,12 +72,24 @@ <_R2RAssemblies Include="SQLitePCLRaw.batteries_v2.dll" /> <_R2RAssemblies Include="StreamJsonRpc.dll" /> <_R2RAssemblies Include="System.IO.Pipelines.dll" /> - <_R2RAssemblies Include="System.Text.Json.dll" /> - <_R2RAssemblies Include="System.Text.Encodings.Web.dll" /> <_R2RAssemblies Include="Microsoft.NET.StringTools.dll" /> + + + <_R2RRuntimeAssemblies Include="System.Collections.Immutable.dll" /> + <_R2RRuntimeAssemblies Include="System.Reflection.Metadata.dll" /> + <_R2RRuntimeAssemblies Include="System.Text.Encodings.Web.dll" /> + <_R2RRuntimeAssemblies Include="System.Text.Json.dll" /> + <_R2RRuntimeAssemblies Include="System.Threading.Tasks.Dataflow.dll" /> + <_R2RAssemblies Include="@(_R2RRuntimeAssemblies)" Condition="'$(_ExcludeRuntimeLibraries)' != 'true'" /> - <_AllPublishedAssemblyPaths Include="@(_PublishDllPaths)" Exclude="%(FileName).EndsWith('.resources')" /> + <_AllPublishedAssemblyPaths Include="@(_PublishDllPaths)" /> + + <_AllPublishedAssemblyPaths Remove="@(_AllPublishedAssemblyPaths)" Condition="$([MSBuild]::ValueOrDefault('%(FileName)', '').EndsWith('.resources'))" /> + + <_AllPublishedAssemblyPaths Remove="@(_AllPublishedAssemblyPaths)" Condition="$([MSBuild]::ValueOrDefault('%(FullPath)', '').StartsWith('$(PublishDir)runtimes'))" /> + <_AllPublishedAssemblies Include="@(_AllPublishedAssemblyPaths->'%(FileName)%(Extension)')" > <_FullFilePath>%(FullPath) @@ -78,31 +104,42 @@ <_R2RAssemblyPaths Include="@(_AllPublishedAssemblyPaths)" Exclude="@(_NoR2RAssemblyPaths)" /> - <_RuntimeLibraries Include="$(_RuntimeLibrariesPath)**\*.dll" /> - <_WinRuntimeLibraries Include="$(_WinRuntimeLibrariesPath)**\*.dll" /> + <_RuntimeLibraryPaths Include="$(_RuntimeLibrariesPath)**\*.dll" /> + <_RuntimeLibraryPaths Include="$(_WinRuntimeLibrariesPath)**\*.dll" /> + <_RuntimeLibraryPaths Remove="@(_RuntimeLibraryPaths)" Condition="$([MSBuild]::ValueOrDefault('%(FileName)', '').EndsWith('.resources'))" /> - <_RuntimeLibrariesInPublishDir Include="@(_RuntimeLibraries->'$(PublishDir)%(FileName)%(Extension)')" /> - <_RuntimeLibrariesInPublishDir Include="@(_WinRuntimeLibraries->'$(PublishDir)%(FileName)%(Extension)')" /> + <_RuntimeLibraries Include="@(_RuntimeLibraryPaths->'%(FileName)%(Extension)')"> + <_FullFilePath>%(FullPath) + - <_NonRuntimeAssembliesInPublishDir Include="@(_PublishDllPaths)" Exclude="@(_RuntimeLibrariesInPublishDir)" /> + + <_NonRuntimeAssemblyPathsInPublishDir Include="@(_AllPublishedAssemblyPaths)" Exclude="@(_RuntimeLibraryPaths->'$(PublishDir)%(FileName)%(Extension)')" /> + <_RuntimeLibraryPathsInPublishDir Include="@(_AllPublishedAssemblyPaths)" Exclude="@(_NonRuntimeAssemblyPathsInPublishDir)" /> + <_RuntimeLibrariesInPublishDir Include="@(_RuntimeLibraryPathsInPublishDir->'%(FileName)%(Extension)')" /> + + <_RuntimeLibrariesNotInPublishDir Include="@(_RuntimeLibraries)" Exclude="@(_RuntimeLibrariesInPublishDir)" /> + <_RuntimeLibraryPathsNotInPublishDir Include="@(_RuntimeLibrariesNotInPublishDir->'%(_FullFilePath)')" Exclude="@(_RuntimeLibrariesInPublishDir)" /> $(PublishDir)CrossGen\ $(CrossgenWorkDir)OriginalAssemblies\ $(CrossgenWorkDir)Symbols\ + $(CrossgenWorkDir)RspFiles\ - + - <_CrossgenTargetsAsDependencies Include="$(OriginalAssemblyDir)*.dll" /> - <_NonCrossgenTargetsAsDependencies Include="@(_NonRuntimeAssembliesInPublishDir)" Exclude="@(_R2RAssemblyPaths)" /> + <_CrossgenTargetsAsDependencies Include="$(OriginalAssemblyDir)**\*.dll" /> + <_NonCrossgenTargetsAsDependencies Include="@(_AllPublishedAssemblyPaths)" Exclude="@(_R2RAssemblyPaths)" /> <_CrossgenTargetPaths Include="@(_CrossgenTargetsAsDependencies)"> - $(PublishDir)%(_CrossgenTargetsAsDependencies.Filename)%(_CrossgenTargetsAsDependencies.Extension) + $(PublishDir)%(RecursiveDir)\%(_CrossgenTargetsAsDependencies.Filename)%(_CrossgenTargetsAsDependencies.Extension) + <_RelativeDirectory>%(RecursiveDir) @@ -139,7 +176,7 @@ - + - <_ExcludeRuntimeLibraries Condition="'$(OfficialBuild)' == 'true'">true - - <_VsixItem Include="@(_PublishPaths)" /> @@ -208,7 +232,7 @@ <_VsixItem Remove="@(_VsixItem)" Condition="$([MSBuild]::ValueOrDefault('%(FullPath)', '').StartsWith('$(PublishDir)runtimes'))" /> - <_VsixItem Remove="@(_RuntimeLibrariesInPublishDir)" Condition="'$(_ExcludeRuntimeLibraries)' == 'true'" /> + <_VsixItem Remove="@(_RuntimeLibraryPathsInPublishDir)" Condition="'$(_ExcludeRuntimeLibraries)' == 'true'" /> diff --git a/src/Workspaces/Remote/ServiceHub/Host/RemoteAnalyzerAssemblyLoader.cs b/src/Workspaces/Remote/ServiceHub/Host/RemoteAnalyzerAssemblyLoader.cs deleted file mode 100644 index fd36b3e185862..0000000000000 --- a/src/Workspaces/Remote/ServiceHub/Host/RemoteAnalyzerAssemblyLoader.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.IO; -using System.Collections.Immutable; - -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 -{ - private readonly string _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 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 index f6e503cb7ba66..2d05eea91eb86 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/RemoteAnalyzerAssemblyLoaderService.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/RemoteAnalyzerAssemblyLoaderService.cs @@ -15,8 +15,21 @@ namespace Microsoft.CodeAnalysis.Remote.Diagnostics; /// Customizes the path where to store shadow-copies of analyzer assemblies. /// [ExportWorkspaceService(typeof(IAnalyzerAssemblyLoaderProvider), [WorkspaceKind.RemoteWorkspace]), Shared] -[method: ImportingConstructor] -[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] -internal sealed class RemoteAnalyzerAssemblyLoaderService( - [ImportMany] IEnumerable externalResolvers) - : AbstractAnalyzerAssemblyLoaderProvider(externalResolvers.ToImmutableArray()); +internal sealed class RemoteAnalyzerAssemblyLoaderService : AbstractAnalyzerAssemblyLoaderProvider +{ +#pragma warning disable IDE02900 // primary constructor +#if NET + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public RemoteAnalyzerAssemblyLoaderService([ImportMany] IEnumerable assemblyResolvers) + : base(assemblyResolvers) + { + } +#else + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public RemoteAnalyzerAssemblyLoaderService() + { + } +#endif +} diff --git a/src/Workspaces/Remote/ServiceHub/Host/RemoteAnalyzerPathResolver.cs b/src/Workspaces/Remote/ServiceHub/Host/RemoteAnalyzerPathResolver.cs new file mode 100644 index 0000000000000..b1cd93589461e --- /dev/null +++ b/src/Workspaces/Remote/ServiceHub/Host/RemoteAnalyzerPathResolver.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.IO; +using System.Collections.Immutable; +using System.Globalization; + +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 RemoteAnalyzerPathResolver(string baseDirectory) : IAnalyzerPathResolver +{ + private readonly string _baseDirectory = baseDirectory; + + private string GetFixedPath(string analyzerPath) + => Path.GetFullPath(Path.Combine(_baseDirectory, Path.GetFileName(analyzerPath))); + + public bool IsAnalyzerPathHandled(string originalAnalyzerPath) + => File.Exists(GetFixedPath(originalAnalyzerPath)); + + public string GetResolvedAnalyzerPath(string originalAnalyzerPath) + => GetFixedPath(originalAnalyzerPath); + + public string? GetResolvedSatellitePath(string originalAnalyzerPath, CultureInfo cultureInfo) + => AnalyzerAssemblyLoader.GetSatelliteAssemblyPath(GetFixedPath(originalAnalyzerPath), cultureInfo); +} diff --git a/src/Workspaces/Remote/ServiceHub/Host/RemoteDocumentDifferenceService.cs b/src/Workspaces/Remote/ServiceHub/Host/RemoteDocumentDifferenceService.cs index 428cb91515795..934c7a12b76fb 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/RemoteDocumentDifferenceService.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/RemoteDocumentDifferenceService.cs @@ -18,30 +18,20 @@ namespace Microsoft.CodeAnalysis.Remote; /// 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. +/// 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 - { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpDocumentDifferenceService() - { - } - } + [method: ImportingConstructor] + [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + internal sealed class CSharpDocumentDifferenceService() : RemoteDocumentDifferenceService; [ExportLanguageService(typeof(IDocumentDifferenceService), LanguageNames.VisualBasic, layer: ServiceLayer.Host), Shared] - internal sealed class VisualBasicDocumentDifferenceService : AbstractDocumentDifferenceService - { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public VisualBasicDocumentDifferenceService() - { - } - } + [method: ImportingConstructor] + [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + internal sealed class VisualBasicDocumentDifferenceService() : RemoteDocumentDifferenceService; public Task GetChangedMemberAsync(Document oldDocument, Document newDocument, CancellationToken cancellationToken) { diff --git a/src/Workspaces/Remote/ServiceHub/Host/RemoteHostTestData.cs b/src/Workspaces/Remote/ServiceHub/Host/RemoteHostTestData.cs index e9867b69da7c4..613c41d0e371f 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/RemoteHostTestData.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/RemoteHostTestData.cs @@ -2,9 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using Microsoft.CodeAnalysis.Host; - namespace Microsoft.CodeAnalysis.Remote; /// diff --git a/src/Workspaces/Remote/ServiceHub/Host/RemoteServiceBrokerProvider.cs b/src/Workspaces/Remote/ServiceHub/Host/RemoteServiceBrokerProvider.cs index 0a77ef7d1abfb..76d786ae763a8 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/RemoteServiceBrokerProvider.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/RemoteServiceBrokerProvider.cs @@ -8,7 +8,6 @@ using Microsoft.CodeAnalysis.BrokeredServices; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.ServiceHub.Framework; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Remote.Host; diff --git a/src/Workspaces/Remote/ServiceHub/Host/RemoteSolutionCache.cs b/src/Workspaces/Remote/ServiceHub/Host/RemoteSolutionCache.cs index d5b3c3be1ef77..18ef7c3fabd0f 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/RemoteSolutionCache.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/RemoteSolutionCache.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Remote; diff --git a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.InFlightSolution.cs b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.InFlightSolution.cs index eb70bc2e000a7..32f89b847124b 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.InFlightSolution.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.InFlightSolution.cs @@ -8,8 +8,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Shared.Collections; -using Microsoft.VisualStudio.Threading; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Remote; diff --git a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs index 2aec192ec8b6d..04e5fc7c59928 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs @@ -11,7 +11,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.ErrorReporting; -using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Serialization; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -575,23 +574,27 @@ private async Task UpdateDocumentInfoAsync(TextDocument document, // 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); + if (document.State.Attributes.Name != newDocumentInfo.Name) + document = document.Project.Solution.WithDocumentName(document.Id, newDocumentInfo.Name).GetRequiredDocument(document.Id); + + if (document.State.Attributes.FilePath != newDocumentInfo.FilePath) + document = document.Project.Solution.WithDocumentFilePath(document.Id, newDocumentInfo.FilePath).GetRequiredDocument(document.Id); + 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)!; + document = document.Project.Solution.WithDocumentFolders(document.Id, newDocumentInfo.Folders).GetRequiredDocument(document.Id); } 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)!; + document = document.Project.Solution.WithDocumentSourceCodeKind(document.Id, newDocumentInfo.SourceCodeKind).GetRequiredDocument(document.Id); } return document; diff --git a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.cs b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.cs index 4177e90130d7a..7ee0da3b27c20 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Serialization; -using Microsoft.VisualStudio.Telemetry; using Microsoft.VisualStudio.Threading; using Roslyn.Utilities; using static Microsoft.VisualStudio.Threading.ThreadingTools; diff --git a/src/Workspaces/Remote/ServiceHub/Microsoft.CodeAnalysis.Remote.ServiceHub.csproj b/src/Workspaces/Remote/ServiceHub/Microsoft.CodeAnalysis.Remote.ServiceHub.csproj index 91da959adde14..54e0ca60be11f 100644 --- a/src/Workspaces/Remote/ServiceHub/Microsoft.CodeAnalysis.Remote.ServiceHub.csproj +++ b/src/Workspaces/Remote/ServiceHub/Microsoft.CodeAnalysis.Remote.ServiceHub.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/Workspaces/Remote/ServiceHub/Services/AssetSynchronization/RemoteAssetSynchronizationService.cs b/src/Workspaces/Remote/ServiceHub/Services/AssetSynchronization/RemoteAssetSynchronizationService.cs index f6cc7c147aab3..73d39d3d53a58 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/AssetSynchronization/RemoteAssetSynchronizationService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/AssetSynchronization/RemoteAssetSynchronizationService.cs @@ -2,12 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Generic; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Serialization; +using Microsoft.CodeAnalysis.Telemetry; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; using RoslynLogger = Microsoft.CodeAnalysis.Internal.Log.Logger; @@ -22,6 +22,11 @@ namespace Microsoft.CodeAnalysis.Remote; internal sealed class RemoteAssetSynchronizationService(in BrokeredServiceBase.ServiceConstructionArguments arguments) : BrokeredServiceBase(in arguments), IRemoteAssetSynchronizationService { + private const string SynchronizeTextChangesAsyncSucceededMetricName = "SucceededCount"; + private const string SynchronizeTextChangesAsyncFailedMetricName = "FailedCount"; + private const string SynchronizeTextChangesAsyncSucceededKeyName = nameof(RemoteAssetSynchronizationService) + "." + SynchronizeTextChangesAsyncSucceededMetricName; + private const string SynchronizeTextChangesAsyncFailedKeyName = nameof(RemoteAssetSynchronizationService) + "." + SynchronizeTextChangesAsyncFailedMetricName; + internal sealed class Factory : FactoryBase { protected override IRemoteAssetSynchronizationService CreateService(in ServiceConstructionArguments arguments) @@ -49,16 +54,32 @@ public ValueTask SynchronizeActiveDocumentAsync(DocumentId? documentId, Cancella } public ValueTask SynchronizeTextChangesAsync( - ImmutableArray<(DocumentId documentId, Checksum baseTextChecksum, ImmutableArray textChanges, Checksum newTextChecksum)> changes, + DocumentId documentId, + Checksum baseTextChecksum, + ImmutableArray textChanges, + Checksum newTextChecksum, CancellationToken cancellationToken) { return RunServiceAsync(async cancellationToken => { - var workspace = GetWorkspace(); + var wasSynchronized = await SynchronizeTextChangesHelperAsync().ConfigureAwait(false); + + var metricName = wasSynchronized ? SynchronizeTextChangesAsyncSucceededMetricName : SynchronizeTextChangesAsyncFailedMetricName; + var keyName = wasSynchronized ? SynchronizeTextChangesAsyncSucceededKeyName : SynchronizeTextChangesAsyncFailedKeyName; + TelemetryLogging.LogAggregatedCounter(FunctionId.RemoteHostService_SynchronizeTextAsyncStatus, KeyValueLogMessage.Create(m => + { + m[TelemetryLogging.KeyName] = keyName; + m[TelemetryLogging.KeyValue] = 1L; + m[TelemetryLogging.KeyMetricName] = metricName; + })); + + return; - using (RoslynLogger.LogBlock(FunctionId.RemoteHostService_SynchronizeTextAsync, cancellationToken)) + async Task SynchronizeTextChangesHelperAsync() { - foreach (var (documentId, baseTextChecksum, textChanges, newTextChecksum) in changes) + var workspace = GetWorkspace(); + + using (RoslynLogger.LogBlock(FunctionId.RemoteHostService_SynchronizeTextAsync, cancellationToken)) { // Try to get the text associated with baseTextChecksum var text = await TryGetSourceTextAsync(WorkspaceManager, workspace, documentId, baseTextChecksum, cancellationToken).ConfigureAwait(false); @@ -66,7 +87,7 @@ public ValueTask SynchronizeTextChangesAsync( { // it won't bring in base text if it is not there already. // text needed will be pulled in when there is request - continue; + return false; } // Now attempt to manually apply the edit, producing the new forked text. Store that directly in @@ -77,9 +98,9 @@ public ValueTask SynchronizeTextChangesAsync( WorkspaceManager.SolutionAssetCache.GetOrAdd(newSerializableText.ContentChecksum, newSerializableText); } - } - return; + return true; + } async static Task TryGetSourceTextAsync( RemoteWorkspaceManager workspaceManager, diff --git a/src/Workspaces/Remote/ServiceHub/Services/AsynchronousOperationListener/RemoteAsynchronousOperationListenerService.cs b/src/Workspaces/Remote/ServiceHub/Services/AsynchronousOperationListener/RemoteAsynchronousOperationListenerService.cs index 7c300e43e717e..e58ac47a6bb35 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/AsynchronousOperationListener/RemoteAsynchronousOperationListenerService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/AsynchronousOperationListener/RemoteAsynchronousOperationListenerService.cs @@ -6,7 +6,6 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.TestHooks; namespace Microsoft.CodeAnalysis.Remote; diff --git a/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.FactoryBase.cs b/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.FactoryBase.cs index acea0f21b289f..a79cd330b7dd1 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.FactoryBase.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.FactoryBase.cs @@ -7,7 +7,6 @@ using System.Globalization; using System.IO; using System.IO.Pipelines; -using System.Runtime; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.ErrorReporting; @@ -15,7 +14,6 @@ using Microsoft.ServiceHub.Framework; using Microsoft.ServiceHub.Framework.Services; using Nerdbank.Streams; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Remote; diff --git a/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.cs b/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.cs index 3a5967c980aa4..27d5a0a2ebb47 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Immutable; using System.ComponentModel; using System.Diagnostics; using System.Runtime; diff --git a/src/Workspaces/Remote/ServiceHub/Services/ClientOptionsProvider.cs b/src/Workspaces/Remote/ServiceHub/Services/ClientOptionsProvider.cs index 1f18c201cd072..553d8b455abf7 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/ClientOptionsProvider.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/ClientOptionsProvider.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; diff --git a/src/Workspaces/Remote/ServiceHub/Services/ConvertTupleToStructCodeRefactoringProvider/RemoteConvertTupleToStructCodeRefactoringService.cs b/src/Workspaces/Remote/ServiceHub/Services/ConvertTupleToStructCodeRefactoringProvider/RemoteConvertTupleToStructCodeRefactoringService.cs index f13d42d978535..a40e6218fc866 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/ConvertTupleToStructCodeRefactoringProvider/RemoteConvertTupleToStructCodeRefactoringService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/ConvertTupleToStructCodeRefactoringProvider/RemoteConvertTupleToStructCodeRefactoringService.cs @@ -2,14 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeCleanup; -using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.ConvertTupleToStruct; -using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; diff --git a/src/Workspaces/Remote/ServiceHub/Services/DependentTypeFinder/RemoteDependentTypeFinderService.cs b/src/Workspaces/Remote/ServiceHub/Services/DependentTypeFinder/RemoteDependentTypeFinderService.cs index f6db2bbe579a5..cfa2ab365dca0 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/DependentTypeFinder/RemoteDependentTypeFinderService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/DependentTypeFinder/RemoteDependentTypeFinderService.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.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Remote; diff --git a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/DiagnosticComputer.cs b/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/DiagnosticComputer.cs index d8b597c517736..0de3f7d834c6c 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/DiagnosticComputer.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/DiagnosticComputer.cs @@ -356,7 +356,8 @@ private async Task GetDiagnosticsAsync( } } - var skippedAnalyzersInfo = _project.GetSkippedAnalyzersInfo(_analyzerInfoCache); + var skippedAnalyzersInfo = _project.Solution.SolutionState.Analyzers.GetSkippedAnalyzersInfo( + _project.State, _analyzerInfoCache); return await AnalyzeAsync(compilationWithAnalyzers, analyzerToIdMap, projectAnalyzers, hostAnalyzers, skippedAnalyzersInfo, logPerformanceInfo, getTelemetryInfo, cancellationToken).ConfigureAwait(false); @@ -401,8 +402,7 @@ private async Task AnalyzeAsync( { builderMap = builderMap.AddRange(await analysisResult.ToResultBuilderMapAsync( additionalPragmaSuppressionDiagnostics, documentAnalysisScope, - _project, VersionStamp.Default, - projectAnalyzers, hostAnalyzers, skippedAnalyzersInfo, cancellationToken).ConfigureAwait(false)); + _project, projectAnalyzers, hostAnalyzers, skippedAnalyzersInfo, cancellationToken).ConfigureAwait(false)); } var telemetry = getTelemetryInfo @@ -506,7 +506,11 @@ private static (ImmutableArray projectAnalyzers, ImmutableAr if (hostAnalyzerIds.Any()) { // If any host analyzers are active, make sure to also include any project diagnostic suppressors - hostBuilder.AddRange(projectAnalyzers.WhereAsArray(static a => a is DiagnosticSuppressor)); + var projectSuppressors = projectAnalyzers.WhereAsArray(static a => a is DiagnosticSuppressor); + // Make sure to remove any project suppressors already in the host analyzer array so we don't end up with + // duplicates. + hostBuilder.RemoveRange(projectSuppressors); + hostBuilder.AddRange(projectSuppressors); } return (projectAnalyzers, hostBuilder.ToImmutableAndClear()); @@ -576,6 +580,7 @@ private async Task CreateCompilationWithAnal { hostAnalyzerBuilder.AddRange(analyzers); } + analyzerMapBuilder.AppendAnalyzerMap(analyzers); } @@ -590,7 +595,13 @@ private async Task CreateCompilationWithAnal var analyzers = reference.GetAnalyzers(_project.Language); projectAnalyzerBuilder.AddRange(analyzers); - hostAnalyzerBuilder.AddRange(analyzers.WhereAsArray(static a => a is DiagnosticSuppressor)); + + var projectSuppressors = analyzers.WhereAsArray(static a => a is DiagnosticSuppressor); + // Make sure to remove any project suppressors already in the host analyzer array so we don't end up with + // duplicates. + hostAnalyzerBuilder.RemoveRange(projectSuppressors); + hostAnalyzerBuilder.AddRange(projectSuppressors); + analyzerMapBuilder.AppendAnalyzerMap(analyzers); } diff --git a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/PerformanceQueue.cs b/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/PerformanceQueue.cs index 633ff4bc2f275..2bdb29b05e6e5 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/PerformanceQueue.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/PerformanceQueue.cs @@ -8,7 +8,6 @@ using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis.Diagnostics; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Remote.Diagnostics; diff --git a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/RemoteDiagnosticAnalyzerService.cs b/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/RemoteDiagnosticAnalyzerService.cs index 53691abc123f8..84341edad9d2a 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/RemoteDiagnosticAnalyzerService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/RemoteDiagnosticAnalyzerService.cs @@ -8,13 +8,10 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Remote.Diagnostics; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.SolutionCrawler; using Microsoft.CodeAnalysis.Telemetry; -using Roslyn.Utilities; using RoslynLogger = Microsoft.CodeAnalysis.Internal.Log.Logger; namespace Microsoft.CodeAnalysis.Remote; diff --git a/src/Workspaces/Remote/ServiceHub/Services/EditAndContinue/EditAndContinueLogReporter.cs b/src/Workspaces/Remote/ServiceHub/Services/EditAndContinue/EditAndContinueLogReporter.cs index d00166c5ccccf..700ec0765e293 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/EditAndContinue/EditAndContinueLogReporter.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/EditAndContinue/EditAndContinueLogReporter.cs @@ -10,8 +10,8 @@ using Microsoft.CodeAnalysis.BrokeredServices; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Threading; using Microsoft.VisualStudio.Debugger.Contracts.HotReload; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.EditAndContinue; diff --git a/src/Workspaces/Remote/ServiceHub/Services/EncapsulateField/RemoteEncapsulateFieldService.cs b/src/Workspaces/Remote/ServiceHub/Services/EncapsulateField/RemoteEncapsulateFieldService.cs index 3986f4d2d7618..762709e92af0c 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/EncapsulateField/RemoteEncapsulateFieldService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/EncapsulateField/RemoteEncapsulateFieldService.cs @@ -5,7 +5,6 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.EncapsulateField; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.PooledObjects; diff --git a/src/Workspaces/Remote/ServiceHub/Services/FindUsages/RemoteFindUsagesService.cs b/src/Workspaces/Remote/ServiceHub/Services/FindUsages/RemoteFindUsagesService.cs index 1948462558784..f262e6e265941 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/FindUsages/RemoteFindUsagesService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/FindUsages/RemoteFindUsagesService.cs @@ -3,7 +3,6 @@ // 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; using Microsoft.CodeAnalysis.Classification; diff --git a/src/Workspaces/Remote/ServiceHub/Services/FullyQualify/RemoteFullyQualifyService.cs b/src/Workspaces/Remote/ServiceHub/Services/FullyQualify/RemoteFullyQualifyService.cs index 3a43c914dc1a4..809383521855d 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/FullyQualify/RemoteFullyQualifyService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/FullyQualify/RemoteFullyQualifyService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections; -using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeFixes.FullyQualify; diff --git a/src/Workspaces/Remote/ServiceHub/Services/LegacySolutionEvents/RemoteLegacySolutionEventsAggregationService.cs b/src/Workspaces/Remote/ServiceHub/Services/LegacySolutionEvents/RemoteLegacySolutionEventsAggregationService.cs index bfa385fe18bc0..320060bf361a2 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/LegacySolutionEvents/RemoteLegacySolutionEventsAggregationService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/LegacySolutionEvents/RemoteLegacySolutionEventsAggregationService.cs @@ -2,13 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.LegacySolutionEvents; -using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.Remote; diff --git a/src/Workspaces/Remote/ServiceHub/Services/NavigateToSearch/RemoteNavigateToSearchService.cs b/src/Workspaces/Remote/ServiceHub/Services/NavigateToSearch/RemoteNavigateToSearchService.cs index a22cacfb58b09..5a80474ead4ad 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/NavigateToSearch/RemoteNavigateToSearchService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/NavigateToSearch/RemoteNavigateToSearchService.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.NavigateTo; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Storage; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Remote; @@ -44,7 +45,7 @@ public ValueTask HydrateAsync(Checksum solutionChecksum, CancellationToken cance return RunServiceAsync(solutionChecksum, solution => ValueTaskFactory.CompletedTask, cancellationToken); } - public ValueTask SearchDocumentAsync( + public ValueTask SearchDocumentAndRelatedDocumentsAsync( Checksum solutionChecksum, DocumentId documentId, string searchPattern, @@ -57,7 +58,7 @@ public ValueTask SearchDocumentAsync( var document = solution.GetRequiredDocument(documentId); var (onItemsFound, onProjectCompleted) = GetCallbacks(callbackId, cancellationToken); - await AbstractNavigateToSearchService.SearchDocumentInCurrentProcessAsync( + await AbstractNavigateToSearchService.SearchDocumentAndRelatedDocumentsInCurrentProcessAsync( document, searchPattern, kinds.ToImmutableHashSet(), onItemsFound, cancellationToken).ConfigureAwait(false); }, cancellationToken); } diff --git a/src/Workspaces/Remote/ServiceHub/Services/NavigationBar/RemoteNavigationBarItemService.cs b/src/Workspaces/Remote/ServiceHub/Services/NavigationBar/RemoteNavigationBarItemService.cs index 4786cf00b8a2a..e6278b8cec5dd 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/NavigationBar/RemoteNavigationBarItemService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/NavigationBar/RemoteNavigationBarItemService.cs @@ -7,7 +7,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.NavigationBar; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Remote; diff --git a/src/Workspaces/Remote/ServiceHub/Services/ProcessTelemetry/RemoteProcessTelemetryService.PerformanceReporter.cs b/src/Workspaces/Remote/ServiceHub/Services/ProcessTelemetry/RemoteProcessTelemetryService.PerformanceReporter.cs index 12a60c27203f5..3200e4d81149e 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/ProcessTelemetry/RemoteProcessTelemetryService.PerformanceReporter.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/ProcessTelemetry/RemoteProcessTelemetryService.PerformanceReporter.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Remote.Diagnostics; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Threading; using Microsoft.VisualStudio.Telemetry; using Roslyn.Utilities; using RoslynLogger = Microsoft.CodeAnalysis.Internal.Log.Logger; diff --git a/src/Workspaces/Remote/ServiceHub/Services/ProcessTelemetry/RemoteWorkspaceConfigurationService.cs b/src/Workspaces/Remote/ServiceHub/Services/ProcessTelemetry/RemoteWorkspaceConfigurationService.cs index 528ddd7abaa31..b6e922e5a54e0 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/ProcessTelemetry/RemoteWorkspaceConfigurationService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/ProcessTelemetry/RemoteWorkspaceConfigurationService.cs @@ -4,10 +4,7 @@ using System; using System.Composition; -using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Storage; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Host; diff --git a/src/Workspaces/Remote/ServiceHub/Services/SemanticClassification/RemoteSemanticClassificationService.Caching.cs b/src/Workspaces/Remote/ServiceHub/Services/SemanticClassification/RemoteSemanticClassificationService.Caching.cs index 4374242bb0683..19df6b40c64ea 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/SemanticClassification/RemoteSemanticClassificationService.Caching.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/SemanticClassification/RemoteSemanticClassificationService.Caching.cs @@ -17,6 +17,7 @@ using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Storage; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Remote; diff --git a/src/Workspaces/Remote/ServiceHub/Services/SemanticClassification/RemoteSemanticClassificationService.cs b/src/Workspaces/Remote/ServiceHub/Services/SemanticClassification/RemoteSemanticClassificationService.cs index 6369abb39128b..6053c02cd7338 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/SemanticClassification/RemoteSemanticClassificationService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/SemanticClassification/RemoteSemanticClassificationService.cs @@ -8,7 +8,6 @@ using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Remote; diff --git a/src/Workspaces/Remote/ServiceHub/Services/SemanticSearch/RemoteSemanticSearchService.cs b/src/Workspaces/Remote/ServiceHub/Services/SemanticSearch/RemoteSemanticSearchService.cs index 8446af1308920..c8d53b2a1c005 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/SemanticSearch/RemoteSemanticSearchService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/SemanticSearch/RemoteSemanticSearchService.cs @@ -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. -using System; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Classification; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.SemanticSearch; diff --git a/src/Workspaces/Remote/ServiceHub/Services/SourceGeneration/RemoteSourceGenerationService.cs b/src/Workspaces/Remote/ServiceHub/Services/SourceGeneration/RemoteSourceGenerationService.cs index 3c979bffd663a..a5c8a2bf46c57 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/SourceGeneration/RemoteSourceGenerationService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/SourceGeneration/RemoteSourceGenerationService.cs @@ -10,8 +10,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Serialization; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SourceGeneration; diff --git a/src/Workspaces/Remote/ServiceHub/Services/SymbolFinder/RemoteSymbolFinderService.cs b/src/Workspaces/Remote/ServiceHub/Services/SymbolFinder/RemoteSymbolFinderService.cs index 2c9c8ad1438c3..76c4d4f5cad68 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/SymbolFinder/RemoteSymbolFinderService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/SymbolFinder/RemoteSymbolFinderService.cs @@ -3,14 +3,11 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.FindSymbols.SymbolTree; -using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; diff --git a/src/Workspaces/Remote/ServiceHub/Services/TaskList/RemoteTaskListService.cs b/src/Workspaces/Remote/ServiceHub/Services/TaskList/RemoteTaskListService.cs index 72deab8b83e9b..ade6d02e42b56 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/TaskList/RemoteTaskListService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/TaskList/RemoteTaskListService.cs @@ -6,9 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.SolutionCrawler; using Microsoft.CodeAnalysis.TaskList; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Remote; diff --git a/src/Workspaces/Remote/ServiceHubTest/RemoteAnalyzerAssemblyLoaderTests.cs b/src/Workspaces/Remote/ServiceHubTest/RemoteAnalyzerAssemblyLoaderTests.cs index 5eaf725e8399c..1227316941eae 100644 --- a/src/Workspaces/Remote/ServiceHubTest/RemoteAnalyzerAssemblyLoaderTests.cs +++ b/src/Workspaces/Remote/ServiceHubTest/RemoteAnalyzerAssemblyLoaderTests.cs @@ -16,14 +16,19 @@ namespace Microsoft.CodeAnalysis.Remote.UnitTests { public class RemoteAnalyzerAssemblyLoaderTests { + private static AnalyzerAssemblyLoader Create(string baseDirectory) => new( + [new RemoteAnalyzerPathResolver(baseDirectory)], + [AnalyzerAssemblyLoader.StreamAnalyzerAssemblyResolver], + compilerLoadContext: null); + [Fact] public void NonIdeAnalyzerAssemblyShouldBeLoadedInSeparateALC() { using var testFixture = new AssemblyLoadTestFixture(); - var remoteAssemblyInCurrentAlc = typeof(RemoteAnalyzerAssemblyLoader).GetTypeInfo().Assembly; + var remoteAssemblyInCurrentAlc = typeof(RemoteAnalyzerPathResolver).GetTypeInfo().Assembly; var remoteAssemblyLocation = remoteAssemblyInCurrentAlc.Location; - var loader = new RemoteAnalyzerAssemblyLoader(Path.GetDirectoryName(remoteAssemblyLocation)!); + var loader = Create(Path.GetDirectoryName(remoteAssemblyLocation)!); // Try to load MS.CA.Remote.ServiceHub.dll as an analyzer assembly via RemoteAnalyzerAssemblyLoader // since it's not one of the special assemblies listed in RemoteAnalyzerAssemblyLoader, @@ -45,7 +50,7 @@ public void IdeAnalyzerAssemblyShouldBeLoadedInLoaderALC() // Try to load MS.CA.Features.dll as an analyzer assembly via RemoteAnalyzerAssemblyLoader // since it's listed as one of the special assemblies in RemoteAnalyzerAssemblyLoader, // RemoteAnalyzerAssemblyLoader should loaded in its own ALC. - var loader = new RemoteAnalyzerAssemblyLoader(Path.GetDirectoryName(featuresAssemblyLocation)!); + var loader = Create(Path.GetDirectoryName(featuresAssemblyLocation)!); loader.AddDependencyLocation(featuresAssemblyLocation); var featuresAssemblyLoadedViaRemoteLoader = loader.LoadFromPath(featuresAssemblyLocation); @@ -61,7 +66,7 @@ public void CompilerAssemblyShouldBeLoadedInLoaderALC() var compilerAssemblyInCurrentAlc = typeof(SyntaxNode).GetTypeInfo().Assembly; var compilerAssemblyLocation = compilerAssemblyInCurrentAlc.Location; - var loader = new RemoteAnalyzerAssemblyLoader(Path.GetDirectoryName(compilerAssemblyLocation)!); + var loader = Create(Path.GetDirectoryName(compilerAssemblyLocation)!); loader.AddDependencyLocation(compilerAssemblyLocation); var compilerAssemblyLoadedViaRemoteLoader = loader.LoadFromPath(compilerAssemblyLocation); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeGeneration/CSharpSyntaxTokens.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeGeneration/CSharpSyntaxTokens.cs index c4bd47a6e864b..948c320fa4cbf 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeGeneration/CSharpSyntaxTokens.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeGeneration/CSharpSyntaxTokens.cs @@ -32,6 +32,7 @@ internal static class CSharpSyntaxTokens public static readonly SyntaxToken EndOfDocumentationCommentToken = Token(SyntaxKind.EndOfDocumentationCommentToken); public static readonly SyntaxToken EqualsToken = Token(SyntaxKind.EqualsToken); public static readonly SyntaxToken ExplicitKeyword = Token(SyntaxKind.ExplicitKeyword); + public static readonly SyntaxToken ExtensionKeyword = Token(SyntaxKind.ExtensionKeyword); public static readonly SyntaxToken ExternKeyword = Token(SyntaxKind.ExternKeyword); public static readonly SyntaxToken FileKeyword = Token(SyntaxKind.FileKeyword); public static readonly SyntaxToken FloatKeyword = Token(SyntaxKind.FloatKeyword); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/CSharpCodeStyleOptions_Parsing.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/CSharpCodeStyleOptions_Parsing.cs index f7cbf796f684f..c1cbdb9b17557 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/CSharpCodeStyleOptions_Parsing.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/CSharpCodeStyleOptions_Parsing.cs @@ -5,7 +5,6 @@ using System; using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeStyle; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.CodeStyle; @@ -56,6 +55,7 @@ public static CodeStyleOption2 ParseUsingDirectivesPlacement { "inside_namespace" => new CodeStyleOption2(AddImportPlacement.InsideNamespace, notification), "outside_namespace" => new CodeStyleOption2(AddImportPlacement.OutsideNamespace, notification), + "outside_namespace_ignoring_aliases" => new CodeStyleOption2(AddImportPlacement.OutsideNamespaceIgnoringAliases, notification), _ => throw new NotSupportedException(), }; } @@ -70,6 +70,7 @@ public static string GetUsingDirectivesPlacementEditorConfigString(CodeStyleOpti { AddImportPlacement.InsideNamespace => $"inside_namespace{notificationString}", AddImportPlacement.OutsideNamespace => $"outside_namespace{notificationString}", + AddImportPlacement.OutsideNamespaceIgnoringAliases => $"outside_namespace_ignoring_aliases{notificationString}", _ => throw new NotSupportedException(), }; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/EmbeddedLanguages/VirtualChars/CSharpVirtualCharService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/EmbeddedLanguages/VirtualChars/CSharpVirtualCharService.cs index 991dbfe11d3c8..3b5dfe1af5ffd 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/EmbeddedLanguages/VirtualChars/CSharpVirtualCharService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/EmbeddedLanguages/VirtualChars/CSharpVirtualCharService.cs @@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Microsoft.CodeAnalysis.Utilities; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.EmbeddedLanguages.VirtualChars; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/EmbeddedLanguages/VirtualChars/RuneExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/EmbeddedLanguages/VirtualChars/RuneExtensions.cs index 1c678e7400cf3..f49f387ffb699 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/EmbeddedLanguages/VirtualChars/RuneExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/EmbeddedLanguages/VirtualChars/RuneExtensions.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Generic; using System.Text; using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ContextQuery/SyntaxTreeExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ContextQuery/SyntaxTreeExtensions.cs index 9d08af3d5e0b4..70e1207b654b4 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ContextQuery/SyntaxTreeExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ContextQuery/SyntaxTreeExtensions.cs @@ -4,14 +4,9 @@ #nullable disable -using System.Collections.Generic; -using System.Linq; using System.Threading; -using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.CSharp.Utilities; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/DirectiveSyntaxExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/DirectiveSyntaxExtensions.cs index dcfb7721ff8e2..7cf81835842be 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/DirectiveSyntaxExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/DirectiveSyntaxExtensions.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Immutable; using System.Runtime.CompilerServices; using System.Threading; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ExpressionSyntaxExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ExpressionSyntaxExtensions.cs index 1e7c5eef36bae..618d78bcaa6bc 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ExpressionSyntaxExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ExpressionSyntaxExtensions.cs @@ -7,7 +7,6 @@ using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ITypeSymbolExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ITypeSymbolExtensions.cs index 304762df06b73..aab4c0035fdf6 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ITypeSymbolExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ITypeSymbolExtensions.cs @@ -44,13 +44,13 @@ public static bool TryGetPrimaryConstructor(this INamedTypeSymbol typeSymbol, [N Debug.Assert(typeSymbol.GetParameters().IsDefaultOrEmpty, "If GetParameters extension handles record, we can remove the handling here."); // A bit hacky to determine the parameters of primary constructor associated with a given record. - // Simplifying is tracked by: https://github.com/dotnet/roslyn/issues/53092. - // Note: When the issue is handled, we can remove the logic here and handle things in GetParameters extension. BUT - // if GetParameters extension method gets updated to handle records, we need to test EVERY usage - // of the extension method and make sure the change is applicable to all these usages. + // Simplifying is tracked by: https://github.com/dotnet/roslyn/issues/53092. Note: When the issue is + // handled, we can remove the logic here and handle things in GetParameters extension. BUT if GetParameters + // extension method gets updated to handle records, we need to test EVERY usage of the extension method and + // make sure the change is applicable to all these usages. primaryConstructor = typeSymbol.InstanceConstructors.FirstOrDefault( - c => c.DeclaringSyntaxReferences.FirstOrDefault()?.GetSyntax() is RecordDeclarationSyntax or ClassDeclarationSyntax or StructDeclarationSyntax); + c => c.DeclaringSyntaxReferences.FirstOrDefault()?.GetSyntax() is TypeDeclarationSyntax); return primaryConstructor is not null; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/LanguageVersionExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/LanguageVersionExtensions.cs index d4aa3c168bb89..e29e9dc61cba8 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/LanguageVersionExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/LanguageVersionExtensions.cs @@ -27,6 +27,9 @@ public static bool SupportsCollectionExpressions(this LanguageVersion languageVe public static bool SupportsPrimaryConstructors(this LanguageVersion languageVersion) => languageVersion.IsCSharp12OrAbove(); + public static bool SupportsExtensions(this LanguageVersion languageVersion) + => languageVersion.IsCSharp14OrAbove(); + /// /// Corresponds to Microsoft.CodeAnalysis.CSharp.LanguageVersionFacts.CSharpNext. /// diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/MemberDeclarationSyntaxExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/MemberDeclarationSyntaxExtensions.cs index a8d8ba4ab5a73..5ad67cba5ccff 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/MemberDeclarationSyntaxExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/MemberDeclarationSyntaxExtensions.cs @@ -8,7 +8,6 @@ using System.Collections.Immutable; using System.Linq; using System.Runtime.CompilerServices; -using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; namespace Microsoft.CodeAnalysis.CSharp.Extensions; @@ -33,10 +32,11 @@ public static SyntaxToken GetNameToken(this MemberDeclarationSyntax member) case SyntaxKind.EnumDeclaration: return ((EnumDeclarationSyntax)member).Identifier; case SyntaxKind.ClassDeclaration: - case SyntaxKind.RecordDeclaration: + case SyntaxKind.ExtensionDeclaration: case SyntaxKind.InterfaceDeclaration: - case SyntaxKind.StructDeclaration: + case SyntaxKind.RecordDeclaration: case SyntaxKind.RecordStructDeclaration: + case SyntaxKind.StructDeclaration: return ((TypeDeclarationSyntax)member).Identifier; case SyntaxKind.DelegateDeclaration: return ((DelegateDeclarationSyntax)member).Identifier; @@ -72,10 +72,11 @@ public static int GetArity(this MemberDeclarationSyntax member) switch (member.Kind()) { case SyntaxKind.ClassDeclaration: - case SyntaxKind.RecordDeclaration: + case SyntaxKind.ExtensionDeclaration: case SyntaxKind.InterfaceDeclaration: - case SyntaxKind.StructDeclaration: + case SyntaxKind.RecordDeclaration: case SyntaxKind.RecordStructDeclaration: + case SyntaxKind.StructDeclaration: return ((TypeDeclarationSyntax)member).Arity; case SyntaxKind.DelegateDeclaration: return ((DelegateDeclarationSyntax)member).Arity; @@ -87,17 +88,20 @@ public static int GetArity(this MemberDeclarationSyntax member) return 0; } - public static TypeParameterListSyntax GetTypeParameterList(this MemberDeclarationSyntax member) +#nullable enable + + public static TypeParameterListSyntax? GetTypeParameterList(this MemberDeclarationSyntax member) { if (member != null) { switch (member.Kind()) { case SyntaxKind.ClassDeclaration: - case SyntaxKind.RecordDeclaration: + case SyntaxKind.ExtensionDeclaration: case SyntaxKind.InterfaceDeclaration: - case SyntaxKind.StructDeclaration: + case SyntaxKind.RecordDeclaration: case SyntaxKind.RecordStructDeclaration: + case SyntaxKind.StructDeclaration: return ((TypeDeclarationSyntax)member).TypeParameterList; case SyntaxKind.DelegateDeclaration: return ((DelegateDeclarationSyntax)member).TypeParameterList; @@ -109,6 +113,8 @@ public static TypeParameterListSyntax GetTypeParameterList(this MemberDeclaratio return null; } +#nullable disable + public static MemberDeclarationSyntax WithParameterList( this MemberDeclarationSyntax member, BaseParameterListSyntax parameterList) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ParenthesizedExpressionSyntaxExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ParenthesizedExpressionSyntaxExtensions.cs index e654b58820d16..929b8052de79a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ParenthesizedExpressionSyntaxExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ParenthesizedExpressionSyntaxExtensions.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxTreeExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxTreeExtensions.cs index 9a0645dc6e0c0..1235118b417ee 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxTreeExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxTreeExtensions.cs @@ -349,14 +349,14 @@ SyntaxKind.Utf8SingleLineRawStringLiteralToken or if (kind is SyntaxKind.SingleLineRawStringLiteralToken or SyntaxKind.MultiLineRawStringLiteralToken) { var sourceText = token.SyntaxTree!.GetText(cancellationToken); - var startDelimeterLength = 0; - var endDelimeterLength = 0; + var startDelimiterLength = 0; + var endDelimiterLength = 0; for (int i = token.SpanStart, n = token.Span.End; i < n; i++) { if (sourceText[i] != '"') break; - startDelimeterLength++; + startDelimiterLength++; } for (int i = token.Span.End - 1, n = token.Span.Start; i >= n; i--) @@ -364,17 +364,17 @@ SyntaxKind.Utf8SingleLineRawStringLiteralToken or if (sourceText[i] != '"') break; - endDelimeterLength++; + endDelimiterLength++; } - return token.Span.Length == startDelimeterLength || - (token.Span.Length > startDelimeterLength && endDelimeterLength < startDelimeterLength); + return token.Span.Length == startDelimiterLength || + (token.Span.Length > startDelimiterLength && endDelimiterLength < startDelimiterLength); } else { - var startDelimeterLength = token.IsVerbatimStringLiteral() ? 2 : 1; - return token.Span.Length == startDelimeterLength || - (token.Span.Length > startDelimeterLength && token.Text[^1] != lastChar); + var startDelimiterLength = token.IsVerbatimStringLiteral() ? 2 : 1; + return token.Span.Length == startDelimiterLength || + (token.Span.Length > startDelimiterLength && token.Text[^1] != lastChar); } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxTriviaListExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxTriviaListExtensions.cs index 99692c2e045a0..3bd36245042af 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxTriviaListExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxTriviaListExtensions.cs @@ -7,7 +7,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Shared.Collections; using Roslyn.Utilities; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/AggregatedFormattingResult.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/AggregatedFormattingResult.cs index 2b8003af0e4b8..9000a086b5182 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/AggregatedFormattingResult.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/AggregatedFormattingResult.cs @@ -7,7 +7,6 @@ using System.Threading; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Shared.Collections; -using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.CSharp.Formatting; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/CSharpStructuredTriviaFormatEngine.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/CSharpStructuredTriviaFormatEngine.cs index cec283c043333..432d11ef13dcc 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/CSharpStructuredTriviaFormatEngine.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/CSharpStructuredTriviaFormatEngine.cs @@ -5,7 +5,6 @@ using System; using System.Threading; using Microsoft.CodeAnalysis.CSharp.LanguageService; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.LanguageService; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/CSharpTriviaFormatter.DocumentationCommentExteriorCommentRewriter.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/CSharpTriviaFormatter.DocumentationCommentExteriorCommentRewriter.cs index 7aaed1ac65c46..01230dacd8f57 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/CSharpTriviaFormatter.DocumentationCommentExteriorCommentRewriter.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/CSharpTriviaFormatter.DocumentationCommentExteriorCommentRewriter.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 Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Formatting; namespace Microsoft.CodeAnalysis.CSharp.Formatting; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/CSharpTriviaFormatter.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/CSharpTriviaFormatter.cs index 4a24d6718a9f6..9ba3a979c455b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/CSharpTriviaFormatter.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/CSharpTriviaFormatter.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Formatting; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.CodeShapeAnalyzer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.CodeShapeAnalyzer.cs index cc2d613fcce73..b47080399003e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.CodeShapeAnalyzer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.CodeShapeAnalyzer.cs @@ -5,7 +5,6 @@ using System.Diagnostics; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.ComplexTrivia.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.ComplexTrivia.cs index 21c63a5e8f9a0..e5232f68e654b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.ComplexTrivia.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.ComplexTrivia.cs @@ -6,10 +6,8 @@ using System.Collections.Generic; using System.Diagnostics; using System.Threading; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Formatting; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.FormattedComplexTrivia.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.FormattedComplexTrivia.cs index d62c4c9a6d9a4..38f7131220906 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.FormattedComplexTrivia.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.FormattedComplexTrivia.cs @@ -7,7 +7,6 @@ using System.Threading; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Formatting; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.ModifiedComplexTrivia.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.ModifiedComplexTrivia.cs index 1db933c501f3b..3aafea68d6215 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.ModifiedComplexTrivia.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.ModifiedComplexTrivia.cs @@ -5,10 +5,8 @@ using System; using System.Collections.Generic; using System.Threading; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Formatting; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.cs index 1ec647df3cd22..839ff26c9d1f7 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.cs @@ -4,7 +4,6 @@ using System.Diagnostics; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaRewriter.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaRewriter.cs index 58f85e2643cad..96eb2c20e1d7f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaRewriter.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaRewriter.cs @@ -12,7 +12,6 @@ using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Formatting; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/AnchorIndentationFormattingRule.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/AnchorIndentationFormattingRule.cs index 29bd5fc527641..df428cb9c26f3 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/AnchorIndentationFormattingRule.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/AnchorIndentationFormattingRule.cs @@ -57,7 +57,7 @@ public override void AddAnchorIndentationOperations(List typeSymbol.TryGetPrimaryConstructor(out primaryConstructor); + #if !CODE_STYLE public async Task GetInterceptorSymbolAsync(Document document, int position, CancellationToken cancellationToken) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpBlockFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpBlockFacts.cs index bbdecabd8cbea..06ea1e6c99591 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpBlockFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpBlockFacts.cs @@ -3,7 +3,6 @@ // 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 Microsoft.CodeAnalysis; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpHeaderFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpHeaderFacts.cs index 73e965f2e5cf9..4fc1dee41714e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpHeaderFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpHeaderFacts.cs @@ -28,11 +28,27 @@ public override bool IsOnTypeHeader(SyntaxNode root, int position, bool fullHead if (node == null) return false; - var lastToken = (node as TypeDeclarationSyntax)?.TypeParameterList?.GetLastToken() ?? node.Identifier; - if (fullHeader) - lastToken = node.BaseList?.GetLastToken() ?? lastToken; + return IsOnHeader(root, position, node, GetLastToken()); - return IsOnHeader(root, position, node, lastToken); + SyntaxToken GetLastToken() + { + if (fullHeader && node.BaseList != null) + return node.BaseList.GetLastToken(); + + if (node is TypeDeclarationSyntax { TypeParameterList.GreaterThanToken: var greaterThanToken }) + return greaterThanToken; + + // .Identifier may be default in the case of an extension type. + if (node.Identifier != default) + return node.Identifier; + + return node switch + { + TypeDeclarationSyntax typeDeclaration => typeDeclaration.Keyword, + EnumDeclarationSyntax enumDeclaration => enumDeclaration.EnumKeyword, + _ => throw ExceptionUtilities.Unreachable(), + }; + } } public override bool IsOnPropertyDeclarationHeader(SyntaxNode root, int position, [NotNullWhen(true)] out SyntaxNode? propertyDeclaration) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs index 360493f97d2ec..21c614183934a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs @@ -23,13 +23,10 @@ namespace Microsoft.CodeAnalysis.CSharp.LanguageService; -internal class CSharpSyntaxFacts : ISyntaxFacts +internal class CSharpSyntaxFacts : AbstractSyntaxFacts, 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() { } @@ -107,7 +104,7 @@ public bool IsOperator(SyntaxToken token) return (SyntaxFacts.IsAnyUnaryExpression(kind) && - (token.Parent is PrefixUnaryExpressionSyntax || token.Parent is PostfixUnaryExpressionSyntax || token.Parent is OperatorDeclarationSyntax)) || + (token.Parent is PrefixUnaryExpressionSyntax or PostfixUnaryExpressionSyntax or OperatorDeclarationSyntax)) || (SyntaxFacts.IsBinaryExpression(kind) && (token.Parent is BinaryExpressionSyntax or OperatorDeclarationSyntax or RelationalPatternSyntax)) || (SyntaxFacts.IsAssignmentExpressionOperatorToken(kind) && token.Parent is AssignmentExpressionSyntax); } @@ -732,13 +729,7 @@ EnumMemberDeclarationSyntax or } public bool IsTopLevelNodeWithMembers([NotNullWhen(true)] SyntaxNode? node) - { - return node is BaseNamespaceDeclarationSyntax or - TypeDeclarationSyntax or - EnumDeclarationSyntax; - } - - private const string dotToken = "."; + => node is BaseNamespaceDeclarationSyntax or BaseTypeDeclarationSyntax; public string GetDisplayName(SyntaxNode? node, DisplayNameOptions options, string? rootNamespace = null) { @@ -762,7 +753,7 @@ public string GetDisplayName(SyntaxNode? node, DisplayNameOptions options, strin } } - var names = ArrayBuilder.GetInstance(); + using var _ = ArrayBuilder.GetInstance(out var names); // containing type(s) var parent = node.GetAncestor() ?? node.Parent; while (parent is TypeDeclarationSyntax) @@ -786,7 +777,7 @@ public string GetDisplayName(SyntaxNode? node, DisplayNameOptions options, strin if (name != null) { builder.Append(name); - builder.Append(dotToken); + builder.Append('.'); } } @@ -802,7 +793,7 @@ public string GetDisplayName(SyntaxNode? node, DisplayNameOptions options, strin return pooled.ToStringAndFree(); } - private static string? GetName(SyntaxNode node, DisplayNameOptions options) + private string? GetName(SyntaxNode node, DisplayNameOptions options) { const string missingTokenPlaceholder = "?"; @@ -820,99 +811,79 @@ public string GetDisplayName(SyntaxNode? node, DisplayNameOptions options, strin return GetName(((BaseNamespaceDeclarationSyntax)node).Name, options); case SyntaxKind.QualifiedName: var qualified = (QualifiedNameSyntax)node; - return GetName(qualified.Left, options) + dotToken + GetName(qualified.Right, options); + return $"{GetName(qualified.Left, options)}.{GetName(qualified.Right, options)}"; } - string? name = null; if (node is MemberDeclarationSyntax memberDeclaration) { - if (memberDeclaration.Kind() == SyntaxKind.ConversionOperatorDeclaration) + if (memberDeclaration is ConversionOperatorDeclarationSyntax conversionOperator) + return ConvertToSingleLine(conversionOperator.Type).ToString(); + + var nameToken = memberDeclaration.GetNameToken(); + if (nameToken != default) { - name = (memberDeclaration as ConversionOperatorDeclarationSyntax)?.Type.ToString(); + using var _ = PooledStringBuilder.GetInstance(out var builder); + if (memberDeclaration.Kind() == SyntaxKind.DestructorDeclaration) + builder.Append('~'); + + builder.Append(nameToken.IsMissing ? missingTokenPlaceholder : nameToken.Text); + + if ((options & DisplayNameOptions.IncludeTypeParameters) != 0) + AppendTypeParameterList(builder, memberDeclaration.GetTypeParameterList()); + + return builder.ToString(); } - else + else if (memberDeclaration is ExtensionDeclarationSyntax extensionDeclaration) { - var nameToken = memberDeclaration.GetNameToken(); - if (nameToken != default) - { - name = nameToken.IsMissing ? missingTokenPlaceholder : nameToken.Text; - if (memberDeclaration.Kind() == SyntaxKind.DestructorDeclaration) - { - name = "~" + name; - } + using var _ = PooledStringBuilder.GetInstance(out var builder); + builder.Append("extension"); - if ((options & DisplayNameOptions.IncludeTypeParameters) != 0) - { - var pooled = PooledStringBuilder.GetInstance(); - var builder = pooled.Builder; - builder.Append(name); - AppendTypeParameterList(builder, memberDeclaration.GetTypeParameterList()); - name = pooled.ToStringAndFree(); - } - } - else - { - Debug.Assert(memberDeclaration.Kind() == SyntaxKind.IncompleteMember); - name = "?"; - } + if ((options & DisplayNameOptions.IncludeTypeParameters) != 0) + AppendTypeParameterList(builder, memberDeclaration.GetTypeParameterList()); + + AppendParameterList(builder, extensionDeclaration.ParameterList); + return builder.ToString(); } - } - else - { - if (node is VariableDeclaratorSyntax fieldDeclarator) + else { - var nameToken = fieldDeclarator.Identifier; - if (nameToken != default) - { - name = nameToken.IsMissing ? missingTokenPlaceholder : nameToken.Text; - } + Debug.Assert(memberDeclaration.Kind() == SyntaxKind.IncompleteMember); + return "?"; } } + else if (node is VariableDeclaratorSyntax fieldDeclarator) + { + var nameToken = fieldDeclarator.Identifier; + return nameToken.IsMissing ? missingTokenPlaceholder : nameToken.Text; + } - Debug.Assert(name != null, "Unexpected node type " + node.Kind()); - return name; - } + Debug.Fail("Unexpected node type " + node.Kind()); + return null; - private static void AppendTypeParameterList(StringBuilder builder, TypeParameterListSyntax typeParameterList) - { - if (typeParameterList != null && typeParameterList.Parameters.Count > 0) + static void AppendTypeParameterList(StringBuilder builder, TypeParameterListSyntax? typeParameterList) { - builder.Append('<'); - builder.Append(typeParameterList.Parameters[0].Identifier.ValueText); - for (var i = 1; i < typeParameterList.Parameters.Count; i++) + if (typeParameterList != null) { - builder.Append(", "); - builder.Append(typeParameterList.Parameters[i].Identifier.ValueText); + builder.Append('<'); + builder.Append(string.Join(", ", typeParameterList.Parameters.Select(static p => p.Identifier.ValueText))); + builder.Append('>'); } - - builder.Append('>'); } - } - public PooledObject> GetTopLevelAndMethodLevelMembers(SyntaxNode? root) - { - var pooledObject = s_syntaxNodeListPool.GetPooledObject(); - var list = pooledObject.Object; - - AppendMembers(root, list, topLevel: true, methodLevel: true); - - return pooledObject; - } - - public PooledObject> GetMethodLevelMembers(SyntaxNode? root) - { - var pooledObject = s_syntaxNodeListPool.GetPooledObject(); - var list = pooledObject.Object; - - AppendMembers(root, list, topLevel: false, methodLevel: true); - - return pooledObject; + void AppendParameterList(StringBuilder builder, ParameterListSyntax? parameterList) + { + if (parameterList != null) + { + builder.Append('('); + builder.Append(string.Join(", ", parameterList.Parameters.Select(p => ConvertToSingleLine(p.Type)))); + builder.Append(')'); + } + } } public SyntaxList GetMembersOfTypeDeclaration(SyntaxNode typeDeclaration) => ((TypeDeclarationSyntax)typeDeclaration).Members; - private void AppendMembers(SyntaxNode? node, List list, bool topLevel, bool methodLevel) + protected override void AppendMembers(SyntaxNode? node, ArrayBuilder list, bool topLevel, bool methodLevel) { Debug.Assert(topLevel || methodLevel); @@ -939,53 +910,19 @@ private void AppendMembers(SyntaxNode? node, List list, bool topLeve public TextSpan GetMemberBodySpanForSpeculativeBinding(SyntaxNode node) { if (node.Span.IsEmpty) - { return default; - } var member = GetContainingMemberDeclaration(node, node.SpanStart); if (member == null) - { return default; - } // TODO: currently we only support method for now - if (member is BaseMethodDeclarationSyntax method) - { - if (method.Body == null) - { - return default; - } - - return GetBlockBodySpan(method.Body); - } + if (member is BaseMethodDeclarationSyntax { Body: not null } method) + return TextSpan.FromBounds(method.Body.OpenBraceToken.Span.End, method.Body.CloseBraceToken.SpanStart); return default; } - public bool ContainsInMemberBody([NotNullWhen(true)] SyntaxNode? node, TextSpan span) - { - switch (node) - { - case ConstructorDeclarationSyntax constructor: - return (constructor.Body != null && GetBlockBodySpan(constructor.Body).Contains(span)) || - (constructor.Initializer != null && constructor.Initializer.Span.Contains(span)); - case BaseMethodDeclarationSyntax method: - return method.Body != null && GetBlockBodySpan(method.Body).Contains(span); - case BasePropertyDeclarationSyntax property: - return property.AccessorList != null && property.AccessorList.Span.Contains(span); - case EnumMemberDeclarationSyntax @enum: - return @enum.EqualsValue != null && @enum.EqualsValue.Span.Contains(span); - case BaseFieldDeclarationSyntax field: - return field.Declaration != null && field.Declaration.Span.Contains(span); - } - - return false; - } - - private static TextSpan GetBlockBodySpan(BlockSyntax body) - => TextSpan.FromBounds(body.OpenBraceToken.Span.End, body.CloseBraceToken.SpanStart); - public SyntaxNode? TryGetBindableParent(SyntaxToken token) { var node = token.Parent; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxKinds.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxKinds.cs index 918895ef01572..5afb9f1eadcfb 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxKinds.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxKinds.cs @@ -70,6 +70,7 @@ public int Convert(TSyntaxKind kind) where TSyntaxKind : struct public int FalseKeyword => (int)SyntaxKind.FalseKeyword; public int IfKeyword => (int)SyntaxKind.IfKeyword; public int NewKeyword => (int)SyntaxKind.NewKeyword; + public int PartialKeyword => (int)SyntaxKind.PartialKeyword; public int TrueKeyword => (int)SyntaxKind.TrueKeyword; public int UsingKeyword => (int)SyntaxKind.UsingKeyword; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/CSharpInferredMemberNameSimplifier.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/CSharpInferredMemberNameSimplifier.cs index f7e9aef695f80..7d066aa2b7e1a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/CSharpInferredMemberNameSimplifier.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/CSharpInferredMemberNameSimplifier.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 Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Simplification; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/Simplifiers/CastSimplifier.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/Simplifiers/CastSimplifier.cs index f6488396cf1f0..19f48c1475d69 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/Simplifiers/CastSimplifier.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/Simplifiers/CastSimplifier.cs @@ -937,7 +937,7 @@ private static bool IsNullOrErrorType(TypeInfo info) => IsNullOrErrorType(info.Type) || IsNullOrErrorType(info.ConvertedType); private static bool IsNullOrErrorType([NotNullWhen(false)] ITypeSymbol? type) - => type is null || type is IErrorTypeSymbol; + => type is null or IErrorTypeSymbol; private static bool CastRemovalWouldCauseUnintendedReferenceComparisonWarning( ExpressionSyntax expression, diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/SpeculationAnalyzer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/SpeculationAnalyzer.cs index bfc64ac68efb1..6da04e237e4ce 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/SpeculationAnalyzer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/SpeculationAnalyzer.cs @@ -9,7 +9,6 @@ using System.Diagnostics; using System.Linq; using System.Threading; -using System.Xml.Serialization; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TokenComparer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TokenComparer.cs index cd25294eb1469..dfdc92b74aa92 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TokenComparer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TokenComparer.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Globalization; -using Microsoft.CodeAnalysis.CSharp.Extensions; namespace Microsoft.CodeAnalysis.CSharp.Utilities; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpTypeStyleHelper.State.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpTypeStyleHelper.State.cs index a2b5aae07ad25..c15705abd5ba6 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpTypeStyleHelper.State.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpTypeStyleHelper.State.cs @@ -5,7 +5,6 @@ using System.Diagnostics.CodeAnalysis; using System.Threading; using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeStyle.TypeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Simplification; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpTypeStyleHelper.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpTypeStyleHelper.cs index 48e8f45c34dc2..2133f04188828 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpTypeStyleHelper.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpTypeStyleHelper.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; -using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpUseExplicitTypeHelper.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpUseExplicitTypeHelper.cs index 679bf4d52bf17..67bee3e072b04 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpUseExplicitTypeHelper.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpUseExplicitTypeHelper.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Threading; -using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.CodeStyle.TypeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Simplification; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/UsingsAndExternAliasesDirectiveComparer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/UsingsAndExternAliasesDirectiveComparer.cs index 0e4a9f22c20b0..dee7d8be5ce4f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/UsingsAndExternAliasesDirectiveComparer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/UsingsAndExternAliasesDirectiveComparer.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Diagnostics; using Microsoft.CodeAnalysis.CSharp.Syntax; using Roslyn.Utilities; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.cs.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.cs.xlf index 5960e43ab93f7..52512162facb9 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.cs.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.cs.xlf @@ -24,7 +24,7 @@ Indentation preferences - Indentation preferences + Předvolby odsazení @@ -39,12 +39,12 @@ Space preferences - Space preferences + Předvolby mezer Wrapping preferences - Wrapping preferences + Předvolby zalamování diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.de.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.de.xlf index 39c9b890e4de5..ffd1eb44dc109 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.de.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.de.xlf @@ -24,7 +24,7 @@ Indentation preferences - Indentation preferences + Einstellungen für Einrückung @@ -39,12 +39,12 @@ Space preferences - Space preferences + Einstellungen für Abstände Wrapping preferences - Wrapping preferences + Umbrucheinstellungen diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.es.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.es.xlf index 18aef8ccd6681..c422516063a79 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.es.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.es.xlf @@ -24,7 +24,7 @@ Indentation preferences - Indentation preferences + Preferencias de indentación @@ -39,12 +39,12 @@ Space preferences - Space preferences + Preferencias de espacio Wrapping preferences - Wrapping preferences + Preferencias de encapsulado diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.fr.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.fr.xlf index 8bae513a134bc..7f61cbb4def16 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.fr.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.fr.xlf @@ -24,7 +24,7 @@ Indentation preferences - Indentation preferences + Préférences de mise en retrait @@ -39,12 +39,12 @@ Space preferences - Space preferences + Préférences d'espace Wrapping preferences - Wrapping preferences + Préférences d'enveloppement diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.it.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.it.xlf index 6f43c85f2f0b5..b8449fdf21d52 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.it.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.it.xlf @@ -24,7 +24,7 @@ Indentation preferences - Indentation preferences + Preferenze per rientro @@ -39,12 +39,12 @@ Space preferences - Space preferences + Preferenze per spazi Wrapping preferences - Wrapping preferences + Preferenze per ritorno a capo diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ja.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ja.xlf index f7f5fe6bda2a6..ecda050a318fd 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ja.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ja.xlf @@ -24,7 +24,7 @@ Indentation preferences - Indentation preferences + インデント設定 @@ -39,12 +39,12 @@ Space preferences - Space preferences + スペース設定 Wrapping preferences - Wrapping preferences + 折り返しの設定 diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ko.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ko.xlf index a8734395e5cb6..bd2c18b1a10cb 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ko.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ko.xlf @@ -24,7 +24,7 @@ Indentation preferences - Indentation preferences + 들여쓰기 기본 설정 @@ -39,12 +39,12 @@ Space preferences - Space preferences + 공간 기본 설정 Wrapping preferences - Wrapping preferences + 기본 설정 래핑 diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.pl.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.pl.xlf index 7b70ff0a5bac1..118c5e584a2ed 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.pl.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.pl.xlf @@ -24,7 +24,7 @@ Indentation preferences - Indentation preferences + Preferencje wcięć @@ -39,12 +39,12 @@ Space preferences - Space preferences + Preferencje dotyczące odstępów Wrapping preferences - Wrapping preferences + Preferencje zawijania 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 9b354dd9495ac..6cd32053de2db 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.pt-BR.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.pt-BR.xlf @@ -24,7 +24,7 @@ Indentation preferences - Indentation preferences + Preferências de recuo @@ -39,12 +39,12 @@ Space preferences - Space preferences + Preferências de espaço Wrapping preferences - Wrapping preferences + Preferências de quebra de linha diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ru.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ru.xlf index c739367280c32..92d64968de2c1 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ru.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ru.xlf @@ -24,7 +24,7 @@ Indentation preferences - Indentation preferences + Параметры отступов @@ -39,12 +39,12 @@ Space preferences - Space preferences + Предпочтения для интервалов Wrapping preferences - Wrapping preferences + Параметры переноса diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.tr.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.tr.xlf index a47ef56c136cf..81397f123bbca 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.tr.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.tr.xlf @@ -24,7 +24,7 @@ Indentation preferences - Indentation preferences + Girinti tercihleri @@ -39,12 +39,12 @@ Space preferences - Space preferences + Boşluk tercihleri Wrapping preferences - Wrapping preferences + Kaydırma tercihleri diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.zh-Hans.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.zh-Hans.xlf index f7719e3167450..a5c3c5dec00d1 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.zh-Hans.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.zh-Hans.xlf @@ -24,7 +24,7 @@ Indentation preferences - Indentation preferences + 缩进首选项 @@ -39,12 +39,12 @@ Space preferences - Space preferences + 空格键首选项 Wrapping preferences - Wrapping preferences + 包装首选项 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 6e9cb79e56496..867ea6880c856 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.zh-Hant.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.zh-Hant.xlf @@ -24,7 +24,7 @@ Indentation preferences - Indentation preferences + 縮排喜好設定 @@ -39,12 +39,12 @@ Space preferences - Space preferences + 空格喜好設定 Wrapping preferences - Wrapping preferences + 換行喜好設定 diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeGeneration/CodeGenerationOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeGeneration/CodeGenerationOptions.cs index 0061f26bf1b40..2aa8408f2b58e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeGeneration/CodeGenerationOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeGeneration/CodeGenerationOptions.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Runtime.Serialization; -using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Microsoft.CodeAnalysis.Options; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/AddImportPlacement.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/AddImportPlacement.cs index 244c168bce9c6..ecaf4c96bf674 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/AddImportPlacement.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/AddImportPlacement.cs @@ -17,5 +17,10 @@ internal enum AddImportPlacement /// /// Place imports outside the namespace definition. /// - OutsideNamespace + OutsideNamespace, + + /// + /// Place imports outside the namespace definition, ignoring import aliases (which can stay inside the namespace). + /// + OutsideNamespaceIgnoringAliases } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CollectionExpressionPreference.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CollectionExpressionPreference.cs index b5973d10a29b1..fab94e9fc3b46 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CollectionExpressionPreference.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CollectionExpressionPreference.cs @@ -2,9 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Generic; -using System.Text; using Microsoft.CodeAnalysis.CodeStyle; namespace Microsoft.CodeAnalysis.Shared.CodeStyle; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/EditorConfigSeverityStrings.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/EditorConfigSeverityStrings.cs index 8876b66bc702b..cadb2413571d2 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/EditorConfigSeverityStrings.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/EditorConfigSeverityStrings.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.CodeAnalysis; internal static class EditorConfigSeverityStrings diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/FadingOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/FadingOptions.cs index 0a4cd95db9c33..a53cb54f98835 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/FadingOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/FadingOptions.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 Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.CodeStyle; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/NotificationOption2.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/NotificationOption2.cs index 06bbca420adfc..62887390e339b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/NotificationOption2.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/NotificationOption2.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Runtime.Serialization; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeStyle; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/VisualBasic/VisualBasicCodeStyleOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/VisualBasic/VisualBasicCodeStyleOptions.cs index 1d5e7a2694f63..9c2f9882bc202 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/VisualBasic/VisualBasicCodeStyleOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/VisualBasic/VisualBasicCodeStyleOptions.cs @@ -3,9 +3,7 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Collections.Immutable; -using System.Text; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Options; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Collections/IntervalTreeHelpers.NodeEnumerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Collections/IntervalTreeHelpers.NodeEnumerator.cs index ab41aa435c149..317c13ea42e6c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Collections/IntervalTreeHelpers.NodeEnumerator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Collections/IntervalTreeHelpers.NodeEnumerator.cs @@ -4,7 +4,6 @@ using System.Collections; using System.Collections.Generic; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Shared.Collections; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems index 56d65226cc0ea..d462c1f17317a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems @@ -15,24 +15,11 @@ - - - - - - - - - - - - - @@ -55,8 +42,6 @@ - - @@ -436,6 +421,7 @@ + @@ -493,9 +479,6 @@ - - - @@ -515,8 +498,6 @@ - - @@ -609,9 +590,7 @@ - - diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EditorConfig/LanguageConstants.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EditorConfig/LanguageConstants.cs index d8558e45d1f0d..f2420c2298109 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EditorConfig/LanguageConstants.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EditorConfig/LanguageConstants.cs @@ -2,10 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Generic; -using System.Text; - namespace Microsoft.CodeAnalysis.EditorConfig; internal static class LanguageConstants diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EditorConfig/Parsing/IEditorConfigOptionAccumulator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EditorConfig/Parsing/IEditorConfigOptionAccumulator.cs index 247262637cee0..b242b074d7683 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EditorConfig/Parsing/IEditorConfigOptionAccumulator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EditorConfig/Parsing/IEditorConfigOptionAccumulator.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Collections.Immutable; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.EditorConfig.Parsing; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EditorConfig/Parsing/NamingStyles/NamingStyleOptionAccumulator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EditorConfig/Parsing/NamingStyles/NamingStyleOptionAccumulator.cs index 656e3458348a1..e384fee0bfb5e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EditorConfig/Parsing/NamingStyles/NamingStyleOptionAccumulator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EditorConfig/Parsing/NamingStyles/NamingStyleOptionAccumulator.cs @@ -3,8 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Collections.Immutable; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; using static Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles.EditorConfigNamingStyleParser; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EmbeddedLanguages/Common/EmbeddedDiagnostic.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EmbeddedLanguages/Common/EmbeddedDiagnostic.cs index b17f4d4bd1235..88344f39c637f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EmbeddedLanguages/Common/EmbeddedDiagnostic.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EmbeddedLanguages/Common/EmbeddedDiagnostic.cs @@ -2,11 +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.Diagnostics; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.EmbeddedLanguages.Common; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EmbeddedLanguages/VirtualChars/AbstractVirtualCharService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EmbeddedLanguages/VirtualChars/AbstractVirtualCharService.cs index 187e045eef7ab..e9c6524b84869 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EmbeddedLanguages/VirtualChars/AbstractVirtualCharService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EmbeddedLanguages/VirtualChars/AbstractVirtualCharService.cs @@ -7,7 +7,6 @@ using System.Text; using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.LanguageService; -using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EmbeddedLanguages/VirtualChars/VirtualChar.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EmbeddedLanguages/VirtualChars/VirtualChar.cs index 9f4ac3d1d8e47..0e2fd7c6e3231 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EmbeddedLanguages/VirtualChars/VirtualChar.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EmbeddedLanguages/VirtualChars/VirtualChar.cs @@ -5,7 +5,6 @@ using System; using System.Text; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EmbeddedLanguages/VirtualChars/VirtualCharSequence.Enumerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EmbeddedLanguages/VirtualChars/VirtualCharSequence.Enumerator.cs index 331512aa7fbe7..941dd26488984 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EmbeddedLanguages/VirtualChars/VirtualCharSequence.Enumerator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EmbeddedLanguages/VirtualChars/VirtualCharSequence.Enumerator.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections; using System.Collections.Generic; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/AnalysisContextExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/AnalysisContextExtensions.cs index f4f351d4ae6a2..2b17437a2af43 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/AnalysisContextExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/AnalysisContextExtensions.cs @@ -5,7 +5,6 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/AnalyzerConfigOptionsExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/AnalyzerConfigOptionsExtensions.cs index d4f598d420175..b61dd3a2f2c52 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/AnalyzerConfigOptionsExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/AnalyzerConfigOptionsExtensions.cs @@ -6,7 +6,6 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Microsoft.CodeAnalysis.Options; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/DiagnosticSeverityExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/DiagnosticSeverityExtensions.cs index 096a23b825d91..22e039c02b096 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/DiagnosticSeverityExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/DiagnosticSeverityExtensions.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.CodeStyle; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Diagnostics; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/DiagnosticSeverityExtensions_Shared.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/DiagnosticSeverityExtensions_Shared.cs index 52fe393accbf3..4b717c36220c7 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/DiagnosticSeverityExtensions_Shared.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/DiagnosticSeverityExtensions_Shared.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Diagnostics; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/DirectiveInfo.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/DirectiveInfo.cs index 4563c330271a9..87c680a6fb5ee 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/DirectiveInfo.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/DirectiveInfo.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Collections.Immutable; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ICompilationExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ICompilationExtensions.cs index 2a8b64755a480..d28f62304e326 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ICompilationExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ICompilationExtensions.cs @@ -3,8 +3,10 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; +using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; @@ -69,12 +71,24 @@ public static ImmutableArray GetReferencedAssemblySymbols(this return builder.ToImmutableAndFree(); } + public static INamedTypeSymbol? ArgumentExceptionType(this Compilation compilation) + => compilation.GetTypeByMetadataName(typeof(ArgumentException).FullName!); + + public static INamedTypeSymbol? ArgumentNullExceptionType(this Compilation compilation) + => compilation.GetTypeByMetadataName(typeof(ArgumentNullException).FullName!); + public static INamedTypeSymbol? ArrayType(this Compilation compilation) => compilation.GetTypeByMetadataName(typeof(Array).FullName!); public static INamedTypeSymbol? AttributeType(this Compilation compilation) => compilation.GetTypeByMetadataName(typeof(Attribute).FullName!); + public static INamedTypeSymbol? BlockingCollectionOfTType(this Compilation compilation) + => compilation.GetTypeByMetadataName(typeof(BlockingCollection<>).FullName!); + + public static INamedTypeSymbol? CollectionOfTType(this Compilation compilation) + => compilation.GetTypeByMetadataName(typeof(Collection<>).FullName!); + public static INamedTypeSymbol? ExceptionType(this Compilation compilation) => compilation.GetTypeByMetadataName(typeof(Exception).FullName!); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/IMethodSymbolExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/IMethodSymbolExtensions.cs index b1d0f13b0eb05..3486531d1de76 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/IMethodSymbolExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/IMethodSymbolExtensions.cs @@ -6,9 +6,7 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Linq; using Microsoft.CodeAnalysis.LanguageService; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/INamespaceOrTypeSymbolExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/INamespaceOrTypeSymbolExtensions.cs index 169623435a5d6..51d9f11b43b9e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/INamespaceOrTypeSymbolExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/INamespaceOrTypeSymbolExtensions.cs @@ -8,7 +8,6 @@ using System.Runtime.CompilerServices; using System.Threading; using Microsoft.CodeAnalysis.PooledObjects; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions_Accessibility.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions_Accessibility.cs index 8bd37a405f656..6a62c91ab702d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions_Accessibility.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions_Accessibility.cs @@ -4,7 +4,6 @@ using System; using System.Diagnostics; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.CollectTypeParameterSymbolsVisitor.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.CollectTypeParameterSymbolsVisitor.cs index 054a38b5a4d15..9211e17456337 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.CollectTypeParameterSymbolsVisitor.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.CollectTypeParameterSymbolsVisitor.cs @@ -2,20 +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. -#nullable disable - using System; -using System.Collections.Generic; +using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.Shared.Extensions; internal static partial class ITypeSymbolExtensions { private sealed class CollectTypeParameterSymbolsVisitor( - IList typeParameters, - bool onlyMethodTypeParameters) : SymbolVisitor + ArrayBuilder typeParameters, + bool onlyMethodTypeParameters) : SymbolVisitor, IDisposable { - private readonly HashSet _visited = []; + private readonly PooledHashSet _visited = PooledHashSet.GetInstance(); + + public void Dispose() + { + _visited.Free(); + } public override void DefaultVisit(ISymbol node) => throw new NotImplementedException(); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.CompilationTypeGenerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.CompilationTypeGenerator.cs index 39c5c0d5682d7..53fd146c7f233 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.CompilationTypeGenerator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.CompilationTypeGenerator.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.Shared.Extensions; internal static partial class ITypeSymbolExtensions diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.cs index dfa471e44ec1e..c5eb6a4d7b6de 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.cs @@ -10,6 +10,7 @@ using System.Linq; using System.Runtime.CompilerServices; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; @@ -796,20 +797,34 @@ public static bool IsInlineArray([NotNullWhen(true)] this ITypeSymbol? type) { return type?.Accept(new UnnamedErrorTypeRemover(compilation)); } - public static IList GetReferencedMethodTypeParameters( - this ITypeSymbol? type, IList? result = null) + + public static void AddReferencedMethodTypeParameters( + this ITypeSymbol? type, ArrayBuilder result) { - result ??= []; - type?.Accept(new CollectTypeParameterSymbolsVisitor(result, onlyMethodTypeParameters: true)); - return result; + AddReferencedTypeParameters(type, result, onlyMethodTypeParameters: true); } - public static IList GetReferencedTypeParameters( - this ITypeSymbol? type, IList? result = null) + public static void AddReferencedTypeParameters( + this ITypeSymbol? type, ArrayBuilder result) { - result ??= []; - type?.Accept(new CollectTypeParameterSymbolsVisitor(result, onlyMethodTypeParameters: false)); - return result; + AddReferencedTypeParameters(type, result, onlyMethodTypeParameters: false); + } + + private static void AddReferencedTypeParameters( + this ITypeSymbol? type, ArrayBuilder result, bool onlyMethodTypeParameters) + { + if (type != null) + { + using var collector = new CollectTypeParameterSymbolsVisitor(result, onlyMethodTypeParameters); + type.Accept(collector); + } + } + + public static IList GetReferencedTypeParameters(this ITypeSymbol? type) + { + using var _ = ArrayBuilder.GetInstance(out var result); + AddReferencedTypeParameters(type, result); + return result.ToList(); } [return: NotNullIfNotNull(parameterName: nameof(type))] diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ImmutableArrayExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ImmutableArrayExtensions.cs index d48e7dc3b86af..a3353548a19f5 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ImmutableArrayExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ImmutableArrayExtensions.cs @@ -31,15 +31,6 @@ public static ImmutableArray ToImmutableArrayOrEmpty(this T[]? items) return ImmutableArray.Create(items); } - public static ImmutableArray TakeAsArray(this ImmutableArray array, int count) - { - var result = new FixedSizeArrayBuilder(count); - for (var i = 0; i < count; i++) - result.Add(array[i]); - - return result.MoveToImmutable(); - } - public static ImmutableArray ToImmutableAndClear(this ImmutableArray.Builder builder) { if (builder.Count == 0) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ListExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ListExtensions.cs index 48ba16001283e..5e059879b6066 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ListExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ListExtensions.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/LocationExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/LocationExtensions.cs index ef1b7a56b34ef..192df5e591963 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/LocationExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/LocationExtensions.cs @@ -4,7 +4,6 @@ using System.Diagnostics; using System.Threading; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ObjectWriterExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ObjectWriterExtensions.cs index cbc86569e6d57..475be240853d2 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ObjectWriterExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ObjectWriterExtensions.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Immutable; -using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/OperationExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/OperationExtensions.cs index eeea1ca2ba754..0ae859bd6b33a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/OperationExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/OperationExtensions.cs @@ -24,6 +24,13 @@ public static bool IsTargetOfObjectMemberInitializer(this IOperation operation) /// Returns the for the given operation. /// This extension can be removed once https://github.com/dotnet/roslyn/issues/25057 is implemented. /// + /// + /// When referring to a variable, this method should only return a 'write' result if the variable is entirely + /// overwritten. Not if the variable is written through. For example, a write to a property on a struct + /// variable is not a write to the struct variable (though at runtime it might impact the value in some fashion). + /// Put another way, this only returns 'write' when certain that the entire value is absolutely + /// entirely overwritten. + /// public static ValueUsageInfo GetValueUsageInfo(this IOperation operation, ISymbol containingSymbol) { /* @@ -205,12 +212,6 @@ where void Foo(in T v) { return ValueUsageInfo.Write; } - else if (operation is { Type.IsValueType: true, Parent: IPropertyReferenceOperation }) - { - // accessing an indexer/property off of a value type will read/write the value type depending on how the - // indexer/property itself is used. - return GetValueUsageInfo(operation.Parent, containingSymbol); - } else if (operation.Parent is IVariableInitializerOperation variableInitializerOperation) { if (variableInitializerOperation.Parent is IVariableDeclaratorOperation variableDeclaratorOperation) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ReportDiagnosticExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ReportDiagnosticExtensions.cs index 9e7045ca5abf7..5200414715f38 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ReportDiagnosticExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ReportDiagnosticExtensions.cs @@ -4,7 +4,6 @@ using System; using Microsoft.CodeAnalysis.CodeStyle; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Diagnostics; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SemanticEquivalence.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SemanticEquivalence.cs index b9805bdfe3e96..e0b11b761b9e2 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SemanticEquivalence.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SemanticEquivalence.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Shared.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SourceTextExtensions_SharedWithCodeStyle.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SourceTextExtensions_SharedWithCodeStyle.cs index 32f8bd1348542..76fb6dbb226a7 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SourceTextExtensions_SharedWithCodeStyle.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SourceTextExtensions_SharedWithCodeStyle.cs @@ -5,7 +5,6 @@ using System; using System.Threading; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/StackExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/StackExtensions.cs index 0df5a82729fd4..1a192e8bc6ab5 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/StackExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/StackExtensions.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SyntaxTreeExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SyntaxTreeExtensions.cs index 77d4b1e1d214c..2752f6e9cd32b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SyntaxTreeExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SyntaxTreeExtensions.cs @@ -17,7 +17,9 @@ internal static partial class SyntaxTreeExtensions { public static bool OverlapsHiddenPosition([NotNullWhen(returnValue: true)] this SyntaxTree? tree, TextSpan span, CancellationToken cancellationToken) { - if (tree == null) + // Short-circuit if there are no line mappings to avoid potentially realizing the source text. + // All lines are visible if there are no line mappings. + if (tree == null || tree.GetLineMappings(cancellationToken).IsEmpty()) { return false; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/CustomDataFlowAnalysis.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/CustomDataFlowAnalysis.cs index a7a322b08ecb8..821d7f87990d0 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/CustomDataFlowAnalysis.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/CustomDataFlowAnalysis.cs @@ -9,7 +9,6 @@ using System.Diagnostics; using System.Threading; using Microsoft.CodeAnalysis.PooledObjects; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.FlowAnalysis; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/DataFlowAnalyzer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/DataFlowAnalyzer.cs index 1637735d46d1d..462a45c1e7daf 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/DataFlowAnalyzer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/DataFlowAnalyzer.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Threading; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/FlowCaptureKind.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/FlowCaptureKind.cs index cae9bc1b8b879..9b5de6361b601 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/FlowCaptureKind.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/FlowCaptureKind.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.FlowAnalysis; /// diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/SymbolUsageAnalysis/SymbolUsageAnalysis.BasicBlockAnalysisData.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/SymbolUsageAnalysis/SymbolUsageAnalysis.BasicBlockAnalysisData.cs index 66bf828dcf33f..f1ed7ccdaae96 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/SymbolUsageAnalysis/SymbolUsageAnalysis.BasicBlockAnalysisData.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/SymbolUsageAnalysis/SymbolUsageAnalysis.BasicBlockAnalysisData.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using Microsoft.CodeAnalysis.PooledObjects; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/SymbolUsageAnalysis/SymbolUsageAnalysis.OperationTreeAnalysisData.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/SymbolUsageAnalysis/SymbolUsageAnalysis.OperationTreeAnalysisData.cs index 9f4c4a4d77edf..42c30ebf2196a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/SymbolUsageAnalysis/SymbolUsageAnalysis.OperationTreeAnalysisData.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/SymbolUsageAnalysis/SymbolUsageAnalysis.OperationTreeAnalysisData.cs @@ -2,15 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Immutable; using System.Threading; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.FlowAnalysis.SymbolUsageAnalysis; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/SymbolUsageAnalysis/SymbolUsageAnalysis.Walker.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/SymbolUsageAnalysis/SymbolUsageAnalysis.Walker.cs index 44910ce0b3446..2268196be9bcd 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/SymbolUsageAnalysis/SymbolUsageAnalysis.Walker.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/SymbolUsageAnalysis/SymbolUsageAnalysis.Walker.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.FlowAnalysis.SymbolUsageAnalysis; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/SymbolUsageAnalysis/SymbolUsageResult.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/SymbolUsageAnalysis/SymbolUsageResult.cs index 18b5732b867af..e0fcc56a680cd 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/SymbolUsageAnalysis/SymbolUsageResult.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/SymbolUsageAnalysis/SymbolUsageResult.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.Linq; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.IndentationData.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.IndentationData.cs index 823d39dd0d745..df97551d56dca 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.IndentationData.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.IndentationData.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Diagnostics; using Microsoft.CodeAnalysis.Formatting.Rules; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.InitialContextFinder.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.InitialContextFinder.cs index bc847a5e2e56f..cf9a64fabd374 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.InitialContextFinder.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.InitialContextFinder.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.cs index 16d91559bef3d..0df5565d06940 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.cs @@ -8,7 +8,6 @@ using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.Collections; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Formatting.Rules; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Utilities; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/DocumentFormattingOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/DocumentFormattingOptions.cs index 8480f2cd540d2..d7472246f1389 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/DocumentFormattingOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/DocumentFormattingOptions.cs @@ -3,10 +3,6 @@ // 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.Options; namespace Microsoft.CodeAnalysis.Formatting; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractAggregatedFormattingResult.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractAggregatedFormattingResult.cs index 4253c2f4d7cca..88574b4bf80a6 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractAggregatedFormattingResult.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractAggregatedFormattingResult.cs @@ -8,7 +8,6 @@ using System.Threading; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Shared.Collections; -using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; 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 51c35aff5e931..490b310bafb99 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.AbstractComplexTrivia.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.AbstractComplexTrivia.cs @@ -4,7 +4,6 @@ using System.Threading; using Microsoft.CodeAnalysis.Shared.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Formatting; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.FormattedWhitespace.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.FormattedWhitespace.cs index 2e1c7f1a60ce4..ad716e23bbf7b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.FormattedWhitespace.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.FormattedWhitespace.cs @@ -5,9 +5,7 @@ using System; using System.Collections.Generic; using System.Threading; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Formatting; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.ModifiedWhitespace.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.ModifiedWhitespace.cs index 474e09b6a354d..495dc6548c390 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.ModifiedWhitespace.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.ModifiedWhitespace.cs @@ -4,8 +4,6 @@ using System; using System.Threading; -using Microsoft.CodeAnalysis.Diagnostics; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Formatting; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.Whitespace.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.Whitespace.cs index bda9b5b3785b4..542a744ec66cc 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.Whitespace.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.Whitespace.cs @@ -5,9 +5,7 @@ using System; using System.Collections.Generic; using System.Threading; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Formatting; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.cs index 71a0fce380856..d9847c2da7662 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.cs @@ -4,10 +4,6 @@ using System; using System.Collections.Generic; -using System.Security.Principal; -using System.Threading; -using Microsoft.CodeAnalysis.Diagnostics; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Formatting; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/ChainedFormattingRules.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/ChainedFormattingRules.cs index b22e34f0e2904..bb99dbb29cdf3 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/ChainedFormattingRules.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/ChainedFormattingRules.cs @@ -8,7 +8,6 @@ using System.Collections.Immutable; using System.Linq; using System.Reflection; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Formatting.Rules; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenData.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenData.cs index 1bc2f1c870430..9f027e199acda 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenData.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenData.cs @@ -3,10 +3,7 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; -using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Formatting; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenPairWithOperations.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenPairWithOperations.cs index 6e24485386c9e..1742783d2ff37 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenPairWithOperations.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenPairWithOperations.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.Formatting.Rules; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Formatting; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenStream.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenStream.cs index 7fc5e874ff56c..cba2d36c6850e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenStream.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenStream.cs @@ -7,11 +7,9 @@ using System.Diagnostics; using System.Threading; using Microsoft.CodeAnalysis.Collections; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Formatting; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.Debug.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.Debug.cs index 9afc40db1754b..447fe86b4076c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.Debug.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.Debug.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Formatting; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.Node.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.Node.cs index 0569ec47103ee..851889b01bded 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.Node.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.Node.cs @@ -4,7 +4,6 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Formatting; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.NodeAndText.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.NodeAndText.cs index 11a2596964922..4b4df723f977d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.NodeAndText.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.NodeAndText.cs @@ -4,7 +4,6 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Formatting; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.StructuredTrivia.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.StructuredTrivia.cs index c11ac58f56781..5bd16b06d4f34 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.StructuredTrivia.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.StructuredTrivia.cs @@ -4,7 +4,6 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Formatting; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.cs index af1e22a020df9..31c6c1b9f86d3 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Formatting; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TriviaData.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TriviaData.cs index 4f62d0df988a8..4c40452640fe2 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TriviaData.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TriviaData.cs @@ -5,9 +5,7 @@ using System; using System.Collections.Generic; using System.Threading; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Formatting; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/FormattingExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/FormattingExtensions.cs index 2f56cc8771715..6e2e935413c3a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/FormattingExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/FormattingExtensions.cs @@ -13,7 +13,6 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Formatting; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/NextAlignTokensOperationAction.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/NextAlignTokensOperationAction.cs index 623f0ea92ae89..ce1b3f15e21a8 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/NextAlignTokensOperationAction.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/NextAlignTokensOperationAction.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Collections.Immutable; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Formatting.Rules; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/NextAnchorIndentationOperationAction.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/NextAnchorIndentationOperationAction.cs index 77c4b9a484870..aad6a25ec9098 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/NextAnchorIndentationOperationAction.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/NextAnchorIndentationOperationAction.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Collections.Immutable; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Formatting.Rules; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/NextGetAdjustNewLinesOperation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/NextGetAdjustNewLinesOperation.cs index 84c51ec522e9f..6ed6763af6a7d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/NextGetAdjustNewLinesOperation.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/NextGetAdjustNewLinesOperation.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Formatting.Rules; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/NextGetAdjustSpacesOperation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/NextGetAdjustSpacesOperation.cs index 7e99042f0aa5d..87bc36ebd1420 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/NextGetAdjustSpacesOperation.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/NextGetAdjustSpacesOperation.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Formatting.Rules; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/NextIndentBlockOperationAction.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/NextIndentBlockOperationAction.cs index 1c4e8bcf02125..5e8fb587ab840 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/NextIndentBlockOperationAction.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/NextIndentBlockOperationAction.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Collections.Immutable; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Formatting.Rules; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/NextSuppressOperationAction.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/NextSuppressOperationAction.cs index f0a02813eb808..64a0891413dcd 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/NextSuppressOperationAction.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/NextSuppressOperationAction.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. -using System.Collections.Generic; using System.Collections.Immutable; using Microsoft.CodeAnalysis.PooledObjects; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Formatting.Rules; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/Operations/AdjustNewLinesOperation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/Operations/AdjustNewLinesOperation.cs index 6bd175857e779..269f43f873199 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/Operations/AdjustNewLinesOperation.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/Operations/AdjustNewLinesOperation.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Roslyn.Utilities; - namespace Microsoft.CodeAnalysis.Formatting.Rules; /// diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/Operations/AdjustSpacesOperation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/Operations/AdjustSpacesOperation.cs index 0696ae808b9a6..952f06eb5e80d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/Operations/AdjustSpacesOperation.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/Operations/AdjustSpacesOperation.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Roslyn.Utilities; - namespace Microsoft.CodeAnalysis.Formatting.Rules; /// diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/Operations/AnchorIndentationOperation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/Operations/AnchorIndentationOperation.cs index b91e75d3caaa5..23700e9de0bbc 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/Operations/AnchorIndentationOperation.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/Operations/AnchorIndentationOperation.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Formatting.Rules; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/Operations/FormattingOperations.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/Operations/FormattingOperations.cs index ea13eaf68014c..00c050309b163 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/Operations/FormattingOperations.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/Operations/FormattingOperations.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; -using Microsoft.CodeAnalysis.Diagnostics; namespace Microsoft.CodeAnalysis.Formatting.Rules; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/Operations/IndentBlockOperation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/Operations/IndentBlockOperation.cs index 47200381d83de..fa545ead82ba9 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/Operations/IndentBlockOperation.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/Operations/IndentBlockOperation.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Formatting.Rules; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/Operations/SuppressOperation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/Operations/SuppressOperation.cs index c0c304dd28574..47bac08fa1188 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/Operations/SuppressOperation.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/Operations/SuppressOperation.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Formatting.Rules; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/TriviaEngine/AbstractTriviaFormatter.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/TriviaEngine/AbstractTriviaFormatter.cs index b99da34f0b4c1..96b39acc5e2e5 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/TriviaEngine/AbstractTriviaFormatter.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/TriviaEngine/AbstractTriviaFormatter.cs @@ -8,7 +8,6 @@ using System.Diagnostics.CodeAnalysis; using System.Threading; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Formatting.Rules; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Helpers/RemoveUnnecessaryImports/RemoveUnnecessaryImportsHelpers.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Helpers/RemoveUnnecessaryImports/RemoveUnnecessaryImportsHelpers.cs index 733a72386b148..ac011f6908b1e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Helpers/RemoveUnnecessaryImports/RemoveUnnecessaryImportsHelpers.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Helpers/RemoveUnnecessaryImports/RemoveUnnecessaryImportsHelpers.cs @@ -2,10 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Generic; using System.Linq; -using System.Text; using Microsoft.CodeAnalysis.LanguageService; namespace Microsoft.CodeAnalysis.Shared.Helpers.RemoveUnnecessaryImports; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Indentation/AbstractIndentation.Indenter.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Indentation/AbstractIndentation.Indenter.cs index 9c2e9583ece61..63a2e0ce43f52 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Indentation/AbstractIndentation.Indenter.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Indentation/AbstractIndentation.Indenter.cs @@ -12,7 +12,6 @@ using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Indentation; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Indentation/ISmartTokenFormatter.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Indentation/ISmartTokenFormatter.cs index bd162af4bdde3..07b04326d45e3 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Indentation/ISmartTokenFormatter.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Indentation/ISmartTokenFormatter.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Threading; -using System.Threading.Tasks; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Indentation; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Log/FunctionId.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Log/FunctionId.cs index 4f123aa508e83..8c37a0ce21abc 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Log/FunctionId.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Log/FunctionId.cs @@ -634,9 +634,25 @@ internal enum FunctionId Copilot_On_The_Fly_Docs_Results_Canceled = 814, Copilot_On_The_Fly_Docs_Get_Counts = 815, Copilot_On_The_Fly_Docs_Content_Excluded = 816, + + Copilot_Generate_Documentation_Dismissed = 820, + Copilot_Generate_Documentation_Diverged = 821, + Copilot_Generate_Documentation_Displayed = 822, + Copilot_Generate_Documentation_Accepted = 823, + Copilot_Generate_Documentation_Canceled = 824, + + Copilot_Implement_NotImplementedException_Fix_Registered = 830, + Copilot_Implement_NotImplementedException_Failed = 831, + Copilot_Implement_NotImplementedException_Completed = 832, + Copilot_Rename = 851, VSCode_LanguageServer_Started = 860, VSCode_Project_Load_Started = 861, VSCode_Projects_Load_Completed = 862, + + // 900-999 for items that don't fit into other categories. + Workspace_EventsImmediate = 900, + ChecksumUpdater_SynchronizeTextChangesStatus = 901, + RemoteHostService_SynchronizeTextAsyncStatus = 902, } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/EditorConfig/EditorConfigNamingStyleParser_NamingRule.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/EditorConfig/EditorConfigNamingStyleParser_NamingRule.cs index 21aa46499162d..e697a1bf349d9 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/EditorConfig/EditorConfigNamingStyleParser_NamingRule.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/EditorConfig/EditorConfigNamingStyleParser_NamingRule.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.EditorConfig.Parsing; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/EditorConfig/EditorConfigNamingStyleParser_NamingStyle.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/EditorConfig/EditorConfigNamingStyleParser_NamingStyle.cs index 75d86a84044c2..40fea29c47c0d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/EditorConfig/EditorConfigNamingStyleParser_NamingStyle.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/EditorConfig/EditorConfigNamingStyleParser_NamingStyle.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.EditorConfig.Parsing.NamingStyles; using Microsoft.CodeAnalysis.NamingStyles; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/Naming/IdentifierNameParts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/Naming/IdentifierNameParts.cs index 3faa922906d29..a4049bc0b136e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/Naming/IdentifierNameParts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/Naming/IdentifierNameParts.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Microsoft.CodeAnalysis.NamingStyles; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyle.WordSpanEnumerable.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyle.WordSpanEnumerable.cs index 0c0bae6082807..abed7cc066568 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyle.WordSpanEnumerable.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyle.WordSpanEnumerable.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.NamingStyles; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyle.WordSpanEnumerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyle.WordSpanEnumerator.cs index b4eadecfdbd93..f263d790b8277 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyle.WordSpanEnumerator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyle.WordSpanEnumerator.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.Diagnostics; using Microsoft.CodeAnalysis.Text; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyleRules.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyleRules.cs index c70501242743d..ac44ce18aebb1 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyleRules.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyleRules.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/ArrayBuilder.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/ArrayBuilder.cs deleted file mode 100644 index c40663de34f02..0000000000000 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/ArrayBuilder.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 Microsoft.CodeAnalysis.PooledObjects; - -internal sealed partial class ArrayBuilder : IPooled -{ - public static PooledDisposer> GetInstance(out ArrayBuilder instance) - { - instance = GetInstance(); - return new PooledDisposer>(instance); - } - - public static PooledDisposer> GetInstance(int capacity, out ArrayBuilder instance) - { - instance = GetInstance(capacity); - return new PooledDisposer>(instance); - } - - public static PooledDisposer> GetInstance(int capacity, T fillWithValue, out ArrayBuilder instance) - { - instance = GetInstance(capacity, fillWithValue); - return new PooledDisposer>(instance); - } -} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/PooledDictionary.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/PooledDictionary.cs index f431ba4ee31ce..c8e35d932b555 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/PooledDictionary.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/PooledDictionary.cs @@ -11,4 +11,8 @@ public static PooledDisposer> GetInstance(out PooledDicti instance = GetInstance(); return new PooledDisposer>(instance); } + + // Nothing special to do here. + void IPooled.Free(bool discardLargeInstance) + => this.Free(); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/PooledDisposer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/PooledDisposer.cs index 1e922f60e5382..48fd3a6008d68 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/PooledDisposer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/PooledDisposer.cs @@ -2,15 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using Roslyn.Utilities; - namespace Microsoft.CodeAnalysis.PooledObjects; [NonCopyable] -internal readonly struct PooledDisposer(TPoolable instance) : IDisposable +internal partial struct PooledDisposer where TPoolable : class, IPooled { - void IDisposable.Dispose() - => instance?.Free(); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/PooledHashSet.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/PooledHashSet.cs index 7c68246ee11ae..64e7ea3c10b95 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/PooledHashSet.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/PooledHashSet.cs @@ -13,4 +13,8 @@ public static PooledDisposer> GetInstance(out PooledHashSet instance = GetInstance(); return new PooledDisposer>(instance); } + + // Nothing special to do here. + void IPooled.Free(bool discardLargeInstance) + => this.Free(); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/PooledStringBuilder.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/PooledStringBuilder.cs index 2d18c1ee3ed89..af156fd99bdd9 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/PooledStringBuilder.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/PooledStringBuilder.cs @@ -8,10 +8,32 @@ namespace Microsoft.CodeAnalysis.PooledObjects; internal sealed partial class PooledStringBuilder : IPooled { + private static readonly ObjectPool s_keepLargeInstancesPool = CreatePool(); + public static PooledDisposer GetInstance(out StringBuilder instance) + => GetInstance(discardLargeInstances: true, out instance); + + public static PooledDisposer GetInstance(bool discardLargeInstances, out StringBuilder instance) { - var pooledInstance = GetInstance(); + // If we're discarding large instances (the default behavior), then just use the normal pool. If we're not, use + // a specific pool so that *other* normal callers don't accidentally get it and discard it. + var pooledInstance = discardLargeInstances ? GetInstance() : s_keepLargeInstancesPool.Allocate(); instance = pooledInstance; - return new PooledDisposer(pooledInstance); + return new PooledDisposer(pooledInstance, discardLargeInstances); + } + + void IPooled.Free(bool discardLargeInstances) + { + // If we're discarding large instances, use the default behavior (which already does that). Otherwise, always + // clear and free the instance back to its originating pool. + if (discardLargeInstances) + { + Free(); + } + else + { + this.Builder.Clear(); + _pool.Free(this); + } } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/IEditorConfigValueSerializer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/IEditorConfigValueSerializer.cs index c2b269f535131..66037f83cc4c9 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/IEditorConfigValueSerializer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/IEditorConfigValueSerializer.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; - namespace Microsoft.CodeAnalysis.Options; internal interface IEditorConfigValueSerializer diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/IOptionReader.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/IOptionReader.cs index 078b8430ad7c2..832cd6889a9c0 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/IOptionReader.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/IOptionReader.cs @@ -2,10 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/Option2.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/Option2.cs index 01e7d62ba20fe..0e4634707a473 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/Option2.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/Option2.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Immutable; using System.Diagnostics; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Options; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionDefinition.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionDefinition.cs index 8f0c4f3347445..0ef0bfb8a9e03 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionDefinition.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionDefinition.cs @@ -7,7 +7,6 @@ using System.Diagnostics; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Options; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionGroup.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionGroup.cs index a1f05a1ea3376..93e6639dc75e1 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionGroup.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionGroup.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; - namespace Microsoft.CodeAnalysis.Options; /// diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionKey2.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionKey2.cs index b2eaabcd75f7c..f3916eeda0a33 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionKey2.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionKey2.cs @@ -4,7 +4,6 @@ using System; using System.Diagnostics; -using Roslyn.Utilities; #if CODE_STYLE using WorkspacesResources = Microsoft.CodeAnalysis.CodeStyleResources; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/PublicOptionFactory.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/PublicOptionFactory.cs index f3165ed53e9ba..aba0e3e615fe6 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/PublicOptionFactory.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/PublicOptionFactory.cs @@ -3,9 +3,7 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Immutable; using Microsoft.CodeAnalysis.CodeStyle; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Options; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/HeaderFacts/AbstractHeaderFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/HeaderFacts/AbstractHeaderFacts.cs index ad5bb68d9be47..1ed0432144e9a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/HeaderFacts/AbstractHeaderFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/HeaderFacts/AbstractHeaderFacts.cs @@ -3,16 +3,11 @@ // 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 System.Threading; -using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageService; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/Precedence/IPrecedenceService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/Precedence/IPrecedenceService.cs index 9092747c8aa3d..2fd4b1266e744 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/Precedence/IPrecedenceService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/Precedence/IPrecedenceService.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.Precedence; internal interface IPrecedenceService diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SelectedMembers/AbstractSelectedMembers.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SelectedMembers/AbstractSelectedMembers.cs index 840b4cb27697f..3d5cefb9fd5c9 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SelectedMembers/AbstractSelectedMembers.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SelectedMembers/AbstractSelectedMembers.cs @@ -5,7 +5,6 @@ #nullable disable using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SemanticFacts/ForEachSymbols.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SemanticFacts/ForEachSymbols.cs index 2de67f0cca83e..01a953c7f803e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SemanticFacts/ForEachSymbols.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SemanticFacts/ForEachSymbols.cs @@ -2,29 +2,18 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - namespace Microsoft.CodeAnalysis.LanguageService; -internal readonly struct ForEachSymbols +internal readonly struct ForEachSymbols( + IMethodSymbol? getEnumeratorMethod, + IMethodSymbol? moveNextMethod, + IPropertySymbol? currentProperty, + IMethodSymbol? disposeMethod, + ITypeSymbol? elementType) { - public readonly IMethodSymbol GetEnumeratorMethod; - public readonly IMethodSymbol MoveNextMethod; - public readonly IPropertySymbol CurrentProperty; - public readonly IMethodSymbol DisposeMethod; - public readonly ITypeSymbol ElementType; - - internal ForEachSymbols(IMethodSymbol getEnumeratorMethod, - IMethodSymbol moveNextMethod, - IPropertySymbol currentProperty, - IMethodSymbol disposeMethod, - ITypeSymbol elementType) - : this() - { - this.GetEnumeratorMethod = getEnumeratorMethod; - this.MoveNextMethod = moveNextMethod; - this.CurrentProperty = currentProperty; - this.DisposeMethod = disposeMethod; - this.ElementType = elementType; - } + public readonly IMethodSymbol? GetEnumeratorMethod = getEnumeratorMethod; + public readonly IMethodSymbol? MoveNextMethod = moveNextMethod; + public readonly IPropertySymbol? CurrentProperty = currentProperty; + public readonly IMethodSymbol? DisposeMethod = disposeMethod; + public readonly ITypeSymbol? ElementType = elementType; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SemanticFacts/ISemanticFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SemanticFacts/ISemanticFacts.cs index 7f05d5afec83f..7db9c7e856f5e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SemanticFacts/ISemanticFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SemanticFacts/ISemanticFacts.cs @@ -2,13 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.LanguageService; @@ -121,6 +119,8 @@ internal partial interface ISemanticFacts /// IPreprocessingSymbol? GetPreprocessingSymbol(SemanticModel semanticModel, SyntaxNode node); + bool TryGetPrimaryConstructor(INamedTypeSymbol typeSymbol, [NotNullWhen(true)] out IMethodSymbol? primaryConstructor); + #if !CODE_STYLE /// diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/AbstractDocumentationCommentService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/AbstractDocumentationCommentService.cs index 535cdc8f2fea2..dc7b3a1f74f77 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/AbstractDocumentationCommentService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/AbstractDocumentationCommentService.cs @@ -2,9 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - -using System.Diagnostics; using System.Linq; using System.Threading; using Roslyn.Utilities; @@ -59,8 +56,11 @@ private string GetDocumentationCommentPrefix(TDocumentationCommentTriviaSyntax d } public string GetBannerText( - TDocumentationCommentTriviaSyntax documentationComment, int maxBannerLength, CancellationToken cancellationToken) + TDocumentationCommentTriviaSyntax? documentationComment, int maxBannerLength, CancellationToken cancellationToken) { + if (documentationComment is null) + return ""; + // TODO: Consider unifying code to extract text from an Xml Documentation Comment (https://github.com/dotnet/roslyn/issues/2290) var summaryElement = documentationComment.ChildNodes().OfType() @@ -187,6 +187,6 @@ private static bool HasLeadingWhitespace(string tokenText) private static bool HasTrailingWhitespace(string tokenText) => tokenText.Length > 0 && char.IsWhiteSpace(tokenText[^1]); - public string GetBannerText(SyntaxNode documentationCommentTriviaSyntax, int maxBannerLength, CancellationToken cancellationToken) - => GetBannerText((TDocumentationCommentTriviaSyntax)documentationCommentTriviaSyntax, maxBannerLength, cancellationToken); + public string GetBannerText(SyntaxNode? documentationCommentTriviaSyntax, int maxBannerLength, CancellationToken cancellationToken) + => GetBannerText((TDocumentationCommentTriviaSyntax?)documentationCommentTriviaSyntax, maxBannerLength, cancellationToken); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/AbstractSyntaxFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/AbstractSyntaxFacts.cs new file mode 100644 index 0000000000000..4b5bbc83d00ee --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/AbstractSyntaxFacts.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 Microsoft.CodeAnalysis.PooledObjects; + +namespace Microsoft.CodeAnalysis.LanguageService; + +internal abstract class AbstractSyntaxFacts +{ + public void AddTopLevelAndMethodLevelMembers(SyntaxNode? root, ArrayBuilder result) + => AppendMembers(root, result, topLevel: true, methodLevel: true); + + public void AddTopLevelMembers(SyntaxNode? root, ArrayBuilder result) + => AppendMembers(root, result, topLevel: true, methodLevel: false); + + public void AddMethodLevelMembers(SyntaxNode? root, ArrayBuilder result) + => AppendMembers(root, result, topLevel: false, methodLevel: true); + + protected abstract void AppendMembers(SyntaxNode? node, ArrayBuilder list, bool topLevel, bool methodLevel); +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ExternalSourceInfo.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ExternalSourceInfo.cs index d24d9ae046f56..204524d138621 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ExternalSourceInfo.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ExternalSourceInfo.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.LanguageService; internal readonly struct ExternalSourceInfo(int? startLine, bool ends) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/IDocumentationCommentService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/IDocumentationCommentService.cs index d00e6e8acd562..0d6ea43f0d990 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/IDocumentationCommentService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/IDocumentationCommentService.cs @@ -2,13 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Threading; namespace Microsoft.CodeAnalysis.LanguageService; internal interface IDocumentationCommentService { - string GetBannerText(SyntaxNode documentationCommentTriviaSyntax, int bannerLength, CancellationToken cancellationToken); + string GetBannerText(SyntaxNode? documentationCommentTriviaSyntax, int bannerLength, CancellationToken cancellationToken); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxFacts.cs index e0abf008de631..124f3fc69230e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxFacts.cs @@ -7,6 +7,7 @@ using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Threading; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.LanguageService; @@ -410,13 +411,14 @@ void GetPartsOfTupleExpression(SyntaxNode node, SyntaxNode? ConvertToSingleLine(SyntaxNode? node, bool useElasticTrivia = false); // Violation. This is a feature level API. - PooledObject> GetTopLevelAndMethodLevelMembers(SyntaxNode? root); + void AddTopLevelAndMethodLevelMembers(SyntaxNode? root, ArrayBuilder result); // Violation. This is a feature level API. - PooledObject> GetMethodLevelMembers(SyntaxNode? root); + void AddTopLevelMembers(SyntaxNode? root, ArrayBuilder result); + // Violation. This is a feature level API. + void AddMethodLevelMembers(SyntaxNode? root, ArrayBuilder result); + SyntaxList GetMembersOfTypeDeclaration(SyntaxNode typeDeclaration); - // Violation. This is a feature level API. - bool ContainsInMemberBody([NotNullWhen(true)] SyntaxNode? node, TextSpan span); // Violation. This is a feature level API. TextSpan GetInactiveRegionSpanAroundPosition(SyntaxTree tree, int position, CancellationToken cancellationToken); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxKinds.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxKinds.cs index 72a9316a37c15..71cdf02df8537 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxKinds.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxKinds.cs @@ -56,6 +56,7 @@ internal interface ISyntaxKinds int? GlobalStatement { get; } int IfKeyword { get; } int NewKeyword { get; } + int PartialKeyword { get; } int TrueKeyword { get; } int UsingKeyword { get; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/ISimplification.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/ISimplification.cs index 22d9d03149504..347476a795392 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/ISimplification.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/ISimplification.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 Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Simplification; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.AnonymousTypeSymbolKey.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.AnonymousTypeSymbolKey.cs index 53b771db7aadd..b108155317187 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.AnonymousTypeSymbolKey.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.AnonymousTypeSymbolKey.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Immutable; using System.Diagnostics; using System.Linq; @@ -21,7 +20,7 @@ public sealed override void Create(INamedTypeSymbol symbol, SymbolKeyWriter visi var properties = symbol.GetMembers().OfType().ToImmutableArray(); var propertyTypes = properties.SelectAsArray(p => p.Type); - var propertyNames = properties.SelectAsArray(p => p.Name); + var propertyNames = properties.SelectAsArray(p => (string?)p.Name); var propertyIsReadOnly = properties.SelectAsArray(p => p.SetMethod == null); var propertyLocations = properties.SelectAsArray(p => p.Locations.FirstOrDefault()); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.BodyLevelSymbolKey.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.BodyLevelSymbolKey.cs index 80aa37a6a9439..9f16312007ddb 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.BodyLevelSymbolKey.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.BodyLevelSymbolKey.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; @@ -17,12 +16,12 @@ internal partial struct SymbolKey { private static class BodyLevelSymbolKey { - public static ImmutableArray GetBodyLevelSourceLocations(ISymbol symbol, CancellationToken cancellationToken) + public static ImmutableArray GetBodyLevelSourceLocations(ISymbol symbol, CancellationToken cancellationToken) { Contract.ThrowIfFalse(IsBodyLevelSymbol(symbol)); Contract.ThrowIfTrue(symbol.DeclaringSyntaxReferences.IsEmpty && symbol.Locations.IsEmpty); - using var _ = ArrayBuilder.GetInstance(out var result); + using var _ = ArrayBuilder.GetInstance(out var result); foreach (var location in symbol.Locations) { @@ -63,7 +62,7 @@ public static void Create(ISymbol symbol, SymbolKeyWriter visitor) var locations = GetBodyLevelSourceLocations(symbol, cancellationToken); - Contract.ThrowIfFalse(locations.All(loc => loc.IsInSource)); + Contract.ThrowIfFalse(locations.All(loc => loc != null && loc.IsInSource)); visitor.WriteLocationArray(locations.Distinct()); // and the containingSymbol/ordinal for resilience @@ -75,7 +74,7 @@ public static void Create(ISymbol symbol, SymbolKeyWriter visitor) int GetOrdinal() { - var syntaxTree = locations[0].SourceTree; + var syntaxTree = locations[0]!.SourceTree; var compilation = ((ISourceAssemblySymbol)symbol.ContainingAssembly).Compilation; // See if we can find an appropriate container for this local and attempt to find this local's index diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.BuiltinOperatorSymbolKey.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.BuiltinOperatorSymbolKey.cs index c4ff59c58d610..d2098901818c7 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.BuiltinOperatorSymbolKey.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.BuiltinOperatorSymbolKey.cs @@ -3,8 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Diagnostics; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.ErrorTypeSymbolKey.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.ErrorTypeSymbolKey.cs index 319e43c9e32e0..3eba6c3e4e83a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.ErrorTypeSymbolKey.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.ErrorTypeSymbolKey.cs @@ -4,7 +4,6 @@ using System.Collections.Immutable; using Microsoft.CodeAnalysis.PooledObjects; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis; @@ -50,9 +49,9 @@ public sealed override void Create(INamedTypeSymbol symbol, SymbolKeyWriter visi /// For a symbol like System.Collections.Generic.IEnumerable, this would produce "Generic", /// "Collections", "System" /// - private static ImmutableArray GetContainingNamespaceNamesInReverse(INamespaceSymbol namespaceSymbol) + private static ImmutableArray GetContainingNamespaceNamesInReverse(INamespaceSymbol namespaceSymbol) { - using var _ = ArrayBuilder.GetInstance(out var builder); + using var _ = ArrayBuilder.GetInstance(out var builder); while (namespaceSymbol != null && namespaceSymbol.Name != "") { builder.Add(namespaceSymbol.Name); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.EventSymbolKey.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.EventSymbolKey.cs index a000d15c9925d..ec572d6ebba0b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.EventSymbolKey.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.EventSymbolKey.cs @@ -14,6 +14,7 @@ public sealed override void Create(IEventSymbol symbol, SymbolKeyWriter visitor) { visitor.WriteString(symbol.MetadataName); visitor.WriteSymbolKey(symbol.ContainingType); + visitor.WriteBoolean(symbol.PartialDefinitionPart is not null); } protected sealed override SymbolKeyResolution Resolve( @@ -21,6 +22,7 @@ protected sealed override SymbolKeyResolution Resolve( { var metadataName = reader.ReadString(); var containingTypeResolution = reader.ReadSymbolKey(contextualSymbol?.ContainingType, out var containingTypeFailureReason); + var isPartialImplementationPart = reader.ReadBoolean(); if (containingTypeFailureReason != null) { @@ -28,8 +30,18 @@ protected sealed override SymbolKeyResolution Resolve( return default; } - using var result = GetMembersOfNamedType(containingTypeResolution, metadataName); - return CreateResolution(result, $"({nameof(EventSymbolKey)} '{metadataName}' not found)", out failureReason); + using var events = GetMembersOfNamedType(containingTypeResolution, metadataName); + + if (isPartialImplementationPart) + { + for (var i = 0; i < events.Builder.Count; i++) + { + var candidate = events.Builder[i]; + events.Builder[i] = candidate.PartialImplementationPart ?? candidate; + } + } + + return CreateResolution(events, $"({nameof(EventSymbolKey)} '{metadataName}' not found)", out failureReason); } } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.FunctionPointerTypeSymbolKey.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.FunctionPointerTypeSymbolKey.cs index 3269109e31629..e63eaf56e773c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.FunctionPointerTypeSymbolKey.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.FunctionPointerTypeSymbolKey.cs @@ -4,8 +4,6 @@ using System.Collections.Immutable; using System.Reflection.Metadata; -using System.Runtime.CompilerServices; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.MethodSymbolKey.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.MethodSymbolKey.cs index 785458b4296dc..6b3690c569ec4 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.MethodSymbolKey.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.MethodSymbolKey.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.NamedTypeSymbolKey.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.NamedTypeSymbolKey.cs index e6391311b7bc2..6bca171a77198 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.NamedTypeSymbolKey.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.NamedTypeSymbolKey.cs @@ -2,9 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Immutable; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis; @@ -19,21 +17,16 @@ public sealed override void Create(INamedTypeSymbol symbol, SymbolKeyWriter visi visitor.WriteSymbolKey(symbol.ContainingSymbol); visitor.WriteString(symbol.Name); visitor.WriteInteger(symbol.Arity); - visitor.WriteString(symbol.IsFileLocal - ? symbol.DeclaringSyntaxReferences[0].SyntaxTree.FilePath - : null); + // Include the metadata name for extensions. We need this to uniquely find it when resolving. + visitor.WriteString(symbol.IsExtension ? symbol.MetadataName : null); + // Include the file path for 'file-local' types. We need this to uniquely find it when resolving. + visitor.WriteString(symbol.IsFileLocal ? symbol.DeclaringSyntaxReferences[0].SyntaxTree.FilePath : null); visitor.WriteBoolean(symbol.IsUnboundGenericType); visitor.WriteBoolean(symbol.IsNativeIntegerType); visitor.WriteBoolean(symbol.SpecialType == SpecialType.System_IntPtr); - if (!symbol.Equals(symbol.ConstructedFrom) && !symbol.IsUnboundGenericType) - { - visitor.WriteSymbolKeyArray(symbol.TypeArguments); - } - else - { - visitor.WriteSymbolKeyArray(ImmutableArray.Empty); - } + visitor.WriteSymbolKeyArray( + symbol.Equals(symbol.ConstructedFrom) || symbol.IsUnboundGenericType ? [] : symbol.TypeArguments); } protected sealed override SymbolKeyResolution Resolve( @@ -42,6 +35,7 @@ protected sealed override SymbolKeyResolution Resolve( var containingSymbolResolution = reader.ReadSymbolKey(contextualSymbol?.ContainingSymbol, out var containingSymbolFailureReason); var name = reader.ReadRequiredString(); var arity = reader.ReadInteger(); + var extensionMetadataName = reader.ReadString(); var filePath = reader.ReadString(); var isUnboundGenericType = reader.ReadBoolean(); var isNativeIntegerType = reader.ReadBoolean(); @@ -73,7 +67,8 @@ protected sealed override SymbolKeyResolution Resolve( var normalResolution = ResolveNormalNamedType( containingSymbolResolution, containingSymbolFailureReason, - name, arity, filePath, isUnboundGenericType, typeArgumentsArray, + name, extensionMetadataName, arity, filePath, + isUnboundGenericType, typeArgumentsArray, out failureReason); if (normalResolution.SymbolCount > 0) @@ -140,10 +135,11 @@ private static SymbolKeyResolution ResolveNormalNamedType( SymbolKeyResolution containingSymbolResolution, string? containingSymbolFailureReason, string name, + string? extensionMetadataName, int arity, string? filePath, bool isUnboundGenericType, - ITypeSymbol[] typeArgumentsArray, + ITypeSymbol[] typeArguments, out string? failureReason) { if (containingSymbolFailureReason != null) @@ -154,43 +150,46 @@ private static SymbolKeyResolution ResolveNormalNamedType( using var result = PooledArrayBuilder.GetInstance(); foreach (var nsOrType in containingSymbolResolution.OfType()) - { - Resolve( - result, nsOrType, name, arity, filePath, - isUnboundGenericType, typeArgumentsArray); - } + Resolve(nsOrType, result); return CreateResolution(result, $"({nameof(NamedTypeSymbolKey)} failed)", out failureReason); - } - private static void Resolve( - PooledArrayBuilder result, - INamespaceOrTypeSymbol container, - string name, - int arity, - string? filePath, - bool isUnboundGenericType, - ITypeSymbol[] typeArguments) - { - foreach (var type in container.GetTypeMembers(name, arity)) + void Resolve( + INamespaceOrTypeSymbol container, + PooledArrayBuilder result) { - // if this is a file-local type, then only resolve to a file-local type from this same file - if (filePath != null) + if (extensionMetadataName != null) { - if (!type.IsFileLocal || - // note: if we found 'IsFile' returned true, we can assume DeclaringSyntaxReferences is non-empty. - type.DeclaringSyntaxReferences[0].SyntaxTree.FilePath != filePath) + // Unfortunately, no fast index from metadata name to type, so we have to iterate all nested types. + foreach (var type in container.GetTypeMembers()) { - continue; + if (type.MetadataName == extensionMetadataName) + result.AddIfNotNull(Construct(type, isUnboundGenericType, typeArguments)); } } - else if (type.IsFileLocal) + else { - // since this key lacks a file path it can't match against a file-local type - continue; + foreach (var type in container.GetTypeMembers(name, arity)) + { + // if this is a file-local type, then only resolve to a file-local type from this same file + if (filePath != null) + { + if (!type.IsFileLocal || + // note: if we found 'IsFile' returned true, we can assume DeclaringSyntaxReferences is non-empty. + type.DeclaringSyntaxReferences[0].SyntaxTree.FilePath != filePath) + { + continue; + } + } + else if (type.IsFileLocal) + { + // since this key lacks a file path it can't match against a file-local type + continue; + } + + result.AddIfNotNull(Construct(type, isUnboundGenericType, typeArguments)); + } } - - result.AddIfNotNull(Construct(type, isUnboundGenericType, typeArguments)); } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.NamespaceSymbolKey.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.NamespaceSymbolKey.cs index c9126832e26e9..7b72e2f5ddb21 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.NamespaceSymbolKey.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.NamespaceSymbolKey.cs @@ -4,7 +4,6 @@ using System; using System.Diagnostics; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.ParameterSymbolKey.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.ParameterSymbolKey.cs index 77417acc4ecc2..56d5d72914c2d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.ParameterSymbolKey.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.ParameterSymbolKey.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; -using System.Diagnostics; namespace Microsoft.CodeAnalysis; @@ -69,6 +68,9 @@ protected sealed override SymbolKeyResolution Resolve( Resolve(result, reader, metadataName, ordinal, delegateInvoke.Parameters); } + break; + case INamedTypeSymbol { IsExtension: true, ExtensionParameter: { } extensionParameter }: + Resolve(result, reader, metadataName, ordinal, [extensionParameter]); break; } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.SymbolKeyWriter.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.SymbolKeyWriter.cs index f94870bd8cdc3..92c7c17a25576 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.SymbolKeyWriter.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.SymbolKeyWriter.cs @@ -11,7 +11,6 @@ using System.Threading; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis; @@ -290,12 +289,10 @@ internal void WriteBooleanArray(ImmutableArray array) // annotating WriteStringArray and WriteLocationArray as allowing null elements // then causes issues where we can't pass ImmutableArrays of non-null elements -#nullable disable - - internal void WriteStringArray(ImmutableArray strings) + internal void WriteStringArray(ImmutableArray strings) => WriteArray(strings, _writeString); - internal void WriteLocationArray(ImmutableArray array) + internal void WriteLocationArray(ImmutableArray array) => WriteArray(array, _writeLocation); #nullable enable diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.TupleTypeSymbolKey.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.TupleTypeSymbolKey.cs index bdef24ce5c2b9..10114d6fcccbf 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.TupleTypeSymbolKey.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.TupleTypeSymbolKey.cs @@ -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. -using System; using System.Linq; using System.Collections.Immutable; using System.Diagnostics; using Microsoft.CodeAnalysis.PooledObjects; -using System.Runtime.CompilerServices; namespace Microsoft.CodeAnalysis; @@ -24,7 +22,7 @@ public sealed override void Create(INamedTypeSymbol symbol, SymbolKeyWriter visi var isError = symbol.TupleUnderlyingType!.TypeKind == TypeKind.Error; using var _1 = ArrayBuilder.GetInstance(out var friendlyNames); - using var _2 = ArrayBuilder.GetInstance(out var locations); + using var _2 = ArrayBuilder.GetInstance(out var locations); foreach (var element in symbol.TupleElements) { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.TypeParameterOrdinalSymbolKey.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.TypeParameterOrdinalSymbolKey.cs index ce64540557095..86ae1340865cf 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.TypeParameterOrdinalSymbolKey.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.TypeParameterOrdinalSymbolKey.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Roslyn.Utilities; - namespace Microsoft.CodeAnalysis; internal partial struct SymbolKey diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.cs index d993f44ba3e89..551ee7a466d5b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.Serialization; using System.Threading; @@ -149,13 +148,14 @@ public static bool CanCreate(ISymbol symbol, CancellationToken cancellationToken if (IsBodyLevelSymbol(symbol)) { var locations = BodyLevelSymbolKey.GetBodyLevelSourceLocations(symbol, cancellationToken); - if (locations.Length == 0) + var firstNonNull = locations.FirstOrDefault(l => l != null); + if (firstNonNull is null) return false; // Ensure that the tree we're looking at is actually in this compilation. It may not be in the // compilation in the case of work done with a speculative model. var compilation = ((ISourceAssemblySymbol)symbol.ContainingAssembly).Compilation; - return compilation.SyntaxTrees.Contains(locations.First().SourceTree); + return compilation.SyntaxTrees.Contains(firstNonNull.SourceTree); } return true; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/AliasSymbolCache.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/AliasSymbolCache.cs index db5673ac2f6ed..bd8b7f0682752 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/AliasSymbolCache.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/AliasSymbolCache.cs @@ -2,11 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/AsyncLazy`1.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/AsyncLazy`1.cs index d1443088d9025..abf853d959a8c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/AsyncLazy`1.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/AsyncLazy`1.cs @@ -1,13 +1,14 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. - using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.ErrorReporting; +using Microsoft.CodeAnalysis.Threading; namespace Roslyn.Utilities; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/CommonFormattingHelpers.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/CommonFormattingHelpers.cs index aa20832c3047f..04dd66c8b5ca2 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/CommonFormattingHelpers.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/CommonFormattingHelpers.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.Formatting.Rules; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Shared.Utilities; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/EnumerableConditionalWeakTable.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/EnumerableConditionalWeakTable.cs index 07023b7d5670a..b4f2fca4d6ae8 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/EnumerableConditionalWeakTable.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/EnumerableConditionalWeakTable.cs @@ -8,6 +8,7 @@ using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; +using Microsoft.CodeAnalysis; namespace Roslyn.Utilities; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/EventMap.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/EventMap.cs index 35ca9ae0fc338..c7e66cb79fe3e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/EventMap.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/EventMap.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.ErrorReporting; namespace Roslyn.Utilities; @@ -155,26 +156,21 @@ public readonly bool HasHandlers public readonly void RaiseEvent(Action invoker, TArg arg) { - // The try/catch here is to find additional telemetry for https://devdiv.visualstudio.com/DevDiv/_queries/query/71ee8553-7220-4b2a-98cf-20edab701fd1/. - // We've realized there's a problem with our eventing, where if an exception is encountered while calling into subscribers to Workspace events, - // we won't notify all of the callers. The expectation is such an exception would be thrown to the SafeStartNew in the workspace's event queue that - // will raise that as a fatal exception, but OperationCancelledExceptions might be able to propagate through and fault the task we are using in the - // chain. I'm choosing to use ReportWithoutCrashAndPropagate, because if our theory here is correct, it seems the first exception isn't actually - // causing crashes, and so if it turns out this is a very common situation I don't want to make a often-benign situation fatal. - try + if (this.HasHandlers) { - if (this.HasHandlers) + foreach (var registry in _registries) { - foreach (var registry in _registries) + try { registry.Invoke(invoker, arg); } + catch (Exception e) when (FatalError.ReportAndCatch(e)) + { + // Catch the exception and continue as this an event handler and propagating the exception would prevent + // other handlers from executing + } } } - catch (Exception e) when (FatalError.ReportAndPropagate(e)) - { - throw ExceptionUtilities.Unreachable(); - } } } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/FixedSizeArrayBuilder.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/FixedSizeArrayBuilder.cs index fa5dbe2bd226d..7ed172ae159a9 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/FixedSizeArrayBuilder.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/FixedSizeArrayBuilder.cs @@ -6,8 +6,8 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Runtime.InteropServices; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.PooledObjects; -using Roslyn.Utilities; /// /// A bare-bones array builder, focused on the case of producing s where the final array diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/NonReentrantLock.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/NonReentrantLock.cs index 9d331024040b9..db1dfe03439a7 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/NonReentrantLock.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/NonReentrantLock.cs @@ -5,6 +5,7 @@ using System; using System.Diagnostics; using System.Threading; +using Microsoft.CodeAnalysis; #if WORKSPACE using Microsoft.CodeAnalysis.Internal.Log; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/PathMetadataUtilities.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/PathMetadataUtilities.cs index 5754d73ddfbc0..723d3b6ee04ef 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/PathMetadataUtilities.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/PathMetadataUtilities.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics; using System.Linq; using Microsoft.CodeAnalysis.LanguageService; using Roslyn.Utilities; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ProducerConsumer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ProducerConsumer.cs index a4b3e0854ad7b..718921282f409 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ProducerConsumer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ProducerConsumer.cs @@ -10,7 +10,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; +using Microsoft.CodeAnalysis.Threading; namespace Microsoft.CodeAnalysis.Shared.Utilities; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ReferenceCountedDisposable.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ReferenceCountedDisposable.cs index 11eaafe676ce9..e1d76bd0d909d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ReferenceCountedDisposable.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ReferenceCountedDisposable.cs @@ -4,8 +4,8 @@ using System; using System.Diagnostics.CodeAnalysis; -using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis; namespace Roslyn.Utilities; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ReferenceCountedDisposableCache.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ReferenceCountedDisposableCache.cs index e8d75f5e52533..69a62f4531a1b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ReferenceCountedDisposableCache.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ReferenceCountedDisposableCache.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; -using System.Threading.Tasks; namespace Roslyn.Utilities; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/RoslynParallel.NetFramework.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/RoslynParallel.NetFramework.cs index dd626976d8108..6f12759f5ce86 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/RoslynParallel.NetFramework.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/RoslynParallel.NetFramework.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. -// - #if !NET #pragma warning disable CA1068 // CancellationToken parameters must come last @@ -12,6 +10,8 @@ #pragma warning disable IDE2004 // Blank line not allowed after constructor initializer colon #pragma warning disable VSTHRD200 // Use "Async" suffix for async methods +#nullable disable + // Ported from // https://github.com/dotnet/runtime/blob/main/src/libraries/System.Threading.Tasks.Parallel/src/System/Threading/Tasks/Parallel.ForEachAsync.cs // With only changes to make the code work on NetFx. Where changes have been made, the original code is kept around in @@ -22,6 +22,7 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Shared.Utilities; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SpecializedTasks.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SpecializedTasks.cs index f9400d9c0065e..47b79e3624176 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SpecializedTasks.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SpecializedTasks.cs @@ -7,10 +7,8 @@ using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Linq; -using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.PooledObjects; namespace Roslyn.Utilities; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.EquivalenceVisitor.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.EquivalenceVisitor.cs index 9c664d0c861c0..b86f86f550442 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.EquivalenceVisitor.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.EquivalenceVisitor.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; @@ -599,8 +598,8 @@ private bool PropertiesAreEquivalent(IPropertySymbol x, IPropertySymbol y, Dicti x.IsIndexer == y.IsIndexer && x.MetadataName == y.MetadataName && x.Parameters.Length == y.Parameters.Length && - IsPartialMethodDefinitionPart(x) == IsPartialMethodDefinitionPart(y) && - IsPartialMethodImplementationPart(x) == IsPartialMethodImplementationPart(y) && + IsPartialPropertyDefinitionPart(x) == IsPartialPropertyDefinitionPart(y) && + IsPartialPropertyImplementationPart(x) == IsPartialPropertyImplementationPart(y) && ParametersAreEquivalent(x.Parameters, y.Parameters, equivalentTypesWithDifferingAssemblies) && AreEquivalent(x.ContainingSymbol, y.ContainingSymbol, equivalentTypesWithDifferingAssemblies); } @@ -609,6 +608,8 @@ private bool EventsAreEquivalent(IEventSymbol x, IEventSymbol y, Dictionary symbol.PartialDefinitionPart != null; - private static bool IsPartialMethodDefinitionPart(IPropertySymbol symbol) + private static bool IsPartialPropertyDefinitionPart(IPropertySymbol symbol) => symbol.PartialImplementationPart != null; - private static bool IsPartialMethodImplementationPart(IPropertySymbol symbol) + private static bool IsPartialPropertyImplementationPart(IPropertySymbol symbol) + => symbol.PartialDefinitionPart != null; + + private static bool IsPartialEventDefinitionPart(IEventSymbol symbol) + => symbol.PartialImplementationPart != null; + + private static bool IsPartialEventImplementationPart(IEventSymbol symbol) => symbol.PartialDefinitionPart != null; private static TypeKind GetTypeKind(INamedTypeSymbol x) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/TaskExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/TaskExtensions.cs index 4f6c229cbcd91..220618bc52d7a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/TaskExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/TaskExtensions.cs @@ -9,6 +9,7 @@ using System.Runtime.ExceptionServices; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.ErrorReporting; namespace Roslyn.Utilities; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ValueTaskExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ValueTaskExtensions.cs index 443c836fddc80..e076ea250d585 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ValueTaskExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ValueTaskExtensions.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Threading.Tasks; +using Microsoft.CodeAnalysis; namespace Roslyn.Utilities; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.cs.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.cs.xlf index e0c34f269a931..1d89ff95bf069 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.cs.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.cs.xlf @@ -4,12 +4,12 @@ A language name cannot be specified for this option. - A language name cannot be specified for this option. + Pro tuto možnost se nesmí zadat název jazyka. A language name must be specified for this option. - A language name must be specified for this option. + Pro tuto možnost se musí zadat název jazyka. @@ -64,7 +64,7 @@ Indentation and spacing - Indentation and spacing + Odsazení a mezery @@ -194,7 +194,7 @@ Stream must support read and seek operations. - Stream must support read and seek operations. + Stream musí podporovat operace read a seek. @@ -254,7 +254,7 @@ Value too large to be represented as a 30 bit unsigned integer. - Value too large to be represented as a 30 bit unsigned integer. + Hodnota je moc velká, než aby se dala vyjádřit jako 30bitové nepodepsané celé číslo. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.de.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.de.xlf index 32c442eb17157..9cdbf4c6042fa 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.de.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.de.xlf @@ -4,12 +4,12 @@ A language name cannot be specified for this option. - A language name cannot be specified for this option. + Für diese Option kann kein Sprachenname angegeben werden. A language name must be specified for this option. - A language name must be specified for this option. + Für diese Option muss ein Sprachenname angegeben werden. @@ -64,7 +64,7 @@ Indentation and spacing - Indentation and spacing + Einzüge und Abstände @@ -194,7 +194,7 @@ Stream must support read and seek operations. - Stream must support read and seek operations. + Stream muss Lese- und Suchvorgänge unterstützen. @@ -254,7 +254,7 @@ Value too large to be represented as a 30 bit unsigned integer. - Value too large to be represented as a 30 bit unsigned integer. + Der Wert ist zu groß, um als ganze 30-Bit-Zahl ohne Vorzeichen dargestellt zu werden. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.es.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.es.xlf index 6c59b85fa5a2f..d57fc5025f134 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.es.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.es.xlf @@ -4,12 +4,12 @@ A language name cannot be specified for this option. - A language name cannot be specified for this option. + No se puede especificar ningún nombre de idioma para esta opción. A language name must be specified for this option. - A language name must be specified for this option. + Se debe especificar un nombre de lenguaje para esta opción. @@ -64,7 +64,7 @@ Indentation and spacing - Indentation and spacing + Sangría y espaciado @@ -194,7 +194,7 @@ Stream must support read and seek operations. - Stream must support read and seek operations. + La secuencia debe admitir las operaciones de lectura y búsqueda. @@ -254,7 +254,7 @@ Value too large to be represented as a 30 bit unsigned integer. - Value too large to be represented as a 30 bit unsigned integer. + Valor demasiado largo para representarse como entero sin signo de 30 bits. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.fr.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.fr.xlf index b090ead34d63b..5b7fc9ca72877 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.fr.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.fr.xlf @@ -4,12 +4,12 @@ A language name cannot be specified for this option. - A language name cannot be specified for this option. + Impossible de spécifier un nom de langage pour cette option. A language name must be specified for this option. - A language name must be specified for this option. + Un nom de langage doit être spécifié pour cette option. @@ -64,7 +64,7 @@ Indentation and spacing - Indentation and spacing + Indentation et espacement @@ -194,7 +194,7 @@ Stream must support read and seek operations. - Stream must support read and seek operations. + Le flux doit prendre en charge les opérations de lecture et de recherche. @@ -254,7 +254,7 @@ Value too large to be represented as a 30 bit unsigned integer. - Value too large to be represented as a 30 bit unsigned integer. + La valeur est trop grande pour être représentée comme un entier non signé 30 bits. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.it.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.it.xlf index bc258c2dbdfbc..ba54489b8e10c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.it.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.it.xlf @@ -4,12 +4,12 @@ A language name cannot be specified for this option. - A language name cannot be specified for this option. + Non è possibile specificare un nome di linguaggio per questa opzione. A language name must be specified for this option. - A language name must be specified for this option. + È necessario specificare un nome di linguaggio per questa opzione. @@ -64,7 +64,7 @@ Indentation and spacing - Indentation and spacing + Rientro e spaziatura @@ -194,7 +194,7 @@ Stream must support read and seek operations. - Stream must support read and seek operations. + Il flusso deve supportare operazioni di lettura e ricerca. @@ -254,7 +254,7 @@ Value too large to be represented as a 30 bit unsigned integer. - Value too large to be represented as a 30 bit unsigned integer. + Il valore è troppo grande per essere rappresentato come intero senza segno a 30 bit. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ja.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ja.xlf index 88cced8049903..f2c575d381e0d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ja.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ja.xlf @@ -4,12 +4,12 @@ A language name cannot be specified for this option. - A language name cannot be specified for this option. + 言語名は、このオプションでは指定できません。 A language name must be specified for this option. - A language name must be specified for this option. + このオプションの言語名を指定する必要があります。 @@ -64,7 +64,7 @@ Indentation and spacing - Indentation and spacing + インデントと間隔 @@ -194,7 +194,7 @@ Stream must support read and seek operations. - Stream must support read and seek operations. + ストリームは、読み取りとシーク操作をサポートする必要があります。 @@ -254,7 +254,7 @@ Value too large to be represented as a 30 bit unsigned integer. - Value too large to be represented as a 30 bit unsigned integer. + 値が大きすぎるため、30 ビットの符号なし整数として表すことができません。 diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ko.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ko.xlf index 09bad15ba92c2..273065dff6187 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ko.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ko.xlf @@ -4,12 +4,12 @@ A language name cannot be specified for this option. - A language name cannot be specified for this option. + 이 옵션에 대한 언어 이름을 지정할 수 없습니다. A language name must be specified for this option. - A language name must be specified for this option. + 이 옵션에 대한 언어 이름을 지정해야 합니다. @@ -64,7 +64,7 @@ Indentation and spacing - Indentation and spacing + 들여쓰기 및 간격 @@ -194,7 +194,7 @@ Stream must support read and seek operations. - Stream must support read and seek operations. + 스트림은 읽기 및 찾기 작업을 지원해야 합니다. @@ -254,7 +254,7 @@ Value too large to be represented as a 30 bit unsigned integer. - Value too large to be represented as a 30 bit unsigned integer. + 값이 너무 커서 30비트 정수로 표시할 수 없습니다. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.pl.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.pl.xlf index 6fc6dd0fe8dc8..7c6ce27485e29 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.pl.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.pl.xlf @@ -4,12 +4,12 @@ A language name cannot be specified for this option. - A language name cannot be specified for this option. + Nie można określić nazwy języka dla tej opcji. A language name must be specified for this option. - A language name must be specified for this option. + Nazwa języka musi zostać określona dla tej opcji. @@ -64,7 +64,7 @@ Indentation and spacing - Indentation and spacing + Wcięcia i odstępy @@ -194,7 +194,7 @@ Stream must support read and seek operations. - Stream must support read and seek operations. + Strumień musi obsługiwać operacje odczytu i wyszukiwania. @@ -254,7 +254,7 @@ Value too large to be represented as a 30 bit unsigned integer. - Value too large to be represented as a 30 bit unsigned integer. + Wartość jest zbyt duża, dlatego nie może być reprezentowana jako 30-bitowa liczba całkowita bez znaku. 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 e6450f68881b0..d5c2f8a1f90fa 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.pt-BR.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.pt-BR.xlf @@ -4,12 +4,12 @@ A language name cannot be specified for this option. - A language name cannot be specified for this option. + Um nome de idioma não pode ser especificado para essa opção. A language name must be specified for this option. - A language name must be specified for this option. + Um nome de idioma deve ser especificado para esta opção. @@ -64,7 +64,7 @@ Indentation and spacing - Indentation and spacing + Recuo e espaçamento @@ -194,7 +194,7 @@ Stream must support read and seek operations. - Stream must support read and seek operations. + O fluxo deve fornecer suporte a operações de leitura e busca. @@ -254,7 +254,7 @@ Value too large to be represented as a 30 bit unsigned integer. - Value too large to be represented as a 30 bit unsigned integer. + Valor muito grande para ser representado como um inteiro não assinado de 30 bits. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ru.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ru.xlf index 6bf75cf7423b5..92d4626d2b82f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ru.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ru.xlf @@ -4,12 +4,12 @@ A language name cannot be specified for this option. - A language name cannot be specified for this option. + Для данного параметра невозможно указать имя языка. A language name must be specified for this option. - A language name must be specified for this option. + Для данного параметра необходимо указать имя языка. @@ -64,7 +64,7 @@ Indentation and spacing - Indentation and spacing + Отступы и интервалы @@ -194,7 +194,7 @@ Stream must support read and seek operations. - Stream must support read and seek operations. + Поток должен поддерживать операции чтения и поиска. @@ -254,7 +254,7 @@ Value too large to be represented as a 30 bit unsigned integer. - Value too large to be represented as a 30 bit unsigned integer. + Слишком большое значение для представления в виде 30-разрядного целого числа без знака. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.tr.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.tr.xlf index 2108bb3650547..6a64eb620fb74 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.tr.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.tr.xlf @@ -4,12 +4,12 @@ A language name cannot be specified for this option. - A language name cannot be specified for this option. + Bu seçenek için bir dil adı belirtilemiyor. A language name must be specified for this option. - A language name must be specified for this option. + Bu seçenek için bir dil adı belirtilmelidir. @@ -64,7 +64,7 @@ Indentation and spacing - Indentation and spacing + Girinti ve aralığı @@ -194,7 +194,7 @@ Stream must support read and seek operations. - Stream must support read and seek operations. + Akış okuma ve arama işlemlerini desteklemelidir. @@ -254,7 +254,7 @@ Value too large to be represented as a 30 bit unsigned integer. - Value too large to be represented as a 30 bit unsigned integer. + Değer, 30 bit işaretsiz tamsayı olarak temsil edilemeyecek kadar büyük. 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 a6ff47683510f..4cf728c76c8b4 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.zh-Hans.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.zh-Hans.xlf @@ -4,12 +4,12 @@ A language name cannot be specified for this option. - A language name cannot be specified for this option. + 无法为此选项指定语言名称。 A language name must be specified for this option. - A language name must be specified for this option. + 必须为此选项指定语言名称。 @@ -64,7 +64,7 @@ Indentation and spacing - Indentation and spacing + 缩进和间距 @@ -194,7 +194,7 @@ Stream must support read and seek operations. - Stream must support read and seek operations. + 流必须支持读取和搜寻操作。 @@ -254,7 +254,7 @@ Value too large to be represented as a 30 bit unsigned integer. - Value too large to be represented as a 30 bit unsigned integer. + 值太大,无法表示为 30 位无符号整数。 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 ce23e63d317f9..9eee8170ccdfb 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.zh-Hant.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.zh-Hant.xlf @@ -4,12 +4,12 @@ A language name cannot be specified for this option. - A language name cannot be specified for this option. + 無法指定此選項的語言名稱。 A language name must be specified for this option. - A language name must be specified for this option. + 必須指定此選項的語言名稱。 @@ -64,7 +64,7 @@ Indentation and spacing - Indentation and spacing + 縮排和間距 @@ -194,7 +194,7 @@ Stream must support read and seek operations. - Stream must support read and seek operations. + 資料流必須支援讀取及搜尋作業。 @@ -254,7 +254,7 @@ Value too large to be represented as a 30 bit unsigned integer. - Value too large to be represented as a 30 bit unsigned integer. + 值太大,無法呈現為 30 位元不帶正負號的整數。 diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SemanticFacts/VisualBasicSemanticFacts.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SemanticFacts/VisualBasicSemanticFacts.vb index 540dba1f7d0b4..31b8674d601df 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SemanticFacts/VisualBasicSemanticFacts.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SemanticFacts/VisualBasicSemanticFacts.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Collections.Immutable +Imports System.Diagnostics.CodeAnalysis Imports System.Runtime.InteropServices Imports System.Threading Imports Microsoft.CodeAnalysis @@ -328,6 +329,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return False End Function + Public Function TryGetPrimaryConstructor(typeSymbol As INamedTypeSymbol, ByRef primaryConstructor As IMethodSymbol) As Boolean Implements ISemanticFacts.TryGetPrimaryConstructor + ' VB does not support primary constructors + Return False + End Function + #If Not CODE_STYLE Then Public Function GetInterceptorSymbolAsync(document As Document, position As Integer, cancellationToken As CancellationToken) As Task(Of ISymbol) Implements ISemanticFacts.GetInterceptorSymbolAsync diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxFacts.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxFacts.vb index 0c464486a45f4..068b6b64f7976 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxFacts.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxFacts.vb @@ -21,15 +21,13 @@ Imports Microsoft.CodeAnalysis.Editing Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService Friend Class VisualBasicSyntaxFacts + Inherits AbstractSyntaxFacts Implements ISyntaxFacts Private Const DoesNotExistInVBErrorMessage = "This feature does not exist in VB" 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 @@ -836,76 +834,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService Return Nothing End Function - Public Function ContainsInMemberBody(node As SyntaxNode, span As TextSpan) As Boolean Implements ISyntaxFacts.ContainsInMemberBody - Dim method = TryCast(node, MethodBlockBaseSyntax) - If method IsNot Nothing Then - Return method.Statements.Count > 0 AndAlso ContainsExclusively(GetSyntaxListSpan(method.Statements), span) - End If - - Dim [event] = TryCast(node, EventBlockSyntax) - If [event] IsNot Nothing Then - Return [event].Accessors.Count > 0 AndAlso ContainsExclusively(GetSyntaxListSpan([event].Accessors), span) - End If - - Dim [property] = TryCast(node, PropertyBlockSyntax) - If [property] IsNot Nothing Then - Return [property].Accessors.Count > 0 AndAlso ContainsExclusively(GetSyntaxListSpan([property].Accessors), span) - End If - - Dim field = TryCast(node, FieldDeclarationSyntax) - If field IsNot Nothing Then - Return field.Declarators.Count > 0 AndAlso ContainsExclusively(GetSeparatedSyntaxListSpan(field.Declarators), span) - End If - - Dim [enum] = TryCast(node, EnumMemberDeclarationSyntax) - If [enum] IsNot Nothing Then - Return [enum].Initializer IsNot Nothing AndAlso ContainsExclusively([enum].Initializer.Span, span) - End If - - Dim propStatement = TryCast(node, PropertyStatementSyntax) - If propStatement IsNot Nothing Then - Return propStatement.Initializer IsNot Nothing AndAlso ContainsExclusively(propStatement.Initializer.Span, span) - End If - - Return False - End Function - - Private Shared Function ContainsExclusively(outerSpan As TextSpan, innerSpan As TextSpan) As Boolean - If innerSpan.IsEmpty Then - Return outerSpan.Contains(innerSpan.Start) - End If - - Return outerSpan.Contains(innerSpan) - End Function - - Private Shared Function GetSyntaxListSpan(Of T As SyntaxNode)(list As SyntaxList(Of T)) As TextSpan - Debug.Assert(list.Count > 0) - Return TextSpan.FromBounds(list.First.SpanStart, list.Last.Span.End) - End Function - - Private Shared Function GetSeparatedSyntaxListSpan(Of T As SyntaxNode)(list As SeparatedSyntaxList(Of T)) As TextSpan - Debug.Assert(list.Count > 0) - Return TextSpan.FromBounds(list.First.SpanStart, list.Last.Span.End) - End Function - - 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 pooledList - End Function - - 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 pooledList - End Function - Public Function GetMembersOfTypeDeclaration(typeDeclaration As SyntaxNode) As SyntaxList(Of SyntaxNode) Implements ISyntaxFacts.GetMembersOfTypeDeclaration Return DirectCast(typeDeclaration, TypeBlockSyntax).Members End Function @@ -1050,7 +978,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService End If End Sub - Private Sub AppendMembers(node As SyntaxNode, list As List(Of SyntaxNode), topLevel As Boolean, methodLevel As Boolean) + Protected Overrides Sub AppendMembers(node As SyntaxNode, list As ArrayBuilder(Of SyntaxNode), topLevel As Boolean, methodLevel As Boolean) Debug.Assert(topLevel OrElse methodLevel) For Each member In node.GetMembers() @@ -1998,6 +1926,18 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService Return DirectCast(node, LiteralExpressionSyntax).Token End Function + Private Sub ISyntaxFacts_AddTopLevelAndMethodLevelMembers(root As SyntaxNode, result As ArrayBuilder(Of SyntaxNode)) Implements ISyntaxFacts.AddTopLevelAndMethodLevelMembers + AddTopLevelAndMethodLevelMembers(root, result) + End Sub + + Private Sub ISyntaxFacts_AddTopLevelMembers(root As SyntaxNode, result As ArrayBuilder(Of SyntaxNode)) Implements ISyntaxFacts.AddTopLevelMembers + AddTopLevelMembers(root, result) + End Sub + + Private Sub ISyntaxFacts_AddMethodLevelMembers(root As SyntaxNode, result As ArrayBuilder(Of SyntaxNode)) Implements ISyntaxFacts.AddMethodLevelMembers + AddMethodLevelMembers(root, result) + End Sub + #End Region End Class diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxKinds.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxKinds.vb index 6921dc24cad4d..0641f531b5c81 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxKinds.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxKinds.vb @@ -73,6 +73,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService Public ReadOnly Property IfKeyword As Integer = SyntaxKind.IfKeyword Implements ISyntaxKinds.IfKeyword Public ReadOnly Property NewKeyword As Integer = SyntaxKind.NewKeyword Implements ISyntaxKinds.NewKeyword Public ReadOnly Property TrueKeyword As Integer = SyntaxKind.TrueKeyword Implements ISyntaxKinds.TrueKeyword + Public ReadOnly Property PartialKeyword As Integer = SyntaxKind.PartialKeyword Implements ISyntaxKinds.PartialKeyword Public ReadOnly Property UsingKeyword As Integer = SyntaxKind.UsingKeyword Implements ISyntaxKinds.UsingKeyword Public ReadOnly Property AliasQualifiedName As Integer? Implements ISyntaxKinds.AliasQualifiedName diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/AttributeGenerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/AttributeGenerator.cs index 5746ccb5dbe43..29460fa0a930b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/AttributeGenerator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/AttributeGenerator.cs @@ -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. -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; @@ -103,7 +101,7 @@ ExpressionSyntax GenerateAttributeSyntax(TypedConstant constant) { // In the case of a string constant with value "x", see if the originating syntax was a `nameof(x)` // expression and attempt to preserve that. - if (existingSyntax?.ArgumentList != null && constant.Value is string stringValue) + if (existingSyntax?.ArgumentList != null && constant.Kind is not TypedConstantKind.Array && constant.Value is string stringValue) { foreach (var existingArgument in existingSyntax.ArgumentList.Arguments) { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/CSharpCodeGenerationServiceFactory.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/CSharpCodeGenerationServiceFactory.cs index fca862869b8fd..cb23e9e7743d9 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/CSharpCodeGenerationServiceFactory.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/CSharpCodeGenerationServiceFactory.cs @@ -11,14 +11,10 @@ namespace Microsoft.CodeAnalysis.CSharp.CodeGeneration; [ExportLanguageServiceFactory(typeof(ICodeGenerationService), LanguageNames.CSharp), Shared] -internal partial class CSharpCodeGenerationServiceFactory : ILanguageServiceFactory +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class CSharpCodeGenerationServiceFactory() : ILanguageServiceFactory { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpCodeGenerationServiceFactory() - { - } - public ILanguageService CreateLanguageService(HostLanguageServices provider) => new CSharpCodeGenerationService(provider.LanguageServices); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/EnumMemberGenerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/EnumMemberGenerator.cs index 5abbf3f7fc960..26a248502e32c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/EnumMemberGenerator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/EnumMemberGenerator.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Shared.Utilities; namespace Microsoft.CodeAnalysis.CSharp.CodeGeneration; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/FieldGenerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/FieldGenerator.cs index 710d68afe5e25..6ce8a205e147e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/FieldGenerator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/FieldGenerator.cs @@ -8,7 +8,6 @@ using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/NamedTypeGenerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/NamedTypeGenerator.cs index 810a767498d1b..31c4d36df8885 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/NamedTypeGenerator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/NamedTypeGenerator.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.CodeGeneration; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/OperatorGenerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/OperatorGenerator.cs index cc7576eadbb94..3df3a22f146fb 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/OperatorGenerator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/OperatorGenerator.cs @@ -8,8 +8,8 @@ using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Shared.Collections; -using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.CSharp.CodeGeneration; @@ -48,8 +48,9 @@ internal static OperatorDeclarationSyntax GenerateOperatorDeclaration( var declaration = GenerateOperatorDeclarationWorker(method, destination, info, cancellationToken); declaration = UseExpressionBodyIfDesired(info, declaration, cancellationToken); - return AddAnnotationsTo(method, + declaration = AddAnnotationsTo(method, ConditionallyAddDocumentationCommentTo(declaration, method, info, cancellationToken)); + return declaration.WithAdditionalAnnotations(Formatter.Annotation); } private static OperatorDeclarationSyntax UseExpressionBodyIfDesired( diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/ParameterGenerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/ParameterGenerator.cs index fde1d2f232ee3..3b27bb15ad4e7 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/ParameterGenerator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/ParameterGenerator.cs @@ -6,7 +6,6 @@ using System.Collections.Immutable; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.CSharp.CodeGeneration; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/StatementGenerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/StatementGenerator.cs index 3e76d39f431b0..1063f9a47dc78 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/StatementGenerator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/StatementGenerator.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis.CodeGeneration; -using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; namespace Microsoft.CodeAnalysis.CSharp.CodeGeneration; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/BasePropertyDeclarationSyntaxExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/BasePropertyDeclarationSyntaxExtensions.cs index 57a0e41c0d322..975f0f05b15ad 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/BasePropertyDeclarationSyntaxExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/BasePropertyDeclarationSyntaxExtensions.cs @@ -48,17 +48,11 @@ public static SyntaxToken TryGetSemicolonToken(this BasePropertyDeclarationSynta /// Available if is or . /// [return: NotNullIfNotNull(nameof(node))] - public static BasePropertyDeclarationSyntax? TryWithExpressionBody(this BasePropertyDeclarationSyntax? node, ArrowExpressionClauseSyntax expressionBody) - { - if (node != null) + public static BasePropertyDeclarationSyntax? TryWithExpressionBody(this BasePropertyDeclarationSyntax? node, ArrowExpressionClauseSyntax? expressionBody) + => node switch { - switch (node.Kind()) - { - case SyntaxKind.PropertyDeclaration: return ((PropertyDeclarationSyntax)node).WithExpressionBody(expressionBody); - case SyntaxKind.IndexerDeclaration: return ((IndexerDeclarationSyntax)node).WithExpressionBody(expressionBody); - } - } - - return node; - } + PropertyDeclarationSyntax property => property.WithExpressionBody(expressionBody), + IndexerDeclarationSyntax indexer => indexer.WithExpressionBody(expressionBody), + _ => node, + }; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxTreeExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxTreeExtensions.cs index d7cd0a61f63cc..2858f4a16eeed 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxTreeExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxTreeExtensions.cs @@ -759,8 +759,8 @@ public static bool IsTypeContext( position, context: null, validModifiers: SyntaxKindSet.AllMemberModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, - canBePartial: false, + validTypeDeclarations: SyntaxKindSet.NonEnumTypeDeclarations, + canBePartial: true, cancellationToken: cancellationToken) || syntaxTree.IsLocalFunctionDeclarationContext(position, cancellationToken); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeParameterSymbolExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeParameterSymbolExtensions.cs index 70ae62d93d8bf..39dec2a10a67d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeParameterSymbolExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeParameterSymbolExtensions.cs @@ -7,6 +7,7 @@ using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.CSharp.Extensions; @@ -23,21 +24,19 @@ public static SyntaxList GenerateConstraint public static SyntaxList GenerateConstraintClauses( this IEnumerable typeParameters) { - var clauses = new List(); + using var _ = ArrayBuilder.GetInstance(out var clauses); foreach (var typeParameter in typeParameters) - { AddConstraintClauses(clauses, typeParameter); - } return [.. clauses]; } private static void AddConstraintClauses( - List clauses, + ArrayBuilder clauses, ITypeParameterSymbol typeParameter) { - var constraints = new List(); + using var _ = ArrayBuilder.GetInstance(out var constraints); if (typeParameter.HasReferenceTypeConstraint) { @@ -64,15 +63,11 @@ private static void AddConstraintClauses( foreach (var type in constraintTypes) { if (type.SpecialType != SpecialType.System_Object) - { constraints.Add(TypeConstraint(type.GenerateTypeSyntax())); - } } if (typeParameter.HasConstructorConstraint) - { constraints.Add(ConstructorConstraint()); - } if (typeParameter.AllowsRefLikeType) { @@ -81,9 +76,7 @@ private static void AddConstraintClauses( } if (constraints.Count == 0) - { return; - } clauses.Add(TypeParameterConstraintClause( typeParameter.Name.ToIdentifierName(), diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/InternalExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/InternalExtensions.cs index d08422ebc6976..8f7a5c42e8f7a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/InternalExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/InternalExtensions.cs @@ -2,11 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Shared.Extensions; -using System; using System.Threading; namespace Microsoft.CodeAnalysis.CSharp; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/NameSyntaxExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/NameSyntaxExtensions.cs index e6365dca83b7e..8499f073aa258 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/NameSyntaxExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/NameSyntaxExtensions.cs @@ -2,13 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Utilities; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Extensions; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/SyntaxTreeExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/SyntaxTreeExtensions.cs index a23cedffb461b..d9ba83277bf08 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/SyntaxTreeExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/SyntaxTreeExtensions.cs @@ -6,7 +6,6 @@ using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Extensions; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/TypeDeclarationSyntaxExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/TypeDeclarationSyntaxExtensions.cs index b15d8d2e2ff26..a182161fcd7c0 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/TypeDeclarationSyntaxExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/TypeDeclarationSyntaxExtensions.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; using System.Threading; using Microsoft.CodeAnalysis; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Formatting/CSharpSyntaxFormattingOptionsProviders.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Formatting/CSharpSyntaxFormattingOptionsProviders.cs index 48f26ccbd62e1..3745f82189a8d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Formatting/CSharpSyntaxFormattingOptionsProviders.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Formatting/CSharpSyntaxFormattingOptionsProviders.cs @@ -4,7 +4,6 @@ using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.CSharp.Formatting; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Indentation/CSharpIndentationService.Indenter.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Indentation/CSharpIndentationService.Indenter.cs index ee52e25add6e0..ebf447439ff9a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Indentation/CSharpIndentationService.Indenter.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Indentation/CSharpIndentationService.Indenter.cs @@ -2,15 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Immutable; -using System.Diagnostics; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Formatting.Rules; using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -220,8 +217,7 @@ private static IndentationResult GetIndentationBasedOnToken(Indenter indenter, S token.IsCloseBraceOfEmbeddedBlock()) { RoslynDebug.Assert( - token.Parent != null && - (token.Parent.Parent is StatementSyntax || token.Parent.Parent is ElseClauseSyntax)); + token.Parent?.Parent is StatementSyntax or ElseClauseSyntax); var embeddedStatementOwner = token.Parent.Parent; while (embeddedStatementOwner.IsEmbeddedStatement()) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Indentation/CSharpIndentationService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Indentation/CSharpIndentationService.cs index 266479d1d0ba5..2016adb504076 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Indentation/CSharpIndentationService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Indentation/CSharpIndentationService.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Collections.Immutable; using System.Composition; using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Extensions; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpAddImportsService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpAddImportsService.cs index 49f49d397cb4f..c2a88b278536c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpAddImportsService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpAddImportsService.cs @@ -12,11 +12,9 @@ using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.AddImport; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpCommandLineParserService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpCommandLineParserService.cs index d3ce253d31fc3..127b88668413f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpCommandLineParserService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpCommandLineParserService.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.Composition; using System.Diagnostics.CodeAnalysis; @@ -21,7 +19,7 @@ public CSharpCommandLineParserService() { } - public CommandLineArguments Parse(IEnumerable arguments, string baseDirectory, bool isInteractive, string sdkDirectory) + public CommandLineArguments Parse(IEnumerable arguments, string? baseDirectory, bool isInteractive, string? sdkDirectory) { #if SCRIPTING var parser = isInteractive ? CSharpCommandLineParser.Interactive : CSharpCommandLineParser.Default; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpGeneratedCodeRecognitionService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpGeneratedCodeRecognitionService.cs index 3cc83101ac218..87bdbcdb5876a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpGeneratedCodeRecognitionService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpGeneratedCodeRecognitionService.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.Composition; using Microsoft.CodeAnalysis.GeneratedCodeRecognition; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpHeaderFactsService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpHeaderFactsService.cs index 465b92b158ed3..e51ec21b5d970 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpHeaderFactsService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpHeaderFactsService.cs @@ -11,11 +11,6 @@ namespace Microsoft.CodeAnalysis.CSharp; [ExportLanguageService(typeof(IHeaderFactsService), LanguageNames.CSharp), Shared] -internal class CSharpHeaderFactsServices : CSharpHeaderFacts, IHeaderFactsService -{ - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpHeaderFactsServices() - { - } -} +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class CSharpHeaderFactsServices() : CSharpHeaderFacts, IHeaderFactsService; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpRemoveUnnecessaryImportsService.Rewriter.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpRemoveUnnecessaryImportsService.Rewriter.cs index 332951421c61a..c0c7c2a271e36 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpRemoveUnnecessaryImportsService.Rewriter.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpRemoveUnnecessaryImportsService.Rewriter.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Helpers.RemoveUnnecessaryImports; using Roslyn.Utilities; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpReplaceDiscardDeclarationsWithAssignmentsService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpReplaceDiscardDeclarationsWithAssignmentsService.cs index 5b4c5b3e3ebde..23c5da364f17c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpReplaceDiscardDeclarationsWithAssignmentsService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpReplaceDiscardDeclarationsWithAssignmentsService.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.Composition; using System.Diagnostics; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSemanticFactsService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSemanticFactsService.cs index 68f20fb393153..57dcf24f1f50e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSemanticFactsService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSemanticFactsService.cs @@ -2,9 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - -using System; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -13,7 +10,6 @@ using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.CSharp.Utilities; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSemanticFactsServiceFactory.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSemanticFactsServiceFactory.cs index bce2c53d42150..612553bc42e42 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSemanticFactsServiceFactory.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSemanticFactsServiceFactory.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.Composition; using Microsoft.CodeAnalysis.Host; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSymbolDeclarationService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSymbolDeclarationService.cs index be60e6d598219..6aba9ac7d279c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSymbolDeclarationService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSymbolDeclarationService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Immutable; using System.Composition; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSyntaxFactsServiceFactory.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSyntaxFactsServiceFactory.cs index d557682787412..3ef3d9fe56959 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSyntaxFactsServiceFactory.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSyntaxFactsServiceFactory.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.Composition; using Microsoft.CodeAnalysis.Host; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSyntaxGeneratorInternal.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSyntaxGeneratorInternal.cs index f937f38177b8a..8f67b9074a5e7 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSyntaxGeneratorInternal.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSyntaxGeneratorInternal.cs @@ -16,7 +16,6 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.CodeGeneration; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSyntaxKindsServiceFactory.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSyntaxKindsServiceFactory.cs index 71aa1577bef1f..1480f101ee7f4 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSyntaxKindsServiceFactory.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSyntaxKindsServiceFactory.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.Composition; using Microsoft.CodeAnalysis.Host; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpTypeInferenceService.TypeInferrer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpTypeInferenceService.TypeInferrer.cs index 8b9aeb302b308..da96d78dfa53a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpTypeInferenceService.TypeInferrer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpTypeInferenceService.TypeInferrer.cs @@ -4,7 +4,6 @@ #nullable disable -using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpTypeInferenceService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpTypeInferenceService.cs index 7d7990d485e2d..8be0838a107e4 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpTypeInferenceService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpTypeInferenceService.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.Composition; using System.Diagnostics.CodeAnalysis; using System.Threading; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/InitializeParameter/InitializeParameterHelpers.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/InitializeParameter/InitializeParameterHelpers.cs index dbd5e6e5b6286..1bce0204bd6f8 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/InitializeParameter/InitializeParameterHelpers.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/InitializeParameter/InitializeParameterHelpers.cs @@ -19,7 +19,6 @@ using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.InitializeParameter; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Simplification/CSharpSimplifierOptionsProviders.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Simplification/CSharpSimplifierOptionsProviders.cs index 5c91aa8381248..a00e05637574f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Simplification/CSharpSimplifierOptionsProviders.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Simplification/CSharpSimplifierOptionsProviders.cs @@ -4,7 +4,6 @@ using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.CSharp.Simplification; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Utilities/SyntaxKindSet.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Utilities/SyntaxKindSet.cs index 9559bfd70b617..0b1707d33682c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Utilities/SyntaxKindSet.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Utilities/SyntaxKindSet.cs @@ -85,6 +85,16 @@ internal class SyntaxKindSet SyntaxKind.RecordStructDeclaration, }; + public static readonly ISet NonEnumTypeDeclarations = new HashSet(SyntaxFacts.EqualityComparer) + { + SyntaxKind.ClassDeclaration, + SyntaxKind.ExtensionDeclaration, + SyntaxKind.InterfaceDeclaration, + SyntaxKind.RecordDeclaration, + SyntaxKind.RecordStructDeclaration, + SyntaxKind.StructDeclaration, + }; + public static readonly ISet ClassInterfaceRecordTypeDeclarations = new HashSet(SyntaxFacts.EqualityComparer) { SyntaxKind.InterfaceDeclaration, diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeFixes/ForkingSyntaxEditorBasedCodeFixProvider.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeFixes/ForkingSyntaxEditorBasedCodeFixProvider.cs index 90cae65a5d562..e8b6f1d6bbe88 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeFixes/ForkingSyntaxEditorBasedCodeFixProvider.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeFixes/ForkingSyntaxEditorBasedCodeFixProvider.cs @@ -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. -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeFixesAndRefactorings/FixAllHelper.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeFixesAndRefactorings/FixAllHelper.cs index b5f3c537124d9..882581b50d9b3 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeFixesAndRefactorings/FixAllHelper.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeFixesAndRefactorings/FixAllHelper.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 Roslyn.Utilities; using FixAllScope = Microsoft.CodeAnalysis.CodeFixes.FixAllScope; namespace Microsoft.CodeAnalysis.CodeFixesAndRefactorings; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/AbstractCodeGenerationService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/AbstractCodeGenerationService.cs index b45ba582898e3..10d45074d8c38 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/AbstractCodeGenerationService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/AbstractCodeGenerationService.cs @@ -6,7 +6,6 @@ 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; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/AbstractCodeGenerationService_FindDeclaration.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/AbstractCodeGenerationService_FindDeclaration.cs index c46c83718ab33..87fff6b2c2f82 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/AbstractCodeGenerationService_FindDeclaration.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/AbstractCodeGenerationService_FindDeclaration.cs @@ -7,7 +7,6 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CodeGenerationOptionsProviders.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CodeGenerationOptionsProviders.cs index 5adc859cea244..8b1953dddd7c1 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CodeGenerationOptionsProviders.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CodeGenerationOptionsProviders.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeGeneration; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CodeGenerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CodeGenerator.cs index 312998cb290d1..3325f4796a16e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CodeGenerator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CodeGenerator.cs @@ -6,7 +6,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeGeneration; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/ICodeGenerationService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/ICodeGenerationService.cs index 3595fd075bed2..7483075918a9a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/ICodeGenerationService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/ICodeGenerationService.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConstructorSymbol.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConstructorSymbol.cs index 4ba1d6ad75bed..3d4c238631dd2 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConstructorSymbol.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConstructorSymbol.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; #if CODE_STYLE @@ -15,7 +13,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration; internal sealed class CodeGenerationConstructorSymbol( - INamedTypeSymbol containingType, + INamedTypeSymbol? containingType, ImmutableArray attributes, Accessibility accessibility, DeclarationModifiers modifiers, diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConversionSymbol.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConversionSymbol.cs index 303ef6233fe75..f063c96b3f67a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConversionSymbol.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConversionSymbol.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; #if CODE_STYLE @@ -15,7 +13,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration; internal sealed class CodeGenerationConversionSymbol( - INamedTypeSymbol containingType, + INamedTypeSymbol? containingType, ImmutableArray attributes, Accessibility declaredAccessibility, DeclarationModifiers modifiers, @@ -23,7 +21,7 @@ internal sealed class CodeGenerationConversionSymbol( IParameterSymbol fromType, bool isImplicit, ImmutableArray toTypeAttributes, - string documentationCommentXml) : CodeGenerationMethodSymbol(containingType, + string? documentationCommentXml) : CodeGenerationMethodSymbol(containingType, attributes, declaredAccessibility, modifiers, diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationDestructorSymbol.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationDestructorSymbol.cs index bff02db796c93..e24f5b82e6c68 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationDestructorSymbol.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationDestructorSymbol.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. -#nullable disable - using System.Collections.Immutable; namespace Microsoft.CodeAnalysis.CodeGeneration; internal sealed class CodeGenerationDestructorSymbol( - INamedTypeSymbol containingType, + INamedTypeSymbol? containingType, ImmutableArray attributes) : CodeGenerationMethodSymbol(containingType, attributes, Accessibility.NotApplicable, diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationEventSymbol.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationEventSymbol.cs index bc60a6bfd6e10..2c05b57bbc671 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationEventSymbol.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationEventSymbol.cs @@ -59,5 +59,11 @@ public override TResult Accept(SymbolVisitor null; + public IEventSymbol? PartialImplementationPart => null; + + public IEventSymbol? PartialDefinitionPart => null; + + public bool IsPartialDefinition => false; + public static ImmutableArray TypeCustomModifiers => []; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationNamespaceOrTypeSymbol.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationNamespaceOrTypeSymbol.cs index 39f916d228630..0330b8cba065d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationNamespaceOrTypeSymbol.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationNamespaceOrTypeSymbol.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; #if CODE_STYLE diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationOperatorSymbol.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationOperatorSymbol.cs index 0a7ac510f3da9..ada9dde7c160a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationOperatorSymbol.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationOperatorSymbol.cs @@ -2,10 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; -using Roslyn.Utilities; #if CODE_STYLE using Microsoft.CodeAnalysis.Internal.Editing; @@ -16,7 +13,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration; internal sealed class CodeGenerationOperatorSymbol( - INamedTypeSymbol containingType, + INamedTypeSymbol? containingType, ImmutableArray attributes, Accessibility accessibility, DeclarationModifiers modifiers, @@ -24,7 +21,7 @@ internal sealed class CodeGenerationOperatorSymbol( CodeGenerationOperatorKind operatorKind, ImmutableArray parameters, ImmutableArray returnTypeAttributes, - string documentationCommentXml) : CodeGenerationMethodSymbol(containingType, + string? documentationCommentXml) : CodeGenerationMethodSymbol(containingType, attributes, accessibility, modifiers, diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationTypeSymbol.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationTypeSymbol.cs index 610fafd8b76b1..281eb98632cdb 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationTypeSymbol.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationTypeSymbol.cs @@ -47,6 +47,10 @@ public ImmutableArray AllInterfaces public bool IsNativeIntegerType => false; + public bool IsExtension => false; + + public IParameterSymbol ExtensionParameter => null; + public static ImmutableArray TupleElementTypes => default; public static ImmutableArray TupleElementNames => default; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/SyntaxAnnotationExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/SyntaxAnnotationExtensions.cs index 75acc5f00a712..c291d3901e3da 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/SyntaxAnnotationExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/SyntaxAnnotationExtensions.cs @@ -4,7 +4,6 @@ using System; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeGeneration; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeRefactorings/CodeRefactoringHelpers.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeRefactorings/CodeRefactoringHelpers.cs index e9e59ea0e3b6e..54a227a9b3410 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeRefactorings/CodeRefactoringHelpers.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeRefactorings/CodeRefactoringHelpers.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Threading; -using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeRefactorings/IRefactoringHelpersService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeRefactorings/IRefactoringHelpersService.cs index 6f25b6784edab..abdf86630343b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeRefactorings/IRefactoringHelpersService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeRefactorings/IRefactoringHelpersService.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.Immutable; using System.Diagnostics.CodeAnalysis; using System.Threading; using Microsoft.CodeAnalysis.Host; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Editing/ImportAdderService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Editing/ImportAdderService.cs index b836a2d0d8f01..91ee326561e99 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Editing/ImportAdderService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Editing/ImportAdderService.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.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.AddImport; -using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.PooledObjects; @@ -38,7 +36,6 @@ public async Task AddImportsAsync( { var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var addImportsService = document.GetRequiredLanguageService(); - var codeGenerator = document.GetRequiredLanguageService(); var generator = document.GetRequiredLanguageService(); // Create a simple interval tree for simplification spans. @@ -53,13 +50,20 @@ public async Task AddImportsAsync( // // We'll dive under the parent because it overlaps with the span. But we only want to include (and dive // into) B and C not A and D. - var nodes = root.DescendantNodesAndSelf(OverlapsWithSpan).Where(OverlapsWithSpan); - if (strategy == Strategy.AddImportsFromSymbolAnnotations) - return await AddImportDirectivesFromSymbolAnnotationsAsync(document, nodes, addImportsService, generator, options, cancellationToken).ConfigureAwait(false); + { + var nodes = root.DescendantNodesAndSelf(n => OverlapsWithSpan(n) && n.ContainsAnnotations).Where(OverlapsWithSpan); + var annotatedNodes = nodes.Where(x => x.HasAnnotations(SymbolAnnotation.Kind)); + + return await AddImportDirectivesFromSymbolAnnotationsAsync(document, annotatedNodes, addImportsService, generator, options, cancellationToken).ConfigureAwait(false); + } if (strategy == Strategy.AddImportsFromSyntaxes) + { + var nodes = root.DescendantNodesAndSelf(OverlapsWithSpan).Where(OverlapsWithSpan); + return await AddImportDirectivesFromSyntaxesAsync(document, nodes, addImportsService, generator, options, cancellationToken).ConfigureAwait(false); + } throw ExceptionUtilities.UnexpectedValue(strategy); @@ -165,7 +169,7 @@ private async Task AddImportDirectivesFromSyntaxesAsync( private async Task AddImportDirectivesFromSymbolAnnotationsAsync( Document document, - IEnumerable syntaxNodes, + IEnumerable annotatedNodes, IAddImportsService addImportsService, SyntaxGenerator generator, AddImportPlacementOptions options, @@ -182,7 +186,6 @@ private async Task AddImportDirectivesFromSymbolAnnotationsAsync( #endif SyntaxNode? first = null, last = null; - var annotatedNodes = syntaxNodes.Where(x => x.HasAnnotations(SymbolAnnotation.Kind)); foreach (var annotatedNode in annotatedNodes) { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/ContextQuery/ISyntaxContextService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/ContextQuery/ISyntaxContextService.cs index 05ca8e515ee58..a1352745bcf34 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/ContextQuery/ISyntaxContextService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/ContextQuery/ISyntaxContextService.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Threading; -using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/DocumentExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/DocumentExtensions.cs index 0fc7f4c3b746a..555379d592453 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/DocumentExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/DocumentExtensions.cs @@ -4,20 +4,15 @@ using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.GeneratedCodeRecognition; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.SemanticModelReuse; 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; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/IMethodSymbolExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/IMethodSymbolExtensions.cs index 6e27c285e13e3..958462ac47447 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/IMethodSymbolExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/IMethodSymbolExtensions.cs @@ -5,8 +5,6 @@ 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; @@ -163,13 +161,13 @@ public static IMethodSymbol RemoveInaccessibleAttributesAndAttributesOfTypes( method, containingType: method.ContainingType, explicitInterfaceImplementations: method.ExplicitInterfaceImplementations, - attributes: method.GetAttributes().WhereAsArray(static (a, arg) => !shouldRemoveAttribute(a, arg), arg), + attributes: method.GetAttributes().WhereAsArray(static (a, arg) => !shouldRemoveAttribute(a, arg), arg: arg), parameters: method.Parameters.SelectAsArray(static (p, arg) => CodeGenerationSymbolFactory.CreateParameterSymbol( - p.GetAttributes().WhereAsArray(static (a, arg) => !shouldRemoveAttribute(a, arg), arg), + p.GetAttributes().WhereAsArray(static (a, arg) => !shouldRemoveAttribute(a, arg), 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)); + returnTypeAttributes: method.GetReturnTypeAttributes().WhereAsArray(static (a, arg) => !shouldRemoveAttribute(a, arg), arg: arg)); static bool shouldRemoveAttribute(AttributeData a, (INamedTypeSymbol[] removeAttributeTypes, ISymbol accessibleWithin) arg) => arg.removeAttributeTypes.Any(attr => attr.Equals(a.AttributeClass)) || diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/IPropertySymbolExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/IPropertySymbolExtensions.cs index 2b2a1a8d5c1f3..bdec134f9580a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/IPropertySymbolExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/IPropertySymbolExtensions.cs @@ -59,7 +59,7 @@ public static IPropertySymbol RemoveInaccessibleAttributesAndAttributesOfTypes( property.Name, property.Parameters.SelectAsArray(static (p, arg) => CodeGenerationSymbolFactory.CreateParameterSymbol( - p.GetAttributes().WhereAsArray(static (a, arg) => !ShouldRemoveAttribute(a, arg), arg), + p.GetAttributes().WhereAsArray(static (a, arg) => !ShouldRemoveAttribute(a, arg), arg: arg), p.RefKind, p.IsParams, p.Type, p.Name, p.IsOptional, p.HasExplicitDefaultValue, p.HasExplicitDefaultValue ? p.ExplicitDefaultValue : null), arg), property.GetMethod, diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/ProjectExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/ProjectExtensions.cs index 13a9669003389..cc5b2d7b12c6d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/ProjectExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/ProjectExtensions.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Immutable; using System.Diagnostics; using System.Linq; using System.Threading; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/StringBuilderExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/StringBuilderExtensions.cs index e9113e2ba7338..05735ef7839b7 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/StringBuilderExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/StringBuilderExtensions.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Text; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/SyntaxGeneratorExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/SyntaxGeneratorExtensions.cs index 2f943663ea358..605627f735c8c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/SyntaxGeneratorExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/SyntaxGeneratorExtensions.cs @@ -10,7 +10,6 @@ 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; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/SyntaxGeneratorExtensions_Negate.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/SyntaxGeneratorExtensions_Negate.cs index 3e342e41ce85f..0b41c1f9c88f0 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/SyntaxGeneratorExtensions_Negate.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/SyntaxGeneratorExtensions_Negate.cs @@ -5,13 +5,11 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics; using System.Threading; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Simplification; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/FindSymbols/LinkedFileReferenceLocationEqualityComparer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/FindSymbols/LinkedFileReferenceLocationEqualityComparer.cs index 2c6eb0fa0b091..551d15bca06ca 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/FindSymbols/LinkedFileReferenceLocationEqualityComparer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/FindSymbols/LinkedFileReferenceLocationEqualityComparer.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Threading; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.FindSymbols; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Indentation/AbstractIndentationService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Indentation/AbstractIndentationService.cs index e89266c0d77c2..6d83b3ceff91d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Indentation/AbstractIndentationService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Indentation/AbstractIndentationService.cs @@ -2,13 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Generic; using System.Collections.Immutable; using System.Threading; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Formatting.Rules; -using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Indentation; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Indentation/IIndentationService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Indentation/IIndentationService.cs index 5643ec0963334..78d3ffaa51dbb 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Indentation/IIndentationService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Indentation/IIndentationService.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Indentation; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/AddImports/AbstractAddImportsService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/AddImports/AbstractAddImportsService.cs index 655d0553ebb12..933c093a5c265 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/AddImports/AbstractAddImportsService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/AddImports/AbstractAddImportsService.cs @@ -8,7 +8,6 @@ using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/AddImports/IAddImportsService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/AddImports/IAddImportsService.cs index 628274b8720bc..32e04f1b2d79a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/AddImports/IAddImportsService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/AddImports/IAddImportsService.cs @@ -3,17 +3,10 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Runtime.Serialization; using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeCleanup; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.AddImport; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/CommandLine/ICommandLineParserService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/CommandLine/ICommandLineParserService.cs index 1146d0ec6db11..662e93d076f50 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/CommandLine/ICommandLineParserService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/CommandLine/ICommandLineParserService.cs @@ -2,13 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Generic; namespace Microsoft.CodeAnalysis.Host; internal interface ICommandLineParserService : ILanguageService { - CommandLineArguments Parse(IEnumerable arguments, string baseDirectory, bool isInteractive, string sdkDirectory); + CommandLineArguments Parse(IEnumerable arguments, string? baseDirectory, bool isInteractive, string? sdkDirectory); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/GeneratedCodeRecognition/AbstractGeneratedCodeRecognitionService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/GeneratedCodeRecognition/AbstractGeneratedCodeRecognitionService.cs index efc0f1e2c912d..ba5e45e4b2486 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/GeneratedCodeRecognition/AbstractGeneratedCodeRecognitionService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/GeneratedCodeRecognition/AbstractGeneratedCodeRecognitionService.cs @@ -8,7 +8,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.GeneratedCodeRecognition; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/GeneratedCodeRecognition/IGeneratedCodeRecognitionService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/GeneratedCodeRecognition/IGeneratedCodeRecognitionService.cs index ede540ccc1ecb..05f5c1c44aba1 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/GeneratedCodeRecognition/IGeneratedCodeRecognitionService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/GeneratedCodeRecognition/IGeneratedCodeRecognitionService.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; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/MoveDeclarationNearReference/IMoveDeclarationNearReferenceService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/MoveDeclarationNearReference/IMoveDeclarationNearReferenceService.cs index c872efc5ce4ab..c065d0d30c728 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/MoveDeclarationNearReference/IMoveDeclarationNearReferenceService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/MoveDeclarationNearReference/IMoveDeclarationNearReferenceService.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; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/RemoveUnnecessaryImports/AbstractRemoveUnnecessaryImportsService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/RemoveUnnecessaryImports/AbstractRemoveUnnecessaryImportsService.cs index be6a0da6fe3b4..eaa1a47979f85 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/RemoveUnnecessaryImports/AbstractRemoveUnnecessaryImportsService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/RemoveUnnecessaryImports/AbstractRemoveUnnecessaryImportsService.cs @@ -4,11 +4,8 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/ReplaceDiscardDeclarationsWithAssignments/IReplaceDiscardDeclarationsWithAssignmentsService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/ReplaceDiscardDeclarationsWithAssignments/IReplaceDiscardDeclarationsWithAssignmentsService.cs index 9fb096ff9995e..260b9956e815d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/ReplaceDiscardDeclarationsWithAssignments/IReplaceDiscardDeclarationsWithAssignmentsService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/ReplaceDiscardDeclarationsWithAssignments/IReplaceDiscardDeclarationsWithAssignmentsService.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; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/SemanticsFactsService/AbstractSemanticFactsService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/SemanticsFactsService/AbstractSemanticFactsService.cs index c3682a87189e6..4274201c8822f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/SemanticsFactsService/AbstractSemanticFactsService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/SemanticsFactsService/AbstractSemanticFactsService.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -257,6 +258,9 @@ public string GenerateNameForExpression(SemanticModel semanticModel, SyntaxNode public IPreprocessingSymbol GetPreprocessingSymbol(SemanticModel semanticModel, SyntaxNode node) => SemanticFacts.GetPreprocessingSymbol(semanticModel, node); + public bool TryGetPrimaryConstructor(INamedTypeSymbol typeSymbol, [NotNullWhen(true)] out IMethodSymbol primaryConstructor) + => SemanticFacts.TryGetPrimaryConstructor(typeSymbol, out primaryConstructor); + #if !CODE_STYLE public Task GetInterceptorSymbolAsync(Document document, int position, CancellationToken cancellationToken) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/SyntaxFactsService/ISyntaxFactsService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/SyntaxFactsService/ISyntaxFactsService.cs index 129fb1bf548d3..bba14b60f1fd4 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/SyntaxFactsService/ISyntaxFactsService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/SyntaxFactsService/ISyntaxFactsService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/SyntaxGeneratorInternalExtensions/SyntaxGeneratorInternal.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/SyntaxGeneratorInternalExtensions/SyntaxGeneratorInternal.cs index 271db0c4aaf77..01f6344bf9fe6 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/SyntaxGeneratorInternalExtensions/SyntaxGeneratorInternal.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/SyntaxGeneratorInternalExtensions/SyntaxGeneratorInternal.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.LanguageService; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/TypeInferenceService/AbstractTypeInferenceService.AbstractTypeInferrer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/TypeInferenceService/AbstractTypeInferenceService.AbstractTypeInferrer.cs index 8880a61959ed0..69caff6ac6b41 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/TypeInferenceService/AbstractTypeInferenceService.AbstractTypeInferrer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/TypeInferenceService/AbstractTypeInferenceService.AbstractTypeInferrer.cs @@ -2,14 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageService.TypeInferenceService; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/TypeInferenceService/AbstractTypeInferenceService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/TypeInferenceService/AbstractTypeInferenceService.cs index fd197962297c5..613b33ec07caa 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/TypeInferenceService/AbstractTypeInferenceService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/TypeInferenceService/AbstractTypeInferenceService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Linq; using System.Threading; @@ -15,7 +13,7 @@ internal abstract partial class AbstractTypeInferenceService : ITypeInferenceSer protected abstract AbstractTypeInferrer CreateTypeInferrer(SemanticModel semanticModel, CancellationToken cancellationToken); private static ImmutableArray InferTypeBasedOnNameIfEmpty( - SemanticModel semanticModel, ImmutableArray result, string nameOpt) + SemanticModel semanticModel, ImmutableArray result, string? nameOpt) { if (result.IsEmpty && nameOpt != null) { @@ -26,7 +24,7 @@ private static ImmutableArray InferTypeBasedOnNameIfEmpty( } private static ImmutableArray InferTypeBasedOnNameIfEmpty( - SemanticModel semanticModel, ImmutableArray result, string nameOpt) + SemanticModel semanticModel, ImmutableArray result, string? nameOpt) { if (result.IsEmpty && nameOpt != null) { @@ -80,7 +78,7 @@ private static bool Matches(string name, string prefix) public ImmutableArray InferTypes( SemanticModel semanticModel, int position, - string nameOpt, CancellationToken cancellationToken) + string? nameOpt, CancellationToken cancellationToken) { var result = CreateTypeInferrer(semanticModel, cancellationToken) .InferTypes(position) @@ -92,7 +90,7 @@ public ImmutableArray InferTypes( public ImmutableArray InferTypes( SemanticModel semanticModel, SyntaxNode expression, - string nameOpt, CancellationToken cancellationToken) + string? nameOpt, CancellationToken cancellationToken) { var result = CreateTypeInferrer(semanticModel, cancellationToken) .InferTypes(expression) @@ -104,7 +102,7 @@ public ImmutableArray InferTypes( public ImmutableArray GetTypeInferenceInfo( SemanticModel semanticModel, int position, - string nameOpt, CancellationToken cancellationToken) + string? nameOpt, CancellationToken cancellationToken) { var result = CreateTypeInferrer(semanticModel, cancellationToken).InferTypes(position); return InferTypeBasedOnNameIfEmpty(semanticModel, result, nameOpt); @@ -112,7 +110,7 @@ public ImmutableArray GetTypeInferenceInfo( public ImmutableArray GetTypeInferenceInfo( SemanticModel semanticModel, SyntaxNode expression, - string nameOpt, CancellationToken cancellationToken) + string? nameOpt, CancellationToken cancellationToken) { var result = CreateTypeInferrer(semanticModel, cancellationToken).InferTypes(expression); return InferTypeBasedOnNameIfEmpty(semanticModel, result, nameOpt); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/TypeInferenceService/ITypeInferenceService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/TypeInferenceService/ITypeInferenceService.cs index b3eda1cefe41f..4fd105c2c36f1 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/TypeInferenceService/ITypeInferenceService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/TypeInferenceService/ITypeInferenceService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Threading; using Microsoft.CodeAnalysis.Host; @@ -26,11 +24,11 @@ namespace Microsoft.CodeAnalysis.LanguageService; /// internal interface ITypeInferenceService : ILanguageService { - ImmutableArray InferTypes(SemanticModel semanticModel, SyntaxNode expression, string nameOpt, CancellationToken cancellationToken); - ImmutableArray InferTypes(SemanticModel semanticModel, int position, string nameOpt, CancellationToken cancellationToken); + ImmutableArray InferTypes(SemanticModel semanticModel, SyntaxNode expression, string? nameOpt, CancellationToken cancellationToken); + ImmutableArray InferTypes(SemanticModel semanticModel, int position, string? nameOpt, CancellationToken cancellationToken); - ImmutableArray GetTypeInferenceInfo(SemanticModel semanticModel, int position, string nameOpt, CancellationToken cancellationToken); - ImmutableArray GetTypeInferenceInfo(SemanticModel semanticModel, SyntaxNode expression, string nameOpt, CancellationToken cancellationToken); + ImmutableArray GetTypeInferenceInfo(SemanticModel semanticModel, int position, string? nameOpt, CancellationToken cancellationToken); + ImmutableArray GetTypeInferenceInfo(SemanticModel semanticModel, SyntaxNode expression, string? nameOpt, CancellationToken cancellationToken); } internal readonly record struct TypeInferenceInfo(ITypeSymbol InferredType, bool IsParams) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Progress/CodeAnalysisProgressExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Progress/CodeAnalysisProgressExtensions.cs index aa8d667c69311..c375e84c4bc74 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Progress/CodeAnalysisProgressExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Progress/CodeAnalysisProgressExtensions.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using Microsoft.CodeAnalysis.Shared.Utilities; namespace Microsoft.CodeAnalysis; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameActionAnnotation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameActionAnnotation.cs index 470faf912bc49..3a1cf60e23f3a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameActionAnnotation.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameActionAnnotation.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Rename.ConflictEngine; @@ -16,8 +14,8 @@ namespace Microsoft.CodeAnalysis.Rename.ConflictEngine; internal sealed class RenameActionAnnotation( TextSpan originalSpan, bool isRenameLocation, - string prefix, - string suffix, + string? prefix, + string? suffix, bool isOriginalTextLocation, RenameDeclarationLocationReference[] renameDeclarationLocations, bool isNamespaceDeclarationReference, @@ -44,13 +42,13 @@ internal sealed class RenameActionAnnotation( /// When replacing the annotated token this string will be prepended to the token's value. This is used when renaming compiler /// generated fields and methods backing properties (e.g. "get_X" or "_X" for property "X"). /// - public readonly string Prefix = prefix; + public readonly string? Prefix = prefix; /// /// When replacing the annotated token this string will be appended to the token's value. This is used when renaming compiler /// generated types whose names are derived from user given names (e.g. "XEventHandler" for event "X"). /// - public readonly string Suffix = suffix; + public readonly string? Suffix = suffix; /// /// A single dimensional array of annotations to verify after rename. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameAnnotation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameAnnotation.cs index 4a0f346335e0a..48047015ce8d9 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameAnnotation.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameAnnotation.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.Rename.ConflictEngine; internal class RenameAnnotation diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameInvalidIdentifierAnnotation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameInvalidIdentifierAnnotation.cs index fd4aa97c58179..af5c8811f38df 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameInvalidIdentifierAnnotation.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameInvalidIdentifierAnnotation.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.Rename.ConflictEngine; internal sealed class RenameInvalidIdentifierAnnotation : RenameAnnotation diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/AbstractReducer.IExpressionRewriter.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/AbstractReducer.IExpressionRewriter.cs index 061738fe22064..c19046e1a453e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/AbstractReducer.IExpressionRewriter.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/AbstractReducer.IExpressionRewriter.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Threading; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/AbstractReducer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/AbstractReducer.cs index 6cab3564d4759..c32ba6f97368b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/AbstractReducer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/AbstractReducer.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.Simplification; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/AbstractSimplificationService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/AbstractSimplificationService.cs index abc030986c383..cf1f0e196799b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/AbstractSimplificationService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/AbstractSimplificationService.cs @@ -196,7 +196,7 @@ async ValueTask ReduceOneNodeOrTokenAsync( cancellationToken.ThrowIfCancellationRequested(); using var rewriter = reducer.GetOrCreateRewriter(); - rewriter.Initialize(document.Project.ParseOptions, options, cancellationToken); + rewriter.Initialize(document.Project.ParseOptions!, options, cancellationToken); do { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/SimplificationHelpers.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/SimplificationHelpers.cs index c9bde8bce7b1c..fe4d9aa307878 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/SimplificationHelpers.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/SimplificationHelpers.cs @@ -4,7 +4,6 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; -using System.Linq.Expressions; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Utilities/ParsedDocument.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Utilities/ParsedDocument.cs index abd63a0705eb1..4706251f3c9eb 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Utilities/ParsedDocument.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Utilities/ParsedDocument.cs @@ -2,16 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; -using System.Reflection.Metadata; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/ILanguageMetadata.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/ILanguageMetadata.cs index a457a27adbf0e..b17df7eb6a8a3 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/ILanguageMetadata.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/ILanguageMetadata.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.Host.Mef; /// diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/ILanguagesMetadata.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/ILanguagesMetadata.cs index a0ab7c8d479f6..00debe8a7803b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/ILanguagesMetadata.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/ILanguagesMetadata.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; namespace Microsoft.CodeAnalysis.Host.Mef; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/IMefHostExportProvider.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/IMefHostExportProvider.cs index f327d6b68d4cb..a65b49295d2a0 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/IMefHostExportProvider.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/IMefHostExportProvider.cs @@ -2,11 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; -using System.Linq; namespace Microsoft.CodeAnalysis.Host.Mef; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/MefConstruction.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/MefConstruction.cs index d5d26a219928a..9a32aaa6c1a8b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/MefConstruction.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/MefConstruction.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.Host.Mef; internal static class MefConstruction diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceServices/SemanticModelReuse/SemanticModelReuseWorkspaceServiceFactory.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceServices/SemanticModelReuse/SemanticModelReuseWorkspaceServiceFactory.cs index 562598812ed69..aa3dbc8befe1c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceServices/SemanticModelReuse/SemanticModelReuseWorkspaceServiceFactory.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceServices/SemanticModelReuse/SemanticModelReuseWorkspaceServiceFactory.cs @@ -4,7 +4,6 @@ using System; using System.Composition; -using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/VisualBasicCodeGenerationHelpers.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/VisualBasicCodeGenerationHelpers.vb index a3ea2c7f99650..59dde2a5298ae 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/VisualBasicCodeGenerationHelpers.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/VisualBasicCodeGenerationHelpers.vb @@ -196,7 +196,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration ''' Note: the returned syntax node might be modified, which means its parent information might be missing. ''' Public Function GetReuseableSyntaxNodeForSymbol(Of T As SyntaxNode)(symbol As ISymbol, options As CodeGenerationContextInfo) As T - ThrowIfNull(symbol) + Contract.ThrowIfNull(symbol) If options.Context.ReuseSyntax AndAlso symbol.DeclaringSyntaxReferences.Length = 1 Then Dim reusableNode = symbol.DeclaringSyntaxReferences(0).GetSyntax() diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicHeaderFactsService.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicHeaderFactsService.vb index 0ebc3730ce03d..dc22c820aa3be 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicHeaderFactsService.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicHeaderFactsService.vb @@ -8,7 +8,7 @@ Imports Microsoft.CodeAnalysis.LanguageService Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService - Friend Class VisualBasicHeaderFactsService + Friend NotInheritable Class VisualBasicHeaderFactsService Inherits VisualBasicHeaderFacts Implements IHeaderFactsService diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb b/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb index a51af9b5cd3bf..c0aa21a33191b 100644 --- a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb +++ b/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb @@ -2368,8 +2368,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Return VisualBasicAccessibilityFacts.GetModifierTokens(declaration) End Function - Public Overrides Function WithModifiers(declaration As SyntaxNode, modifiers As DeclarationModifiers) As SyntaxNode - Return Isolate(declaration, Function(d) Me.WithModifiersInternal(d, modifiers)) + Friend Overrides Function WithModifiers(Of TSyntaxNode As SyntaxNode)(declaration As TSyntaxNode, modifiers As DeclarationModifiers) As TSyntaxNode + Return DirectCast(Isolate(declaration, Function(d) Me.WithModifiersInternal(d, modifiers)), TSyntaxNode) End Function Private Function WithModifiersInternal(declaration As SyntaxNode, modifiers As DeclarationModifiers) As SyntaxNode